Я пытаюсь определить временной шаг для симуляции физики в приложении PhysX, чтобы физика работала с одинаковой скоростью на всех машинах. Я хочу, чтобы физика обновлялась со скоростью 60FPS, поэтому каждое обновление должно иметь время разницы 1/60 секунды.
Мое приложение должно использовать GLUT. В настоящее время мой цикл настроен следующим образом.
Функция холостого хода:
void GLUTGame::Idle()
{
newElapsedTime = glutGet(GLUT_ELAPSED_TIME);
deltaTime = newElapsedTime - lastElapsedTime;
lastElapsedTime = newElapsedTime;
glutPostRedisplay();
}
Частота кадров в данном случае на самом деле не имеет значения — на самом деле важна только скорость, с которой обновляется моя физика.
Моя функция рендеринга содержит следующее:
void GLUTGame::Render()
{
// Rendering Code
simTimer += deltaTime;
if (simTimer > m_fps)
{
m_scene->UpdatePhys(m_fps);
simTimer = 0;
}
}
Куда:
Fl32 m_fps = 1.f/60.f
Однако это приводит к некоторым очень медленным обновлениям из-за того, что deltaTime кажется равным 0 в большинстве циклов (что на самом деле не должно быть возможным …) Я попытался переместить мои вычисления deltaTime в конец моей функции рендеринга , поскольку я думал, что, возможно, обратный вызов в режиме ожидания вызывался слишком часто, но это не решило проблему. Есть идеи, что я здесь делаю не так?
От Сайт OpenGL, мы находим, что glutGet(GLUT_ELAPSED_TIME)
возвращает количество пройденных миллисекунд в виде ИНТ. Итак, если вы позвоните void GLUTGame::Idle()
метод около 2000 раз в секунду, затем время, прошедшее после одного такого вызова, составляет около 1000 * 1/2000 = 0,5 мс. Таким образом, более 2000 вызовов в секунду, чтобы аннулировать GLUTGame::Idle()
результаты в glutGet(GLUT_ELAPSED_TIME)
возврате 0 из-за целочисленного округления.
Скорее всего, вы добавляете очень маленькие числа к более крупным, и вы получаете ошибки округления.
Попробуй это:
void GLUTGame::Idle()
{
newElapsedTime = glutGet(GLUT_ELAPSED_TIME);
timeDelta = newElapsedTime - lastElapsedTime;
if (timeDelta < m_fps) return;
lastElapsedTime = newElapsedTime;
glutPostRedisplay();
}
Вы можете сделать что-то подобное в другом методе, если хотите.
Сейчас я ничего не имею о GLUT или PhysX, но вот как заставить что-то выполняться с одинаковой скоростью (с использованием целых чисел) независимо от того, насколько быстро игра запускается:
if (currentTime - lastUpdateTime > msPerUpdate)
{
DWORD msPassed = currentTime - lastUpdateTime;
int updatesPassed = msPassed / msPerUpdate;
for (int i=0; i<updatesPassed; i++)
UpdatePhysX(); //or whatever function you use
lastUpdateTime = currentTime - msPassed + (updatesPassed * msPerUpdate);
}
куда currentTime
обновляется до timeGetTime
каждый проход по игровому циклу, lastUpdateTime
последний раз обновляется PhysX, и msPerUpdate
количество миллисекунд, которое вы назначаете каждому обновлению — 16 или 17 мс для 60 кадров в секунду
Если вы хотите поддерживать коэффициенты обновления с плавающей запятой (что рекомендуется для физических приложений), тогда определите float timeMultiplier
и обновлять его каждый кадр так: timeMultiplier = (float)frameRate / desiredFrameRate;
— где frameRate
говорит само за себя и desiredFramerate
равно 60.0f, если вы хотите обновить физику со скоростью 60 кадров в секунду. Для этого нужно обновить UpdatePhysX
как принимая float
параметр, на который он умножает все коэффициенты обновления.