An optional lesson in the games direction. Students add screens (title, play, game over), levels that speed up and a turtle that walks between spots, the way game engines move sprites.
Load these into Waypoints Prepare: choose Load URL and paste the copied address, or download the file and import it. In Prepare, the worksheet's Teacher edition shows the answers; the student copy hides them.
Predict, Run and Investigate 15 min · Levels 10 min · Moving turtle 10 min · Your own rule 10 min
state holds one of three words: "title", "play" or "over". It replaces True and False because a game has three screens, and two values cannot tell them apart. The moving turtle takes 10 small steps, one every 50 milliseconds, instead of jumping. (An animated move with speed() would make the program ignore clicks until the move finished.)
A state variable deciding which screen runs. Ask them to say which state the game is in after each click, and check the spelling is the same everywhere.
| What you will see | A question to ask | The fix |
|---|---|---|
| A screen never appears. | Is the state name spelt the same everywhere, including capitals? | "Play" and "play" are different. Use the same lowercase words everywhere. |
| The game becomes impossibly fast. | What stops delay getting smaller and smaller? | Only take 150 off while delay > 400. |
| A new game starts at the level the last one ended on. | What does start() set back to the beginning? | Reset level and delay in start(), with score and time. |
One possible solution for each task. Other correct programs are fine.
from turtle import *
from ui import inside, draw_button
speed(0)
penup()
hideturtle()
xs = [-120, 0, 120, 120, 0, -120]
ys = [60, 110, 60, -50, -100, -50]
place = 0
tx = 0
ty = 0
score = 0
showing = False
time_left = 30
state = "title"
level = 1
delay = 1000
def big(text, x, y):
goto(x, y)
write(text, False, "left", ("Arial", 28, "bold"))
def draw_scene():
clear()
if state == "title":
big("Catch the turtle", -140, 40)
draw_button(-60, -180, 120, 40, "Play")
if state == "play":
goto(-190, 160)
write(score, False, "left", ("Arial", 20, "normal"))
goto(150, 160)
write(time_left, False, "left", ("Arial", 20, "normal"))
goto(-30, 160)
write(level, False, "left", ("Arial", 20, "normal"))
if state == "over":
big("Game over", -90, 40)
big(score, -10, -10)
draw_button(-60, -180, 120, 40, "Again")
goto(tx, ty)
def hop():
global place, tx, ty, showing
if state == "play":
tx = xs[place]
ty = ys[place]
place = (place + 1) % len(xs)
goto(tx, ty)
showturtle()
showing = True
ontimer(hide, delay - 300)
ontimer(hop, delay)
def hide():
global showing
if showing:
showing = False
hideturtle()
def tick():
global time_left, state
if state == "play":
time_left = time_left - 1
if time_left == 0:
state = "over"
hideturtle()
else:
ontimer(tick, 1000)
draw_scene()
def start():
global score, time_left, place, state, level, delay
level = 1
delay = 1000
score = 0
time_left = 30
place = 0
state = "play"
draw_scene()
hop()
ontimer(tick, 1000)
def clicked(x, y):
global score, showing, level, delay
if state == "play" and showing and inside(x, y, tx - 20, ty - 20, 40, 40):
score = score + 1
if score % 5 == 0 and delay > 400:
level = level + 1
delay = delay - 150
showing = False
hideturtle()
draw_scene()
if state != "play" and inside(x, y, -60, -180, 120, 40):
start()
draw_scene()
onscreenclick(clicked)
listen()
mainloop()
from turtle import *
from ui import inside, draw_button
speed(0)
penup()
hideturtle()
xs = [-120, 0, 120, 120, 0, -120]
ys = [60, 110, 60, -50, -100, -50]
place = 0
tx = 0
ty = 0
score = 0
showing = False
time_left = 30
state = "title"
level = 1
delay = 1000
steps = 0
dx = 0
dy = 0
def big(text, x, y):
goto(x, y)
write(text, False, "left", ("Arial", 28, "bold"))
def draw_scene():
clear()
if state == "title":
big("Catch the turtle", -140, 40)
draw_button(-60, -180, 120, 40, "Play")
if state == "play":
goto(-190, 160)
write(score, False, "left", ("Arial", 20, "normal"))
goto(150, 160)
write(time_left, False, "left", ("Arial", 20, "normal"))
goto(-30, 160)
write(level, False, "left", ("Arial", 20, "normal"))
if state == "over":
big("Game over", -90, 40)
big(score, -10, -10)
draw_button(-60, -180, 120, 40, "Again")
goto(tx, ty)
def move():
global tx, ty, steps
if state == "play" and steps > 0:
tx = tx + dx
ty = ty + dy
goto(tx, ty)
steps = steps - 1
ontimer(move, 50)
def hop():
global place, showing, steps, dx, dy
if state == "play":
dx = (xs[place] - tx) / 10
dy = (ys[place] - ty) / 10
steps = 10
place = (place + 1) % len(xs)
showturtle()
showing = True
move()
ontimer(hide, delay - 300)
ontimer(hop, delay)
def hide():
global showing
if showing:
showing = False
hideturtle()
def tick():
global time_left, state
if state == "play":
time_left = time_left - 1
if time_left == 0:
state = "over"
hideturtle()
else:
ontimer(tick, 1000)
draw_scene()
def start():
global score, time_left, place, state, level, delay
level = 1
delay = 1000
score = 0
time_left = 30
place = 0
state = "play"
draw_scene()
hop()
ontimer(tick, 1000)
def clicked(x, y):
global score, showing, level, delay
if state == "play" and showing and inside(x, y, tx - 20, ty - 20, 40, 40):
score = score + 1
if score % 5 == 0 and delay > 400:
level = level + 1
delay = delay - 150
showing = False
hideturtle()
draw_scene()
if state != "play" and inside(x, y, -60, -180, 120, 40):
start()
draw_scene()
onscreenclick(clicked)
listen()
mainloop()
from turtle import *
from ui import inside, draw_button
speed(0)
penup()
hideturtle()
xs = [-120, 0, 120, 120, 0, -120]
ys = [60, 110, 60, -50, -100, -50]
place = 0
tx = 0
ty = 0
score = 0
showing = False
time_left = 30
state = "title"
best = 0
level = 1
delay = 1000
steps = 0
dx = 0
dy = 0
def big(text, x, y):
goto(x, y)
write(text, False, "left", ("Arial", 28, "bold"))
def draw_scene():
clear()
if state == "title":
big("Catch the turtle", -140, 40)
draw_button(-60, -180, 120, 40, "Play")
if state == "play":
goto(-190, 160)
write(score, False, "left", ("Arial", 20, "normal"))
goto(150, 160)
write(time_left, False, "left", ("Arial", 20, "normal"))
goto(-30, 160)
write(level, False, "left", ("Arial", 20, "normal"))
if state == "over":
big("Game over", -90, 40)
big(score, -10, -10)
goto(-60, -60)
write("Best:", False, "left", ("Arial", 16, "normal"))
goto(0, -60)
write(best, False, "left", ("Arial", 16, "bold"))
draw_button(-60, -180, 120, 40, "Again")
goto(tx, ty)
def move():
global tx, ty, steps
if state == "play" and steps > 0:
tx = tx + dx
ty = ty + dy
goto(tx, ty)
steps = steps - 1
ontimer(move, 50)
def hop():
global place, showing, steps, dx, dy
if state == "play":
dx = (xs[place] - tx) / 10
dy = (ys[place] - ty) / 10
steps = 10
place = (place + 1) % len(xs)
showturtle()
showing = True
move()
ontimer(hide, delay - 300)
ontimer(hop, delay)
def hide():
global showing
if showing:
showing = False
hideturtle()
def tick():
global time_left, state, best
if state == "play":
time_left = time_left - 1
if time_left == 0:
state = "over"
if score > best:
best = score
hideturtle()
else:
ontimer(tick, 1000)
draw_scene()
def start():
global score, time_left, place, state, level, delay
level = 1
delay = 1000
score = 0
time_left = 30
place = 0
state = "play"
draw_scene()
hop()
ontimer(tick, 1000)
def clicked(x, y):
global score, showing, level, delay
if state == "play" and showing and inside(x, y, tx - 20, ty - 20, 40, 40):
score = score + 1
if score % 5 == 0 and delay > 400:
level = level + 1
delay = delay - 150
showing = False
hideturtle()
draw_scene()
if state != "play" and inside(x, y, -60, -180, 120, 40):
start()
draw_scene()
onscreenclick(clicked)
listen()
mainloop()
Stretch: Add a boss turtle every tenth spot that needs three clicks, with its own hit counter.
Support: Do Levels together; leave Moving turtle as an extra for those who finish.
Why does this game use state = "title", "play" or "over" instead of playing = True or False?
There are three screens, and True or False can only tell two situations apart.
MakeCode Arcade and microStudio give you sprites that move by themselves and screens to switch between. Underneath they run the same loop: update the data, check for hits, redraw.