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

如何在Turtle图形库中终止ontimer已设置的函数?蛇游戏问题

问题描述

我正在开发一款食物可随机传送的蛇类游戏,使用Turtle库的ontimer结合函数递归,让mole(食物)在固定位置停留3秒后自动传送。但玩家控制的乌龟吃到mole时,触发传送后,之前ontimer已经设置好的回调函数仍会在到点后执行,导致传送被调用两次。我试过用参数阻止递归,但实际需求是:乌龟吃到mole后,传送计时器要重新从起点开始计时,而不是继续之前的剩余时间。

原主代码:

def mole_teleport(is_loop=True):
        rand_x = random.randint(-250, 250)
        rand_y = random.randint(-250, 250)
        mole.teleport(rand_x, rand_y)
        if is_loop == False:
            return
        else:
            screen.ontimer(mole_teleport, 3000)

tim = Player() #user_turtle
mole = Turtle("circle")

mole_teleport()

screen = Screen()
screen.setup(600, 600)

screen.listen()
screen.onkey(tim.turn_left, "Left")
screen.onkey(tim.turn_right, "Right")

game_is_on = True
while game_is_on:
    tim.move()
    if mole.distance(tim) < 20:
        mole_teleport(is_loop=False)

Player类代码:

from turtle import Turtle

SPEED = 3

class Player(Turtle):
    
    def __init__(self) -> None:
        super().__init__()
        self.speed("fastest")
        self.shape("turtle")
        self.penup()
    
    def move(self):
        self.forward(SPEED)
    
    
    def turn_left(self):
        self.left(90)
        
    def turn_right(self):
        self.right(90)
解决方案

问题核心是:之前通过ontimer注册的3秒回调并没有被取消,即使你调用mole_teleport(is_loop=False)立即传送,那个已经在队列里的回调到时间还是会执行。要实现"吃到食物后重置计时器",需要先取消之前的计时器,再重新启动计时。

Turtle的ontimer会返回一个计时器ID,我们可以保存这个ID,在需要重置时用screen.cleartimer(timer_id)取消未触发的计时器,然后重新调用传送函数并设置新的计时器。

修改后的完整代码:

import random
from turtle import Turtle, Screen

def mole_teleport():
    rand_x = random.randint(-250, 250)
    rand_y = random.randint(-250, 250)
    mole.teleport(rand_x, rand_y)
    # 保存计时器ID,用于后续取消操作
    global timer_id
    timer_id = screen.ontimer(mole_teleport, 3000)

class Player(Turtle):
    SPEED = 3
    
    def __init__(self) -> None:
        super().__init__()
        self.speed("fastest")
        self.shape("turtle")
        self.penup()
    
    def move(self):
        self.forward(self.SPEED)
    
    def turn_left(self):
        self.left(90)
        
    def turn_right(self):
        self.right(90)

# 初始化游戏元素
tim = Player()
mole = Turtle("circle")
screen = Screen()
screen.setup(600, 600)

# 绑定控制按键
screen.listen()
screen.onkey(tim.turn_left, "Left")
screen.onkey(tim.turn_right, "Right")

# 初始化计时器ID并启动首次传送
timer_id = None
mole_teleport()

game_is_on = True
while game_is_on:
    screen.update()  # 优化动画流畅度,避免循环卡顿
    tim.move()
    if mole.distance(tim) < 20:
        # 取消之前未触发的计时器
        screen.cleartimer(timer_id)
        # 立即传送并重新启动3秒计时
        mole_teleport()

关键修改点:

  • 移除了is_loop参数,简化逻辑:每次调用mole_teleport都会完成传送,并设置下一次3秒后的传送计时器,同时保存计时器ID
  • 吃到食物时,先调用screen.cleartimer(timer_id)取消之前注册的计时器,再重新调用mole_teleport,确保计时器从当前时间重新开始计算3秒,不会出现重复触发
  • 添加screen.update()优化游戏循环的动画流畅度,避免Turtle原生循环的卡顿问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 05:17:11