写游戏循环的困惑

时间:2017-06-07 17:58:57

标签: game-engine game-loop crystal-lang

我正在研究2D视频游戏框架,我之前从未编写过游戏循环。我曾经研究过的大多数框架似乎都实现了drawupdate方法。

对于my project,我实现了一个调用这两种方法的循环。我注意到其他框架,这些方法并不总是被称为交替。某些框架的update运行速度超过draw。此外,大多数这些类型的框架将以60FPS运行。我想我在这里需要一些睡眠。

我的问题是,实现这种类型循环的最佳方法是什么?我打电话给draw然后update,反之亦然?在我的情况下,我正在编写SDL2的包装器,所以也许该库需要以某种方式设置某些东西?

这是我正在考虑实施的一些“伪”代码。

loop do
  clear_screen
  draw
  update
  sleep(16.milliseconds)
  break if window_is_closed
end

虽然我的项目是用Crystal-Lang编写的,但我更多的是寻找可应用于任何语言的一般概念。

1 个答案:

答案 0 :(得分:2)

这取决于你想要达到的目标。有些游戏更喜欢游戏逻辑比帧速率更频繁地运行(我相信源游戏会这样做),对于某些游戏,你可能希望游戏逻辑运行频率较低(我能想到的唯一例子是服务器)一些多人游戏,非常着名的Overwatch)。

同样重要的是要考虑这是分辨率的问题,而不是速度问题。逻辑速率为120且帧速率为60的游戏不一定以x2速度运行,任何时候游戏逻辑中的关键操作都应该相对于时钟*而不是抽动率进行,否则你的游戏将逐渐进入慢速运动状态。帧渲染时间太长。

我建议写一个这样的循环:

loop do
    time_until_update = (update_interval + time_of_last_update) - current_time
    time_until_draw = (draw_interval + time_of_last_draw) - current_time
    work_done = false

    # Update the game if it's been enough time
    if time_until_update <= 0
        update
        time_of_last_update = current_time
        work_done = true
    end

    # Draw the screen if it's been enough time
    if time_until_draw <= 0
        clear_screen
        draw
        time_of_last_draw = current_time
        work_done = true
    end

    # Nothing to do, sleep for the smallest period
    if work_done == false
        smaller = time_until_update

        if time_until_draw < smaller
            smaller = time_until_draw
        end

        sleep_for(smaller)
    end

    # Leave, maybe
    break if window_is_closed
end

你不想每帧等待16毫秒,否则如果帧花费了很多时间来完成,你最终可能会过度等待。 work_done变量是这样的,我们知道我们在循环开始时计算的间隔是否仍然有效,我们可能已经完成了5ms的工作,这会使我们的睡眠完全关闭,所以在这种情况下我们去回来并计算新的价值。

*你可能想要对时钟进行抽象化,直接使用时钟可以产生一些奇怪的效果,例如如果你保存游戏而你上次使用神奇的力量作为时钟时间保存,它会立即脱落加载保存时的冷却时间,因为现在是过去几分钟,几小时甚至几天。操作系统暂停进程也存在类似问题。