Pygame类方法中如何实现非阻塞定时执行操作
Pygame固定间隔执行操作非阻塞实现方案
time.sleep()会阻塞整个主线程,直接导致游戏渲染、事件响应全部卡住,绝对不能在Pygame主逻辑里用。游戏场景下最稳妥的实现方式是基于主循环帧时间差的计时方案,不需要开多线程,没有线程安全问题,完全不阻塞循环运行,是2D游戏开发的标准实现思路。
实现原理
Pygame自带的pygame.time.get_ticks()可以返回程序启动后经过的毫秒数,我们只需要给类增加两个记录变量:
- 上一次执行目标方法的时间戳
- 固定触发间隔(50秒对应50000毫秒)
每次主循环运行时,比对当前时间和上次执行时间的差值,达到间隔就执行目标方法,同时更新上次执行的时间戳即可。整个判断过程耗时不到1微秒,完全不会拖慢运行效率。
现有代码的前置bug修正
在加计时逻辑前,先把原有代码里会导致功能失效的错误改了:
- 所有类的
__init__方法漏写self参数(包括buildings、c_panel、monster),实例化时会直接报错 town_hall内部自己新建了一个city实例,但主循环里渲染的是外部单独创建的town实例,加钱操作和显示的对象不是同一个,永远看不到金钱增长self.cit.add_money没加括号,只是引用了函数对象,根本没有实际执行加钱方法- 主循环里
pygame.display.update()和pygame.display.flip()功能重复,保留一个即可
具体修改代码
1. 修正基类定义
class buildings(): def __init__(self): self.b_health = 100 class c_panel(): def __init__(self): pass class monster(): def __init__(self): pass
2. 修改town_hall类,加入计时逻辑
class town_hall(buildings): def __init__(self, target_city): super().__init__() # 调用父类构造方法,继承b_health属性 self.cit = target_city # 绑定外部传入的city实例,保证加钱和显示是同一个对象 self.last_trigger_time = pygame.time.get_ticks() # 初始化上次触发时间为程序当前运行时间 self.trigger_interval = 50 * 1000 # 触发间隔:50秒,单位为毫秒 def adding_money(self): current_time = pygame.time.get_ticks() # 时间差达到间隔就执行加钱 if current_time - self.last_trigger_time >= self.trigger_interval: self.cit.add_money() # 加括号才是实际调用方法 self.last_trigger_time = current_time # 更新上次触发时间
3. 修改实例化代码,传入关联的city对象
town = city() townhall = town_hall(town) # 把要加钱的town实例传入town_hall citizen = citizens()
4. 主循环部分不需要大改,保留原有调用即可
while True: clock.tick(FPS) for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() gamedisplay.fill(WHITE) citizen.draw(gamedisplay) citizen.c_mousedrag() citizen.c_raidfight() townhall.adding_money() # 这个方法现在只会做时间判断,到点才加钱,不会阻塞 town.draw(gamedisplay) pygame.display.flip() # 删掉重复的update调用
不推荐多线程方案的原因
虽然用threading.Timer也能实现定时,但Pygame的渲染、对象属性读写都不是线程安全的,跨线程修改money属性偶尔会出现和渲染逻辑的竞态问题,导致随机崩溃或者显示异常,对于这种简单的定时需求完全没必要引入多线程复杂度。
这个方案的时间误差最多为1帧时长,设置FPS为30时误差不超过33毫秒,对于50秒的触发间隔来说完全感知不到,稳定性远高于多线程方案。
内容的提问来源于stack exchange,提问作者loudmounth artist
相关产品推荐
相关产品推荐

