double t = 0.0;
double dt = 0.01;
double currentTime = hires_time_in_seconds();
double accumulator = 0.0;
State previous;
State current;
while ( !quit )
{
double newTime = time();
double frameTime = newTime - currentTime;
if ( frameTime > 0.25 )
frameTime = 0.25;
currentTime = newTime;
accumulator += frameTime;
while ( accumulator >= dt )
{
previousState = currentState;
integrate( currentState, t, dt );
t += dt;
accumulator -= dt;
}
const double alpha = accumulator / dt;
State state = currentState * alpha +
previousState * ( 1.0 - alpha );
render( state );
}
目标:
- 我不希望渲染受到帧率的限制,应该在繁忙循环中进行渲染。
- 我想要一个完全固定的时间步长,在其中使用
float
类型的时间增量调用我的更新函数。 - 不能休眠。
我当前的尝试(半固定):
#include <algorithm>
#include <chrono>
#include <SDL.h>
namespace {
using frame_period = std::chrono::duration<long long, std::ratio<1, 60>>;
const float s_desiredFrameRate = 60.0f;
const float s_msPerSecond = 1000;
const float s_desiredFrameTime = s_msPerSecond / s_desiredFrameRate;
const int s_maxUpdateSteps = 6;
const float s_maxDeltaTime = 1.0f;
}
auto framePrev = std::chrono::high_resolution_clock::now();
auto frameCurrent = framePrev;
auto frameDiff = frameCurrent - framePrev;
float previousTicks = SDL_GetTicks();
while (m_mainWindow->IsOpen())
{
float newTicks = SDL_GetTicks();
float frameTime = newTicks - previousTicks;
previousTicks = newTicks;
// 32 ms in a frame would cause this to be .5, 16ms would be 1.0
float totalDeltaTime = frameTime / s_desiredFrameTime;
// Don't execute anything below
while (frameDiff < frame_period{ 1 })
{
frameCurrent = std::chrono::high_resolution_clock::now();
frameDiff = frameCurrent - framePrev;
}
using hr_duration = std::chrono::high_resolution_clock::duration;
framePrev = std::chrono::time_point_cast<hr_duration>(framePrev + frame_period{ 1 });
frameDiff = frameCurrent - framePrev;
// Time step
int i = 0;
while (totalDeltaTime > 0.0f && i < s_maxUpdateSteps)
{
float deltaTime = std::min(totalDeltaTime, s_maxDeltaTime);
m_gameController->Update(deltaTime);
totalDeltaTime -= deltaTime;
i++;
}
// ProcessCallbackQueue();
// ProcessSDLEvents();
// m_renderEngine->Render();
}
这种实现的问题
- 渲染、处理输入等都与帧率相关
- 我使用的是SDL_GetTicks()而不是std::chrono
我的实际问题
- 我如何将
SDL_GetTicks()
替换为std::chrono::high_resolution_clock::now()
?似乎无论如何我都需要使用count()
,但我从Howard Hinnant本人那里读到了这句话:
如果你使用count(),和/或者在你的chrono代码中有转换因子,那么你就是在过度尝试。 所以我想可能有一种更直观的方式。
- 我如何用实际的std::chrono_literal时间值取代所有的
float
,除了最后我得到float deltaTime
作为模拟更新函数的修饰符之外?
State state = currentState * alpha + previousState * (1 - alpha)
会扩展到在state.acceleration
和state.velocity
上执行该操作吗?我不确定是否暗示了一种可以执行该操作的operator=
重载。 - Josh Sanders250毫秒
是另一种表示milliseconds{250}
的方式。这种语法要求使用C++14或更高版本,并且需要添加using namespace std::chrono_literals;
语句。 - Howard Hinnant250ms
是为了应对“死循环”而设置的帧时间限制。它不一定要恰好是250ms
,但应该足够高以处理(希望是暂时的)负载峰值。 - Fake Code Monkey Rashidchrono
库的大量使用尤其令人启发。如果我必须挑剔什么,那就是integrate
函数不完整(传递了t
但未命名或使用),并且在此基础上应该让人们知道积分基础确实是必读的。 - Fake Code Monkey Rashid