← Teacher guide

Optional: Game levels

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.

Python functions and events · Final challenge: Catch the turtle · about 45 minutes · Open the student lesson

Classroom resources

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.

Students will be able to

Timing

Predict, Run and Investigate 15 min · Levels 10 min · Moving turtle 10 min · Your own rule 10 min

Before class

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.)

Running the lesson

  1. Predict: when time runs out, tick sets state to 'over' and draw_scene draws the game-over screen.
  2. Investigate: find every line that changes state and say which event causes it.
  3. Levels: every 5 points, the level goes up and delay drops by 150, but never below 400. Ask why a minimum matters.
  4. Moving turtle: move() takes one step and asks the timer to run it again in 50 ms, until steps reaches 0. This is how game loops move things.
  5. Make: a high score or a boss turtle that needs three clicks. Both need one new variable.

The hard part (on purpose)

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.

When students get stuck

What you will seeA question to askThe 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.

Answers to the checks

  1. Predict: The 30 seconds run out. What is on the screen?
    tick sets state to "over", and draw_scene draws the over screen: Game over, the score and Again.
  2. Investigate: Why does this game use state with three values instead of playing = True or False?
    The game has three screens, and True or False can only tell two apart
    Title, play and over are three different situations. Two values cannot tell the title screen from game over.

Solutions

One possible solution for each task. Other correct programs are fine.

levels and a moving turtle › Levels

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()

levels and a moving turtle › Moving turtle

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()

your own game rule

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 and support

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.

Exit ticket

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.

What each step is for

Where it leads

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.