2010-03-30 19 views
11

Estoy tratando de hacer un programa SDL que se ejecute con una velocidad de cuadros constante. Sin embargo, estoy descubriendo que a pesar de que mi programa se está quedando bastante rezagado y omitiendo muchos fotogramas (aunque se está ejecutando en un fotograma bajo y no está renderizando demasiado).Lograr una velocidad de cuadros constante en SDL

¿Ustedes tienen alguna sugerencia para hacer que mi programa funcione sin problemas?

#include "SDL.h" 
#include "SDL/SDL_ttf.h" 

//in milliseconds 
const int FPS = 24; 
const int SCREENW = 400; 
const int SCREENH = 300; 
const int BPP = 32; 

void apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination) { 

    SDL_Rect offset; 

    offset.x = x; 

    offset.y = y; 



    if(SDL_BlitSurface(source, NULL, destination, &offset) < 0) { 
     printf("%s\n", SDL_GetError()); 
    } 

} 

int main(int argc, char* argv[]) { 
    //calculate the period 
    double period = 1.0/(double)FPS; 
    period = period * 1000; 
    int milliPeriod = (int)period; 
    int sleep; 

    SDL_Init(SDL_INIT_EVERYTHING); 
    TTF_Init(); 

    TTF_Font* font = TTF_OpenFont("/usr/share/fonts/truetype/freefont/FreeMono.ttf", 24); 
    SDL_Color textColor = { 0x00, 0x00, 0x00 }; 

    SDL_Surface* screen = SDL_SetVideoMode(SCREENW, SCREENH, BPP, SDL_SWSURFACE); 
    SDL_Surface* message = NULL; 

    Uint32 white = SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF); 

    SDL_Event event; 

    char str[15]; 

    Uint32 lastTick; 
    Uint32 currentTick; 
    while(1) { 
     while(SDL_PollEvent(&event)) { 
      if(event.type == SDL_QUIT) { 
       return 0; 
      } 
      else { 
       lastTick = SDL_GetTicks(); 

       sprintf(str, "%d", lastTick); 
       message = TTF_RenderText_Solid(font, str, textColor); 
       if(message == NULL) { printf("%s\n", SDL_GetError()); return 1; } 

       //the actual blitting 
       SDL_FillRect(screen, &screen->clip_rect, white); 
       apply_surface(SCREENW/2, SCREENH/2, message, screen); 

       currentTick = SDL_GetTicks(); 

       //wait the appropriate amount of time 
       sleep = milliPeriod - (currentTick - lastTick); 
       if(sleep < 0) { sleep = 0; } 
       SDL_Delay(sleep); 

       SDL_Flip(screen); 
      } 
     } 
    } 

    TTF_CloseFont(font); 
    TTF_Quit(); 
    SDL_Quit(); 

    return 0; 
} 

Respuesta

6

Do not sleep.

En su lugar, utilice una función de interpolación lineal para calcular su posición dada la hora actual cada vez a través del bucle principal. Hacer esto garantizará que no importa el hardware, las naves espaciales lleguen a sus destinos al mismo tiempo (aunque en una máquina rápida, verá más pasos intermedios).

También hay otras funciones de interpolación/fusión (como la facilidad lineal de entrada y salida, la facilidad de entrada/salida cuadrática, cúbicos, etc.) para otros efectos geniales.

Compruebe hacia fuera este enlace: Frame Rate Independent Linear Interpolation

+16

Creo que podría ser una buena idea dormir para ahorrar pilas. La interpolación es buena y en algunos juegos es bueno hacerlo de todos modos, pero si mi juego puede alcanzar 60 FPS durante el uso, digamos 20% de la CPU, ABSOLUTAMENTE no hay necesidad de correr más rápido, ya que la pantalla probablemente esté funcionando a 60Hz de todos modos, estoy desperdiciando la vida de la batería en computadoras portátiles y dispositivos. –

+0

@TomA ¿No hace SDL VSync que limita el framerate de todos modos? –

+0

Puede elegir entre 3 tipos de V-Sync con SDL 2.x. Ver SDL_GL_SetSwapInterval() – Michaelangel007

4

hay un pequeño ejemplo de cómo hacer esto en http://www.libsdl.org/release/SDL-1.2.15/docs/html/guidetimeexamples.html:

#define TICK_INTERVAL 30 

static Uint32 next_time; 

Uint32 time_left(void) 
{ 
    Uint32 now; 

    now = SDL_GetTicks(); 
    if(next_time <= now) 
     return 0; 
    else 
     return next_time - now; 
} 


/* main game loop */ 

    next_time = SDL_GetTicks() + TICK_INTERVAL; 
    while (game_running) { 
     update_game_state(); 
     SDL_Delay(time_left()); 
     next_time += TICK_INTERVAL; 
    } 
+3

ese enlace está muerto – user1040495

+0

@Jjpx: ya no, pero supongo que fue una respuesta de solo enlace, así que supongo que la pegaré aquí ... – SamB

3

Como dijo DiCroce, no duermen. ¿Por qué? Como la mayoría de los sistemas operativos de escritorio no son sistemas duros en tiempo real, y por lo tanto sleep(10) no significa "despertarme en exactamente 10 milisegundos", significa "asegúrese de estar dormido por al menos 10 milisegundos". Esto significa que a veces pasas mucho más tiempo durmiendo de lo que querías. Esto rara vez es lo que quieres. Si la jugabilidad fluida es importante, generalmente solo quieres renderizar con la mayor frecuencia posible: SDL_Flip maneja eso por ti, siempre que tus drivers de video no tengan la función VSync deshabilitada.

En lugar de dormir, dicroce sugirió un algoritmo de interpolación lineal para calcular las posiciones correctas para sus entidades en un momento dado. Si bien esta es una estrategia razonable para muchos juegos, y una que usualmente uso, puede causar problemas en algunos casos si no se maneja con cuidado: el artículo "Integration Basics" explica algo de esto. Una alternativa ofrecida en el siguiente artículo del mismo autor, llamado "Fix Your Timestep".

Cuestiones relacionadas