game-engine - 编写游戏循环时的困惑

标签 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 编写的,我更寻找一个可以应用于任何语言的通用概念。

最佳答案

这取决于您想要实现的目标。有些游戏更喜欢游戏逻辑比帧速率更频繁地运行(我相信 Source 游戏会这样做),对于某些游戏,您可能希望游戏逻辑运行得不那么频繁(我能想到的唯一例子是服务器)一些多人游戏,最著名的是《守望先锋》)。

还需要考虑的是,这是一个分辨率问题,而不是速度问题。逻辑速率 120 和帧速率 60 的游戏不一定以 x2 速度运行,游戏逻辑中的任何时间关键操作都应该相对于时钟*而不是 tic 速率完成,否则您的游戏实际上会进入慢动作,如果帧渲染时间太长。

我建议编写这样的循环:

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 变量是为了让我们知道在循环开始时计算的间隔是否仍然有效,我们可能已经完成了 5 毫秒的工作,这将完全扰乱我们的 sleep ,因此我们返回并计算新值的场景。

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

关于game-engine - 编写游戏循环时的困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44419729/

相关文章:

c++ - Steady_Clock 在主游戏循环的更新之间跳过

java - 我应该在哪里将游戏循环放入挥杆应用程序?

crystal-lang - 为什么数组 "each"在 Crystal 1.3.0 中不再工作?我应该用什么代替?

crystal-lang - 如何在 C 绑定(bind)中拥有数组类型?

c++ - 将 Lua 绑定(bind)胶水代​​码与我的游戏引擎的其余部分隔离开来

c++ - 为什么对固定时间步长的游戏循环使用积分? (Gaffer 谈游戏)

c++ - Visual Studio 2019 找不到很多头文件

c++ - 在游戏循环中创建类对象

c++ - 对象构造函数的静态库 "Undefined Reference"

lazy-evaluation - 在 Crystal 中实现惰性枚举器