我正在开发 2D 视频游戏框架,之前从未编写过游戏循环。我研究过的大多数框架似乎都实现了 draw
和 update
方法。
对于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/