You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Python Turtle的游戏二次重玩异常问题求助

障碍躲避游戏二次重玩异常问题

我用Python的turtle库做了一款障碍躲避游戏,玩家通过上箭头键控制乌龟穿越屏幕、躲避障碍物,失败后点击Replay按钮就能重置游戏。但第二次点击Replay重玩后,障碍物突然加速,而且玩家失败后,障碍物还会继续生成,把Game Over提示都盖住了。

我猜这和tkinter的某些机制有关,调试时发现:乌龟撞到障碍物后,play_game被设为False,但程序还是会递归调用begin_game函数,而且此时play_game的值确实是False。想问下这个异常的原因是什么?为什么二次重玩后障碍物变快、失败后还不停生成?

存在问题的begin_game函数代码

# Begin game when player hits 'Play' or 'Replay' buttons
def begin_game():
    cosmo.showturtle()
    level_display.show_level()
    play_game = True
    screen.update()

    # Call obstacle_generator methods to create obstacles and move them forward
    obstacle_generator.create_obstacles()
    obstacle_generator.obstacle_move()

    # Detect collision between obstacle and turtle
    for c in obstacle_generator.all_obstacles:
        if cosmo.distance(c) <= 20:
            time.sleep(0.3)
            screen.tracer(0)

            # Iterate over obstacle list, hide turtle, and append to recycle list since this game round is over,
            # and they should not be visible on the end game screen
            for num in range(len(obstacle_generator.all_obstacles)):
                obstacle_generator.all_obstacles[num].hideturtle()
                obstacle_generator.recycle.append(obstacle_generator.all_obstacles[num])
            obstacle_generator.all_obstacles = []

            cosmo.hideturtle()

            # Call function to display end game screen
            end_game()

            play_game = False
            break

    # Detect if player has completed current level
    if cosmo.reach_finish_line():
        level_display.refresh_level()
        obstacle_generator.level_up()

    # Recursively call begin_game function if game is still on
    if play_game:
        screen.ontimer(fun=begin_game, t=100)

异常原因分析

1. 未清除旧定时器导致多循环叠加

每次点击Replay触发begin_game时,上一轮游戏通过screen.ontimer()设置的递归定时器并没有被取消。第一次游戏结束后,旧定时器仍在后台触发begin_game调用;二次重玩时又新增了一套定时器,相当于多个游戏循环同时运行。这会让障碍物生成、移动的频率翻倍,视觉上就是“加速”,而且旧循环会持续生成障碍物,覆盖Game Over提示。

2. 局部play_game变量无法终止所有循环

play_game是begin_game的局部变量,每个递归调用的begin_game实例都有独立的play_game。当一次碰撞把当前函数的play_game设为False,其他旧定时器触发的begin_game里的play_game还是True,会继续执行生成障碍物的逻辑。

3. 游戏结束后未阻断残留循环

调用end_game()后,虽然清空了当前障碍物列表,但旧的begin_game循环仍在运行,会持续调用obstacle_generator.create_obstacles()生成新障碍物,导致Game Over界面被覆盖。

修复建议

  • 全局管理游戏状态:把play_game改成全局变量,或者封装到游戏类中作为属性,确保所有begin_game调用共享同一个状态。
  • 重置时清除旧定时器:在点击Play/Replay按钮时,先清除上一轮的定时器。可以用变量保存定时器ID,调用screen.cleartimer(timer_id)取消未触发的定时器。
  • 游戏终止时彻底停循环:在end_game()中设置全局play_game = False,并清除所有定时器,阻断所有残留的begin_game调用。
  • 重构循环逻辑:避免用递归ontimer实现游戏循环,改用while循环结合screen.update(),更易控制启停。

内容的提问来源于stack exchange,提问作者esp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 01:02:09