使用 gettimeofday 钳制 FPS
Posted
技术标签:
【中文标题】使用 gettimeofday 钳制 FPS【英文标题】:Clamping FPS with gettimeofday 【发布时间】:2012-07-11 19:56:51 【问题描述】:我正在尝试通过使用 gettimeofday 将我的游戏循环限制在特定的 FPS 上。这是一个非常初级的游戏,所以它一直在消耗我所有的处理能力。
无论我将 FRAMES_PER_SECOND 设置得有多低,它都会继续尝试以尽可能快的速度运行。
我非常了解 deWiTTERS 对游戏循环的看法,但我使用的是 gettimeofday 而不是 GetTickCount b/c 我在 Mac 上。
另外,我正在运行 OSX 并使用 C++、GLUT。
这是我的主要外观:
int main (int argc, char **argv)
while (true)
timeval t1, t2;
double elapsedTime;
gettimeofday(&t1, NULL); // start timer
const int FRAMES_PER_SECOND = 30;
const int SKIP_TICKS = 1000 / FRAMES_PER_SECOND;
double next_game_tick = elapsedTime;
int sleep_time = 0;
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize (windowWidth, windowHeight);
glutInitWindowPosition (100, 100);
glutCreateWindow ("A basic OpenGL Window");
glutDisplayFunc (display);
glutIdleFunc (idle);
glutReshapeFunc (reshape);
glutPassiveMotionFunc(mouseMovement); //check for mouse movement
glutMouseFunc(buttonPress); //check for button press
gettimeofday(&t2, NULL); // stop timer after one full loop
elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0; // compute sec to ms
elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0; // compute us to ms
next_game_tick += SKIP_TICKS;
sleep_time = next_game_tick - elapsedTime;
if( sleep_time >= 0 )
sleep( sleep_time );
glutMainLoop ();
我尝试将 gettimeofday 和 sleep 函数放置在多个位置,但我似乎找不到它们的最佳位置(考虑到我的代码甚至是正确的)。
【问题讨论】:
如果您使用 GLUT,为什么不使用glutGet(GLUT_ELAPSED_TIME)
?
非常感谢您的评论。我希望有一天能使用 GLUT 的替代品,我认为如果我开始至少让我的计时器功能非 GLUT 特定,那将是朝着正确方向迈出的一步。
【参考方案1】:
这只会被调用一次。我相信你需要将 FPS 逻辑放在 display 函数中,因为 glutMainLoop 永远不会返回。 (这也意味着不需要你的 while 循环。)
edit:或者更有可能它应该进入您的空闲函数。我已经有一段时间没有使用 glut 了。
【讨论】:
非常感谢您的回复。但是,我将整个 FPS 代码移到了我的 glutIdleFunc 中 - 程序在运行时就崩溃了……我的印象是我不得不将gettimeofday(&t1, NULL);
和 gettimeofday(&t2, NULL);
与我的 glutDisplayFunc 分开?
Update1:我已将所有 FPS 代码移至 glutIdleFunc(如您在上面建议的那样)。但是,只有注释掉我的if( sleep_time >= 0 )
语句,我才能让程序运行。也许我的sleep
代码有问题?
Update2:我已将 sleep( sleep_time );
更改为 usleep( sleep_time );
b/c 我正在处理微秒。至少不再冻结我 :) 然而,即使将我的 FRAMES_PER_SECOND
更改为 5
,我也没有看到帧速率发生变化,因为程序继续以极快的速度运行。还在尝试。
更新 3:已修复 - 谢谢! :) B/c 我现在以微秒为单位计算我的睡眠,我不得不乘以 sleep_time 本身:usleep( sleep_time * 1000 )
谢谢,谢谢,谢谢 :)【参考方案2】:
glutMainLoop()
:
glutMainLoop
进入 GLUT 事件处理循环。 此例程在 GLUT 程序中最多应调用一次。一旦调用,此例程将永远不会返回。它将根据需要调用已注册的任何回调。
【讨论】:
非常感谢您的评论。我在 main 中完全删除了 while 循环。谢谢你。另外,我正在尝试将其余的 FPS 代码移动到 glutIdleFunc 中。仍在努力。【参考方案3】:在您从elapsed_time
初始化next_game_tick
时,您还没有初始化elapsed_time
。
【讨论】:
非常感谢您的回复。我已经继续并将elapsedTime
初始化为任意值:float elapsedTime = 1;
但是,在将 FPS 代码移动到 glutIdleFunc 之后,程序对我来说是冻结的。仍在尝试。谢谢。以上是关于使用 gettimeofday 钳制 FPS的主要内容,如果未能解决你的问题,请参考以下文章
如何在不产生 y 旋转抖动的情况下统一使用触摸输入来钳制游戏对象的 z 旋转
Linux时间函数之gettimeofday()函数之使用方法