请耐心等待,这可能有点难以解释清楚。我试图了解如何编写仅使用所需CPU数量的程序。解释起来有点混乱所以我只想用一个真实的例子。
我制作了一个具有无限主游戏循环的俄罗斯方块游戏。我把它限制在40 fps。但是循环仍然每秒执行数千甚至数百万次。它只是在经过足够的时间后将其限制为40 fps。
由于我有一个4核CPU,当我运行游戏时,一切都很好,游戏运行良好。但游戏过程的CPU使用率保持在25%。这是预期的,因为它是一个无限循环并持续运行。
然后我在线阅读为主循环添加1 ms的延迟。这立即将使用量减少到约1%或更低。这很好,但现在我故意每个循环等待1毫秒。它的工作原理是因为我的主循环执行时间少得多,1ms延迟不影响游戏。
但是如果我制作更大的游戏呢?具有更长和更多处理器密集循环的游戏。如果我需要1ms时间片来顺利运行游戏,该怎么办?然后,如果我删除延迟,处理器将再次跳到25%。如果我添加延迟,游戏将会很慢并且可能会有一些延迟。
在这种情况下,理想的解决方案是什么?如何对真实游戏/应用程序进行编码以防止出现此问题?
答案 0 :(得分:5)
由于您在标签中列出了三种不同的语言,因此我将保留此常规,而不提供代码示例。
一般情况下,为了避免刻录CPU,从不都有一个在每次迭代上都没有的循环:
wait()
。 sleep()
是阻塞调用的一个示例,但正如您所观察到的,在许多情况下,它有点像躲闪。
所以:
while(true) {
if(some_condition) {
foo();
}
}
......很糟糕。 (我的一个朋友曾经用这样的代码把共享的大型机带到了一边)
您需要找到一个对显示API的调用,该调用会阻塞直到垂直同步。我相信DirectX,device.Present()
就是这样一个调用,如果设备设置得当。
在单线程游戏中,逻辑可能会出现:
while(game is active)
read user input
calculate next frame
blocking call to display API
因此,CPU会休息,每次都等待垂直同步。
至少有两个线程更常规,一个处理渲染循环,另一个处理游戏状态。在这种情况下,渲染循环需要像以前一样等待垂直同步。游戏状态循环需要阻塞,直到渲染循环准备就绪。
渲染线程循环:
while(game is active)
notify()
prepare_frame(game_state)
blocking call to display API
游戏状态线程循环:
while(game is active)
read user input
update game_state
wait(display_loop_thread)
请务必了解线程等待/通知/加入,以便理解这一点。
此模型允许您拥有其他也影响游戏状态的线程。例如,另一个线程可能控制AI敌人。
另一种方法是使计算事件驱动,并在vsync之后触发它们:
while(game is active)
calculate next frame
blocking call to display API
gameLogic.onFrame()
如果onFrame()花费的时间超过一帧,那么游戏的帧速率就会受到影响。这是否重要取决于游戏;解决方案超出了这个答案的范围 - 如果对你来说很重要,那么可能是时候买一本关于视频游戏架构的书了。
答案 1 :(得分:3)
而不是睡眠1毫秒,你可以睡觉X毫秒,其中X是用公式max(NextDrawingTime-CurrentTime, 0)