Python 挑战版 · Day 9

倒计时与 Game Over:给游戏加压力

从“收集宝石”升级成“限时收集宝石”:学生不仅写倒计时,还要理解状态开关如何控制规则。

节奏分配(45 分钟)

01

复习并制造问题

收集宝石能一直玩,所以缺少压力。引出限时挑战。

02

演示倒计时版本

先看 Time 30、29、28,到 0 后 Game Over。

03

加入状态变量

time_left 负责时间,game_over 负责游戏是否结束。

04

刷新信息栏

show_info 同时显示 score 和 time_left。

05

ontimer 自动调用

让 update_time 每隔 1000 毫秒再次执行。

06

结束规则

time_left 到 0 时切换 game_over,并禁止移动和得分。

07

分层改造

调整秒数、最后 5 秒变红、显示最终分数。

教师话术

"限时不是装饰,它改变了玩家的行为:玩家会更快、更紧张。"

"ontimer(update_time, 1000) 的意思是:1000 毫秒后调用 update_time。"

"game_over 是状态变量。移动函数先检查状态,再决定能不能动。"

"如果结束后还能得分,说明有一条路径没有检查 game_over。"

计时器知识卡

time_left

还剩多少秒,是会被 update_time 改变的变量。

screen.ontimer(fn, 1000)

1000 毫秒后调用 fn 一次。想持续倒计时,就在函数里再次安排下一次。

game_over

游戏结束开关,用来统一控制移动和得分。

not game_over

只有游戏没有结束时,才允许移动、收集和加分。

关键代码

计时器核心

python
time_left = 30
game_over = False
 
def update_time():
    global time_left, game_over
 
    if time_left > 0:
        time_left = time_left - 1
        show_info()
        screen.ontimer(update_time, 1000)
    else:
        game_over = True
        show_game_over()

移动前检查 game_over

python
def move_up():
    if not game_over and player.ycor() < top_edge:
        player.sety(player.ycor() + step)
        collect_gem()

完整版本

python
import turtle
import random
 
screen = turtle.Screen()
screen.title("第 9 课:限时收集宝石")
screen.setup(700, 500)
screen.bgcolor("lightcyan")
 
player = turtle.Turtle()
player.shape("turtle")
player.color("green")
player.penup()
player.goto(0, 0)
 
gem = turtle.Turtle()
gem.shape("circle")
gem.color("gold")
gem.penup()
gem.shapesize(0.8)
 
score = 0
time_left = 30
game_over = False
step = 20
left_edge = -320
right_edge = 320
top_edge = 220
bottom_edge = -220
 
pen = turtle.Turtle()
pen.hideturtle()
pen.penup()
 
def move_gem():
    gem.goto(random.randint(-280, 280), random.randint(-180, 180))
 
def show_info():
    pen.clear()
    pen.goto(-310, 210)
    if time_left <= 5:
        pen.color("red")
    else:
        pen.color("black")
    pen.write(f"分数: {score}  时间: {time_left}", font=("Arial", 16, "bold"))
 
def show_game_over():
    pen.clear()
    pen.goto(0, 20)
    pen.color("red")
    pen.write("Game Over", align="center", font=("Arial", 36, "bold"))
    pen.goto(0, -30)
    pen.color("black")
    pen.write(f"最终分数: {score}", align="center", font=("Arial", 18, "normal"))
 
def update_time():
    global time_left, game_over
 
    if time_left > 0:
        time_left = time_left - 1
        show_info()
        screen.ontimer(update_time, 1000)
    else:
        game_over = True
        show_game_over()
 
def collect_gem():
    global score
    if not game_over and player.distance(gem) < 25:
        score = score + 1
        move_gem()
        show_info()
 
def move_up():
    if not game_over and player.ycor() < top_edge:
        player.sety(player.ycor() + step)
        collect_gem()
 
def move_down():
    if not game_over and player.ycor() > bottom_edge:
        player.sety(player.ycor() - step)
        collect_gem()
 
def move_left():
    if not game_over and player.xcor() > left_edge:
        player.setx(player.xcor() - step)
        collect_gem()
 
def move_right():
    if not game_over and player.xcor() < right_edge:
        player.setx(player.xcor() + step)
        collect_gem()
 
move_gem()
show_info()
update_time()
 
screen.listen()
screen.onkey(move_up, "Up")
screen.onkey(move_down, "Down")
screen.onkey(move_left, "Left")
screen.onkey(move_right, "Right")
 
turtle.done()

分层挑战

基础

把倒计时改成 20 秒或 10 秒,并解释难度变化。

进阶

最后 5 秒把时间文字变红。

挑战

显示最终分数,或让每收集 3 个宝石加 3 秒。

完成标准

能解释 ontimer 的两个参数分别是什么。

能说明 time_left 和 game_over 各自负责什么。

能确认时间到 0 后不能移动、不能继续得分。

能做一个限时规则改造,并解释它如何改变游戏体验。

排查 bug 时按路径查:移动函数、收集函数、计时函数都需要尊重 game_over。

收尾问题

如果只有奖励没有危险,好玩吗?下一步可以加入敌人:碰到敌人就提前 Game Over。