使用c ++在游戏循环中模拟时间

Tim*_*Tim 4 c++ opengl sdl

我正在使用Linux上的OpenGL和SDL从头开始构建一个3D游戏作为业余爱好,并了解有关这一编程领域的更多信息.

想知道在游戏运行时模拟时间的最佳方法.显然我有一个看起来像这样的循环:

void main_loop()
{
    while(!quit)
    {
         handle_events();
         DrawScene();
         ...
         SDL_Delay(time_left());
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用SDL_Delay和time_left()来保持大约33 fps的帧速率.

我以为我只需要一些全局变量

int current_hour = 0;
int current_min = 0;
int num_days = 0;
Uint32 prev_ticks = 0;
Run Code Online (Sandbox Code Playgroud)

然后是一个函数:

void handle_time()
{
    Uint32 current_ticks;
    Uint32 dticks;
    current_ticks = SDL_GetTicks();
    dticks = current_ticks - prev_ticks; // get difference since last time

    // if difference is greater than 30000 (half minute) increment game mins
    if(dticks >= 30000) {
         prev_ticks = current_ticks;
         current_mins++;
         if(current_mins >= 60) {
            current_mins = 0;
            current_hour++;
         }
         if(current_hour > 23) {
            current_hour = 0;
            num_days++;
         }
    }
 }
Run Code Online (Sandbox Code Playgroud)

然后在主循环中调用handle_time()函数.

它编译并运行(使用printf将时间写入控制台)但我想知道这是否是最好的方法.有更简单的方法或更有效的方法吗?

小智 13

我之前在其他游戏相关的主题中提到了这一点.一如既往,请遵循Glenn Fiedler在Game Physics系列中的建议

你想要做的是使用一个恒定的时间步长,你通过累积时间增量来获得.如果你想每秒33次更新,那么你的恒定时间步长应该是1/33.您也可以将此称为更新频率.您还应该将游戏逻辑与渲染分离,因为它们不属于一起.您希望能够在渲染速度与机器允许的情况下一样快地使用较低的更新频率.以下是一些示例代码:

running = true;
unsigned int t_accum=0,lt=0,ct=0;
while(running){
    while(SDL_PollEvent(&event)){
        switch(event.type){
            ...
        }
    }
    ct = SDL_GetTicks();
    t_accum += ct - lt;
    lt = ct;
    while(t_accum >= timestep){
        t += timestep; /* this is our actual time, in milliseconds. */
        t_accum -= timestep;
        for(std::vector<Entity>::iterator en = entities.begin(); en != entities.end(); ++en){
            integrate(en, (float)t * 0.001f, timestep);
        }
    }
    /* This should really be in a separate thread, synchronized with a mutex */
    std::vector<Entity> tmpEntities(entities.size());
    for(int i=0; i<entities.size(); ++i){
        float alpha = (float)t_accum / (float)timestep;
        tmpEntities[i] = interpolateState(entities[i].lastState, alpha, entities[i].currentState, 1.0f - alpha);
    }
    Render(tmpEntities);
}
Run Code Online (Sandbox Code Playgroud)

这样可以处理欠采样和过采样.如果你使用像这里完成的整数运算,你的游戏物理应该接近100%确定性,无论机器有多慢或多快.这是在固定时间间隔内增加时间的优点.用于渲染的状态是通过在先前状态和当前状态之间进行插值来计算的,其中时间累加器内的剩余值被用作插值因子.无论时间步长多大,这都可确保渲染顺利进行.