我有一款使用Bullet Physics作为物理引擎的游戏,这款游戏是在线多人游戏,所以我想尝试使用Source engine方法来处理网络上的物理同步。所以在客户端我使用GLFW,所以fps限制在默认情况下工作。(至少我认为这是因为GLFW)。但是在服务器端没有图形库,所以我需要"锁定"模拟世界的循环,并将物理引擎步进到每秒60个"滴答"。
这是正确的方式来锁定一个循环运行60次每秒吗?(也就是60 "fps")
void World::Run()
{
m_IsRunning = true;
long limit = (1 / 60.0f) * 1000;
long previous = milliseconds_now();
while (m_IsRunning)
{
long start = milliseconds_now();
long deltaTime = start - previous;
previous = start;
std::cout << m_Objects[0]->GetObjectState().position[1] << std::endl;
m_DynamicsWorld->stepSimulation(1 / 60.0f, 10);
long end = milliseconds_now();
long dt = end - start;
if (dt < limit)
{
std::this_thread::sleep_for(std::chrono::milliseconds(limit - dt));
}
}
}
是否可以使用std::thread执行此任务?
这种方式足够有效吗?
物理模拟会被每秒步进60次吗?
p。S
milliseconds_now()
看起来像这样:
long long milliseconds_now()
{
static LARGE_INTEGER s_frequency;
static BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency);
if (s_use_qpc) {
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
return (1000LL * now.QuadPart) / s_frequency.QuadPart;
}
else {
return GetTickCount();
}
}
摘自:https://gamedev.stackexchange.com/questions/26759/best-way-to-get-elapsed-time-in-miliseconds-in-windows
如果你想限制渲染到60帧的最大帧数,这是非常简单的:
每一帧,检查游戏是否运行得太快,如果是就等待,例如:
while ( timeLimitedLoop )
{
float framedelta = ( timeNow - timeLast )
timeLast = timeNow;
for each ( ObjectOrCalculation myObjectOrCalculation in allItemsToProcess )
{
myObjectOrCalculation->processThisIn60thOfSecond(framedelta);
}
render(); // if display needed
}
请注意,如果垂直同步是启用的,渲染将被限制在你的垂直刷新频率,也许50或60赫兹)。
如果,然而,你希望逻辑锁定在60fps,那是另一回事:你将不得不隔离你的显示和逻辑代码,以这样的方式,逻辑运行在60fps的最大值,并修改代码,以便你可以有一个固定的时间间隔循环和一个可变的时间间隔循环(如上所述)。好的资源是"固定时间步长"one_answers"可变时间步长"(链接1链接2和旧的可靠的谷歌搜索)。
代码注释:因为你使用的睡眠是1/60秒的整个持续时间——已经过去的时间,你很容易错过正确的时间,把睡眠改为循环运行,如下所示:
代替
if (dt < limit)
{
std::this_thread::sleep_for(std::chrono::milliseconds(limit - dt));
}
改为
while(dt < limit)
{
std::this_thread::sleep_for(std::chrono::milliseconds(limit - (dt/10.0)));
// or 100.0 or whatever fine-grained step you desire
}
希望这对你有帮助,但是如果你需要更多的信息,请告诉我:)