gpt4 book ai didi

windows - 使用操作系统计时器处理游戏循环

转载 作者:可可西里 更新时间:2023-11-01 11:14:31 25 4
gpt4 key购买 nike

一个简单的游戏循环运行起来有点像这样:

MSG msg;
while (running){
if (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
try{
onIdle();
}
catch(std::exception& e){
onError(e.what());
close();
}
}

(取自this question)

为了示例,我在这里以 Windows 为例,它可以是任何平台。如果我弄错了请纠正我,但这样的循环会使用 100% 的 cpu/核心(在我的计算机上使用 50% 的一个核心),因为它总是检查 running 变量的状态.

我的问题是,使用操作系统(在示例 Windows 中)定时器功能实现游戏循环是否会更好(性能方面),根据每个游戏逻辑所需的滴答数设置所需的间隔第二?我问这个是因为我假设定时器功能使用 CPU 的 RTC 中断。

最佳答案

通常,即使用户什么都不做,游戏也会一直绘制新帧。这通常会发生在您调用 onIdle() 的地方。如果您的游戏仅在用户按下按钮或类似按钮时更新窗口/屏幕,或者偶尔在两者之间更新,则 MSGWaitForMultipleObjects 是一个不错的选择。

但是,在连续动画游戏中,如果可以的话,您通常根本不想在渲染线程中阻塞或休眠,而是希望以最大速度渲染并依赖在垂直同步上作为 throttle 。这样做的原因是计时、阻塞和休眠往好里说是不精确的,往坏里说是不可靠的,而且它很可能会给您的动画添加令人不安的人工制品。
您通常想要做的是尽快将属于帧的所有内容推送到图形 API(最有可能是 OpenGL,因为您说的是“任何平台”),向工作线程发出信号以开始执行游戏逻辑和物理等,并且然后在 SwapBuffers 上阻塞。

所有计时器、超时和 sleep 都受调度程序分辨率的限制,在 Windows 下为 15ms(可以使用 timeBeginPeriod 设置为 1ms)。在 60fps 下,一帧是 16.666ms,所以阻塞 15ms 是灾难性的,但即使是 1ms 仍然是相当长的时间。您无法获得更好的分辨率(这在 Linux 下要好得多)。

Sleep,或任何具有超时的阻塞函数,保证您的进程至少只要您要求就可以休眠(事实上,在 Posix 系统上,如果发生中断,它可能睡得)。它不保证您的线程会在时间一到时立即运行,也不提供任何其他保证。
Windows 下的 Sleep(0) 更糟。文档说“线程将放弃其剩余时间片但保持就绪状态。请注意,不能保证就绪线程立即运行”。现实情况是它在大多数情况下都可以正常工作,阻塞从“根本不”到 5-10 毫秒不等,但有时我也看到 Sleep(0) 阻塞 100 毫秒,这在它发生时是灾难性的.

使用 QueryPerformanceCounter 是自找麻烦 -- just don't do it .在某些系统(带有最新 CPU 的 Windows 7)上,它会工作得很好,因为它使用了可靠的 HPET,但在许多其他系统上,您会看到各种奇怪的“时间旅行”或“倒转时间”效果,没有人可以解释或调试。那是因为在那些系统上,QPC 的结果读取取决于 CPU 频率的 TSC 计数器。 CPU 频率不是恒定的,多核/多处理器系统上的 TSC 值不需要保持一致。

然后是同步问题。两个独立的计时器,即使以相同的频率计时,也必然会变得不同步(因为没有“相同”这样的东西)。您的显卡中已经有一个计时器在进行垂直同步。使用这个同步意味着一切都会正常,使用不同的同步意味着事情最终会不同步。不同步可能根本没有效果,可能会绘制一个半完成的帧,或者可能会阻塞一整帧,等等。
虽然丢失一帧通常不是什么大问题(如果它只是一个并且很少发生),但在这种情况下,您首先可以完全避免这种情况。

关于windows - 使用操作系统计时器处理游戏循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5559985/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com