4. Loops & Conditions (if/else)


In-Page Navigation

This tutorial requires PyScratch version 2.1.0 or above.

I assume you already know the basics of loops and conditions (if/else).

Demo 1: Fade out effect when the enemy is clicked

We want the enemy to shrink and fade out when it is clicked before it reappears somewhere else.

This is what you would do in in Scratch:

Scratch

scratch-blocks

In PyScratch, it would be similar:

enemy.py
@enemy.when_this_sprite_clicked()
def clicked():
    """
    change the enemy location with a fade out effect
    """
    # make the enemy smaller and paler 
    for i in range(10): # this is a repeat loop (10 repeats)
        yield 0.05 # wait for 0.05 second
        enemy.set_transparency(1-i/10) # make the enemy paler each step. if you find this confusing, do print(1-i/10) 
        enemy.scale_by(0.9) # make the enemy 10% smaller each step

    # change the location of the enemy
    enemy.x = pysc.random_number(0, game.screen_width)
    enemy.y = pysc.random_number(0, game.screen_height)

    # put the size and transparency back to normal
    enemy.set_transparency(1)
    enemy.set_scale(1)
Explanation for the features used
  • for i in range(10): a repeat loop of 10 times
  • yield 0.05: wait for 0.05 second
  • enemy.scale_by(0.9):
    • change the size to be 90% of the current size.
    • very similar to “change scale by -10”
  • enemy.set_transparency(1-i/10):
    • the ghost effect, with 0 being completely transparent, 1 be completely opaque.
    • i increases by 1 in each iteration, so to transparency would decrease like this:
      • 1-0/10 = 1
      • 1-1/10 = 0.9
      • 1-2/10 = 0.8
      • 1-9/10 = 0.1

When directly translated back to Scratch, this would be similar to:

Scratch

scratch-blocks

The main differences are as follow:

  • The ghost effect of 0 in Scratch is the transparency of 1.0 in PyScratch
  • There is no “change ghost effect by” in PyScratch
  • In Scratch, (0,0) is the centre of the screen but in PyScratch it is the top-left corner
The game would look like this

Wait (yield) in the Loop

It is essential to wait (yield) in the loop!

Python will put everything aside to run the loop as quickly as possible, unless you ask it to wait. Without waiting, a repeat loop (for loop) for 1000 times will be finished almost instantly and a forever loop (while True) without waiting will get the program stucked forever.

In this library, we use yield as the wait block in Scratch. For example, yield 0.5 means wait for 0.5 second.

Demo 2: Enemy Movement using a Forever Loop

We want the enemy to move to the centre of the window but avoid the mouse when it’s close..

enemy.py
@enemy.when_game_start()
def movement():
    """
    the movement of the enemy
    """
    speed = 5
    centre = (game.screen_width/2, game.screen_height/2)

    while True:
        # wait for one frame 
        yield 1/60 # or 1/game.framerate

        # get the enemy's distance to the cursor location
        mouse_x, mouse_y = pysc.get_mouse_pos()
        distance_to_mouse = enemy.distance_to((mouse_x, mouse_y))

        # enemy avoids the mouse when it is close to the mouse
        if distance_to_mouse < 200: 
            enemy.point_towards_mouse()
            enemy.direction += 180
            enemy.move_indir(speed)
        
        # otherwise, go to the centre of the screen 
        else:
            enemy.point_towards(centre)
            enemy.move_indir(speed)
Explanation for the features used
  • pysc.get_mouse_pos(): returns the mouse coordinate
  • enemy.distance_to((mouse_x, mouse_y))
    • get the distance between the enemy and the coordinate (mouse_x, mouse_y)
  • enemy.point_towards_mouse(): rotate the enemy towards the mouse
  • enemy.point_towards(centre)
    • this is evaluated to enemy.point_towards((game.screen_width/2, game.screen_height/2))
    • rotate the enemy towards the centre of the window
  • enemy.direction += 180: rotate the enemy 180 degrees
  • enemy.move_indir(5): move the enemy 5 pixels in the direction of the sprite

The Hexagon Slot in the If-Statement

In Scratch, the if-block would have a hexagon slot that only takes in the hexagon blocks.

TODO TODO TODO TODO

These hexagon blocks are always some sorts of a condition, that can only be one of the two states: True or False. In Python, this is known as a boolean variable.

The if keyword in Python always expect a boolean variable to follow, just like that the if-block on Scratch expects a hexagon block.

Example

These four if-statements below are all valid and almost equivalent.

mouse_x, mouse_y = pysc.get_mouse_pos()
distance_to_mouse = enemy.distance_to((mouse_x, mouse_y))
is_close_to_mouse = distance_to_mouse < 200

# all these four ways are valid and almost equivalent
if is_close_to_mouse:
    pass
if distance_to_mouse < 200: 
    pass
if enemy.distance_to((mouse_x, mouse_y)) < 200: 
    pass
if enemy.distance_to(pysc.get_mouse_pos()) < 200: 
    pass

It’s Now Your Turn!

Task 1: Experiment with yield

  • Try removing the yield line in the first demo event (in the for loop)
  • Try removing the yield line in the second demo event (in the while loop) - Expect the program to freeze!
  • Try putting a longer or shorter wait time in the demo events

Task 2: Add a new sprite, named “friend”

  • Use an image of a fish for this sprite.

Remember to import the new sprite to main.py!

Task 3: Add the movement of the friend fish

  • The friend fish should have the same movement logic as the enemy:
    • It moves to the centre of the screen.
    • It avoids the cursor when it is getting close.
  • You may copy the relevant event from the example and make appropriate changes to make it work for the friend fish.

Task 4: The friend fish disappears and reappears somewhere random when it is near the centre of the window

  • Do not use is_touching. This will come in day 2.
  • When the distance of the friend fish to the centre is smaller than a certain threshold, change its location randomly.
  • You can create a new when_game_start event with a forever loop to check this condition.
The game might look like this

You might want to create the fade out effect for the friend fish as well.

Tips

  • If you find it hard, think about how you would do it if it is on Scratch.
  • Remember to wait (yield) in the loop!
  • Remember to save the files before you run.

Next Step


This site uses Just the Docs, a documentation theme for Jekyll.