我正在使用OpenGL GLUT代码编写游戏,我正在应用游戏开发技术,该技术包括测量游戏主循环每次迭代所消耗的时间,因此您可以使用它来更新游戏场景与上次更新时的比例。为实现这一目标,我在循环开始时有这个:
void logicLoop () {
float finalTime = (float) clock() / CLOCKS_PER_SEC;
float deltaTime = finalTime - initialTime;
initialTime = finalTime;
...
// Here I move things using deltaTime value
...
}
当我在游戏中添加子弹时出现了问题。如果子弹在两秒内没有击中任何目标,则必须将其销毁。然后,我所做的就是保持对子弹创建时刻的参考:
class Bullet: public GameObject {
float birthday;
public:
Bullet () {
...
// Some initialization staff
...
birthday = (float) clock() / CLOCKS_PER_SEC;
}
float getBirthday () { return birthday; }
}
然后我将其添加到finalTime和deltaTime测量之外的逻辑中:
if (bullet != NULL) {
if (finalTime - bullet->getBirthday() > 2) {
world.remove(bullet);
bullet = NULL;
}
}
它看起来很不错,但是当我运行代码时,子弹会保留太多时间。寻找问题,我打印了(finalTime - bullet-> getBirthday())的值,我看到它增加的确非常慢,就像它不是以秒为单位测量的时间。
问题出在哪里?我认为结果将在几秒钟内完成,因此子弹将在两秒内被移除。
答案 0 :(得分:10)
这是一个常见的错误。 clock()
不衡量实际时间的流逝;它测量CPU运行此特定进程所经过的时间。
其他进程也占用CPU时间,因此两个时钟不一样。每当您的操作系统执行某些其他进程代码时,包括这个代码何时进入"休眠",都不会计入clock()
。如果您的程序在具有多个CPU的系统上是多线程的,clock()
可以"重复计数"时间!
人类对OS时间片没有任何了解或感知:我们只是感知实际时间的实际通过(称为"墙上时间")。最后,您会看到clock()
的时基与时间不同。
Do not use clock()
to measure wall time!
您需要gettimeofday()
或clock_gettime()
之类的内容。为了减轻人们改变系统时间的影响,在Linux上我个人推荐clock_gettime()
使用系统"单调时钟",一个与壁挂时间同步的时钟但是有一个任意的时代不受人们玩电脑的时间设置的影响。 (如果需要,显然可以转用便携式替代品。)
这实际上是在the cppreference.com page for clock()
上讨论的:
std::clock
时间可能比挂钟更快或更慢,这取决于操作系统给予程序的执行资源。例如,如果CPU由其他进程共享,std::clock
时间可能比挂钟慢。另一方面,如果当前进程是多线程的并且有多个执行核心可用,std::clock
时间可能比挂钟更快。
当你不确定发生了什么时,请养成阅读所用功能文档的习惯。
编辑:结果显示GLUT本身有一个可用于此的功能,这可能很方便。 glutGet(GLUT_ELAPSED_TIME)
为您提供自致电glutInit()
以来经过的墙毫秒数。所以我想这就是你需要的东西。它可能稍微高性能,特别是如果GLUT(或OpenGL的其他部分)已经定期请求挂起时间,并且此函数仅查询已经获得的时间...从而使您免于不必要的第二次系统调用(成本)
答案 1 :(得分:1)
如果您在Windows上,可以使用QueryPerformanceFrequency / QueryPerformanceCounter,它可以提供非常准确的时间测量。
以下是一个例子。
#include <Windows.h>
using namespace std;
int main()
{
LARGE_INTEGER freq = {0, 0};
QueryPerformanceFrequency(&freq);
LARGE_INTEGER startTime = {0, 0};
QueryPerformanceCounter(&startTime);
// STUFF.
for(size_t i = 0; i < 100; ++i) {
cout << i << endl;
}
LARGE_INTEGER stopTime = {0, 0};
QueryPerformanceCounter(&stopTime);
const double ellapsed = ((double)stopTime.QuadPart - (double)startTime.QuadPart) / freq.QuadPart;
cout << "Ellapsed: " << ellapsed << endl;
return 0;
}