Pregunta

Estoy construyendo un juego 3D desde cero en C ++ usando OpenGL y SDL en Linux como hobby y para aprender más sobre esta área de programación.

Preguntándote sobre la mejor manera de simular el tiempo mientras el juego se está ejecutando. Obviamente tengo un bucle que se parece a:

void main_loop()
{
    while(!quit)
    {
         handle_events();
         DrawScene();
         ...
         SDL_Delay(time_left());
    }
}

Estoy usando SDL_Delay y time_left () para mantener un framerate de aproximadamente 33 fps.

Pensé que solo necesitaba algunas variables globales como

int current_hour = 0;
int current_min = 0;
int num_days = 0;
Uint32 prev_ticks = 0;

Entonces una función como:

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++;
         }
    }
 }

y luego llame a la función handle_time () en el bucle principal.

Se compila y ejecuta (usando printf para escribir la hora en la consola en este momento) pero me pregunto si esta es la mejor manera de hacerlo. ¿Hay formas más fáciles o más eficientes?

¿Fue útil?

Solución

He mencionado esto antes en otros hilos relacionados con el juego. Como siempre, siga las sugerencias de Glenn Fiedler en su Serie Game Physics

Lo que desea hacer es utilizar un paso de tiempo constante que obtiene al acumular deltas de tiempo. Si desea 33 actualizaciones por segundo, su paso de tiempo constante debe ser 1/33. También podría llamar a esto la frecuencia de actualización . También debe desacoplar la lógica del juego del renderizado, ya que no van de la mano. Desea poder usar una frecuencia de actualización baja mientras renderiza tan rápido como lo permite la máquina. Aquí hay un código de muestra:

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);
}

Esto maneja el submuestreo y el sobremuestreo. Si usa la aritmética de enteros como se hace aquí, la física de su juego debe ser cercana al 100% determinista, sin importar cuán lenta o rápida sea la máquina. Esta es la ventaja de aumentar el tiempo en intervalos de tiempo fijos. El estado utilizado para la representación se calcula mediante la interpolación entre los estados anterior y actual, donde el valor restante dentro del acumulador de tiempo se utiliza como factor de interpolación. Esto asegura que el renderizado sea suave, sin importar cuán grande sea el paso de tiempo.

Otros consejos

Aparte de los problemas ya señalados (debe usar una estructura para los tiempos y pasarla a handle_time () y su minuto se incrementará cada medio minuto) su solución está bien para mantener un registro del tiempo en el juego.

Sin embargo, para la mayoría de los eventos de juegos que deben ocurrir de vez en cuando, probablemente deberías basarlos en el ciclo principal del juego en lugar de un tiempo real para que sucedan en las mismas proporciones con un fps diferente.

Una de las publicaciones de Glenn que realmente querrás leer es Fix Your Timestep! . Después de buscar este enlace, noté que Mads lo dirigió al mismo lugar general en su answer .

No soy un desarrollador de Linux, pero es posible que desee echar un vistazo al uso de Timers en lugar de sondear los ticks.

http://linux.die.net/man/2/timer_create

EDITAR:
SDL parece admitir temporizadores: SDL_SetTimer

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top