7. More advanced games

These games demonstrate some essential building blocks you will need to make more advanced games of your own.

7.1. Lists

We introduced lists in Program 2.12. In this game, we create an empty list [] and use a loop to fill it with alien Actors.

We again use loops to draw all the aliens and move all the aliens in the list. When the mouse is clicked we add a new alien to the list.

Program 7.1 Lists are useful in games!
 1from rlzero import *
 2
 3WIDTH = 500
 4HEIGHT = 500
 5
 6aliens = []
 7for i in range(0,10):
 8    aliens.append(Sprite('alien.png', (i*30, i*30)))
 9
10def draw():
11    for alien in aliens:
12        alien.draw()
13
14def update():
15    for alien in aliens:
16        alien.x += 2
17        if alien.x > WIDTH:
18            alien.x = 0
19
20def on_mouse_pressed(pos, button):
21    aliens.append(Sprite('alien.png', pos))
22
23run()

Advanced

Go back to a previous game (e.g. Program 5.1) and add a list of bullets that move up the screen. When the player presses the spacebar to shoot, add a new bullet to the list.

7.2. Timed callbacks

So far we have been using certain functions as callbacks: update(), draw() etc. These are called automatically for us by RLZero every frame. However, you can also create your own callbacks, and ask RLZero to call them back for you at a certain time.

Warning

Using a large number of callbacks can be confusing for the programmer. Especially you should avoid creating a callback from inside a callback function.

Program 7.2 Callbacks
 1from rlzero import *
 2import random
 3
 4aliens = []
 5
 6def add_alien():
 7    aliens.append(
 8        Sprite("alien", (random.randint(0,500), random.randint(0,500)))
 9    )
10
11# call add_alien once, 0.5 seconds from now
12schedule_once(add_alien, 0.5)
13
14# call add_alien over and over again, ever 2 seconds
15schedule_repeat(add_alien, 2.0)
16
17def draw():
18    for alien in aliens:
19        alien.draw()
20
21run()

Exercise

Make the aliens appear more often.

Advanced

Use len(aliens) to print how many aliens there are

Advanced

When there are too many aliens, stop adding them using this code:

schedule_cancel(add_alien)

7.3. Callbacks for animation

Instead of using the Animation class, in this program we define our own function for animation and then ask RLzero to call it back every 0.2 seconds. Most of this code is from Program 5.1.

Program 7.3 Animation via callbacks
 1from rlzero import *
 2
 3WIDTH = 500
 4HEIGHT = 500
 5
 6alan = Sprite('alien.png')
 7alan.pos = (200, 200)
 8
 9def draw():
10    alan.draw()
11
12def update():
13    if keyboard.right:
14        alan.x = alan.x + 2
15    elif keyboard.left:
16        alan.x = alan.x - 2
17    if keyboard.space:
18        schedule_cancel(animateAlien)
19
20images = ["alien_hurt.png", "alien.png"]
21image_counter = 0
22
23def animateAlien():
24    global image_counter
25    alan.image_file = images[image_counter % len(images)]
26    image_counter += 1
27
28schedule_repeat(animateAlien, 0.2)
29
30run()

Exercise

Make the alien animate more quickly.

Advanced

Add another image to the list of images.

Advanced

Draw your own animation, e.g. a man walking left which plays when the left key is pressed

7.4. Simple physics

Here we draw a ball and move it, like we did in Program 4.3. But instead of moving it by a fixed number of pixels, we store the number of pixels to move in variables, vx and vy. These are velocities, i.e. speed in a fixed direction. vx is the speed in the horizontal direction and vy is the speed in the vertical direction. This allow us to change the velocity. Here we reverse the velocity when the ball hits the edge of the screen.

Program 7.4 Simple physics: velocity
 1from rlzero import *
 2
 3WIDTH = 500
 4HEIGHT = 500
 5
 6ball = Rectangle(200, 400, 20, 20)
 7vx = 1
 8vy = 1
 9
10def draw():
11    draw_rectangle_rec(ball, RED)
12
13def update():
14    global vx, vy
15    ball.x += vx
16    ball.y += vy
17    if ball.x > WIDTH or ball.x < 0:
18        vx = -vx
19    if ball.y > HEIGHT or ball.y < 0:
20        vy = -vy
21
22run()

Advanced

Make the ball move faster by increasing its velocity each time it hits the sides.

7.5. Bat and ball game

Pong is the classic bat and ball game.

Program 7.5 Pong
 1from rlzero import *
 2
 3WIDTH = 500
 4HEIGHT = 500
 5
 6ball = Rectangle(150, 400, 20, 20)
 7bat = Rectangle(200, 480, 60, 20)
 8vx = 4
 9vy = 4
10
11def draw():
12    draw_rectangle_rec(ball, RED)
13    draw_rectangle_rec(bat, WHITE)
14
15def update():
16    global vx, vy
17    ball.x += vx
18    ball.y += vy
19    if ball.x > WIDTH or ball.x < 0:
20        vx = -vx
21    if check_collision_recs(bat, ball) or ball.y < 0:
22        vy = -vy
23    if ball.y > HEIGHT:
24        exit()
25    if(keyboard.right):
26        bat.x += 2
27    elif(keyboard.left):
28        bat.x -= 2
29
30run()
31

Exercise

Make the ball move more quickly.

Advanced

Add another bat at the top of the screen for player 2.

Advanced

Add bricks (Rectangles) that disappear when the ball hits them.

7.6. Timer

The update() and draw() functions are called by RLZero many times every second. Each time draw() is called we say it draws one frame. The exact number of frames per second is called the framerate and it will vary from one computer to another. Therefore counting frames is not the most reliable way of keeping time.

Fortunately RLZero can tell us exactly how much many seconds have passed since the last frame in a parameter to our update function. We use this delta time to keep a timer.

Program 7.6 Timer
 1from rlzero import *
 2
 3timer = 0
 4
 5def update(dt):
 6    global timer
 7    timer += dt
 8
 9
10def draw():
11    draw_text(f"Time passed: {timer}", 0, 0, 20, RED)
12    if timer > 5:
13        draw_text("Time's up!", 50, 50, 40, WHITE)
14
15run()

Exercise

Make the timer count down, not up.

Advanced

Add a timer to one of your other games.

Advanced

Add a timer to Program 7.1 that deletes one of the aliens when the timer runs out, then starts the timer again.