在PyGame中处理定时事件的最佳方法

时间:2010-05-25 20:44:36

标签: python pygame

我正在开发一款俄罗斯方块克隆型游戏,我想知道什么是最好的方法来处理每隔N秒移动一次块的逻辑。我最初做的很简单:

pygame.time.set_timer(USEREVENT+1, 300)

这当然会每300毫秒向队列中添加一个PyGame事件。在主循环中,我可以测试此事件,并在发生时将块放下。这种方法的问题在于玩家可以使用键盘生成的事件轻松地充斥队列。我注意到玩家可以通过简单地快速按下向上翻转的向上箭头来无限制地将块保持在相同的高度。在测试键盘事件之前评估timer事件的代码测试似乎并不重要。键盘总是比计时器具有更高的优先级。知道如何防止这种情况发生吗?

如果这是pygame.time不可避免的怪癖那么处理定时事件的更好方法是什么?

  • 检查每次循环迭代的经过时间,如果大于某个值,则前进块?
  • 使用sched或类似的东西在一个单独的线程中运行并通过一些共享资源发回信号?

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

以下是典型游戏循环的工作原理:

repeat forever:
    read all pending events
    if current time > last frame + frame time:
        last frame = last frame + frame time
        update game
    redraw screen

一个计时器应该每隔300毫秒启动但如果用户使用事件充满游戏则不起作用可能是一个损坏的计时器。但是,如果您在每个用户事件上重绘屏幕而不是在处理完所有待处理事件后重新绘制屏幕,​​那么您的代码就是问题。

以下是游戏循环破损版的示例:

repeat forever:
    read the next pending event
    if current time > last frame + frame time:
        last frame = last frame + frame time
        update game
    redraw screen

它被破坏了,因为它试图过于频繁地重绘屏幕。如果玩家同时按下两个键,它们将被分成不同的帧,这是不必要的。

上述循环假设您希望尽可能频繁地绘制到屏幕上。这很常见,但您可能不希望频繁地在屏幕上绘图。只要在重新绘制屏幕之前抓取所有待处理事件,您使用事件的方法就可以了。

P.S。不要使用多个线程来解决此问题。这会造成巨大的混乱。

答案 1 :(得分:0)

对Dietrich Epp的答案的一次修正 - redraw screen实际上应该在两个后续的游戏状态之间进行插值或推断。这需要为玩家提供流畅的体验。

在插值的情况下,作为插值因子,您使用更新时“左”的时间分数(因为它小于frame time)除以帧时间以获得[0..1]范围内的结果。

这也称为canonical game loop