12. Tutorial: Race game
In this chapter we will build a racing game together, step by step. The Python we will use is: conditionals, loops, lists, functions and tuples. We will show use of velocity, high score and a title screen.
12.1. Basic game
Similar to the shooter game, we will begin with a complete program
listing but with empty bodies for some of the functions that we will
fill in later. (Python will not run a program with completely empty
functions, so they just contain pass
to indicate to Python they do
nothing.)
Like the shooter program, we begin we three things:
Definitions of global variables.
A
draw()
function.An
update()
function.
These functions now check a boolean variable playing
. If False
then instead of drawing/updating the game we show the title screen.
The only really complicated part of this program is how we store the
shape of the tunnel the player is racing down. lines
is a list of
tuples. A tuple is like a list but cannot be modified and can be
unpacked into separate variables. Each tuple will represent one
horizontal line of the screen. It will have three values, x
, x2
and color
, representing the position of the left wall, the gap
between the left wall and the right wall and the colour of the wall.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | import random
import math
WIDTH = 600
HEIGHT = 600
player = Actor("alien", (300, 580))
player.vx = 0 # horizontal velocity
player.vy = 1 # vertical velocity
lines = [] # list of tuples of horizontal lines of walls
wall_gradient = -3 # steepness of wall
left_wall_x = 200 # x-coordinate of wall
distance = 0 # how far player has travelled
time = 15 # time left until game ends
playing = False # True when in game, False when on title screen
best_distance = 0 # remember the highest distance scored
def draw():
screen.clear()
if playing: # we are in game
for i in range(0, len(lines)): # draw the walls
x, x2, color = lines[i]
screen.draw.line((0, i), (x, i), color)
screen.draw.line((x + x2, i), (WIDTH, i), color)
player.draw()
else: # we are on title screen
screen.draw.text("PRESS SPACE TO START",
(150, 300),color="green",fontsize=40)
screen.draw.text("BEST DISTANCE: "+str(int(best_distance / 10)),
(170, 400), color="green", fontsize=40)
screen.draw.text("SPEED: " + str(int(player.vy)),
(0, 0), color="green", fontsize=40)
screen.draw.text("DISTANCE: " + str(int(distance / 10)),
(200, 0), color="green", fontsize=40)
screen.draw.text("TIME: " + str(int(time)),
(480, 0), color="green", fontsize=40)
def update(delta):
global playing, distance, time
if playing:
wall_collisions()
scroll_walls()
generate_lines()
player_input()
timer(delta)
elif keyboard.space:
playing = True
distance = 0
time = 10
def player_input():
pass
def generate_lines():
pass
generate_lines()
def scroll_walls():
pass
def wall_collisions():
pass
def timer(delta):
pass
def on_mouse_move(pos):
pass
|
Exercise
Run the program. Verify it has a title screen and you can start the game and see the player. (That is all it will do until we fill in the remaining functions.)
12.2. Player input
Replace the definiton of player_input()
with this:
def player_input():
if keyboard.up:
player.vy += 0.1
if keyboard.down:
player.vy -= 0.1
if player.vy < 1:
player.vy = 1
if keyboard.right:
player.vx += 0.4
if keyboard.left:
player.vx -= 0.4
player.x += player.vx
Exercise
Run the program. Verify the player can move left and right and has momentum. Try adjusting the speed or making a limit so you can’t go too fast.
12.3. Generate the walls
We already have code to draw the walls, but currently lines
is empty
so nothing gets drawn. Replace the function generate_lines()
with
this. Note that we immediately call generate_lines()
after defining
it to generate the walls for the start of the game.
def generate_lines():
global wall_gradient, left_wall_x
gap_width = 300 + math.sin(distance / 3000) * 100
while len(lines) < HEIGHT:
pretty_colour = (255, 0, 0)
lines.insert(0, (left_wall_x, gap_width, pretty_colour))
left_wall_x += wall_gradient
if left_wall_x < 0:
left_wall_x = 0
wall_gradient = random.random() * 2 + 0.1
elif left_wall_x + gap_width > WIDTH:
left_wall_x = WIDTH - gap_width
wall_gradient = -random.random() * 2 - 0.1
generate_lines()
Advanced
Run the program. Change the colour of the walls from red to green.
12.4. Make the walls colourful
Modify the line that sets the colour of the generated line to this:
pretty_colour = (255, min(left_wall_x, 255), min(time * 20, 255))
12.5. Scrolling
Modify the scroll_walls()
function so it removes lines from the
bottom of the screen according to the player’s vertical velocity.
def scroll_walls():
global distance
for i in range(0, int(player.vy)):
lines.pop()
distance += 1
Exercise
Modify scroll_walls() as above and check that the player can now accelerate forward.
Advanced
Change the amount of the forward acceleration to make the game faster or slower.
12.6. Wall collisions
Currently the player can move through the walls - we don’t want to allow this. Also we want the player to lose all their velocity each time they collide as a penalty.
def wall_collisions():
a, b, c = lines[-1]
if player.x < a:
player.x += 5
player.vx = player.vx * -0.5
player.vy = 0
if player.x > a + b:
player.x -= 5
player.vx = player.vx * -0.5
player.vy = 0
Exercise
Modify wall_collisions() as above and check that the player now bounces off the walls.
Advanced
Make the collision more bouncy, i.e. the player bounces further when he hits the wall.
12.7. Timer
Currently the player has infinite time. We want decrease the time
variable by how much time has passed and end the game when time runs
out.
def timer(delta):
global time, playing, best_distance
time -= delta
if time < 0:
playing = False
if distance > best_distance:
best_distance = distance
Exercise
Modify the timer() function as above. Verify the game ends after 15 seconds.
Exercise
Make the game last for 30 seconds.
12.8. Mouse movement
The game is easier but perhaps more fun if you can play it with mouse. Pygame will call this function for us automatically.
def on_mouse_move(pos):
x, y = pos
player.x = x
player.vy = (HEIGHT - y) / 20
Exercise
Modify the on_mouse_move() function as above. How does the player accelerate using the mouse?
12.9. Ideas for extension
Draw a new image for the player. Make the Actor show a different image depending on if the player is steering left or right.
Give the player a goal distance that must be reached. If the player reaches this distance he gets extra time added to allow him to continue.
Add sound effects and music.
If you have a larger screen, make the game window taller (and make sure the alien appears at the bottom still).