2010-03-30 3 views
11

Ich versuche, ein SDL-Programm zu erstellen, das mit einer konstanten Bildrate ausgeführt wird. Allerdings finde ich das, obwohl mein Programm viel hinterherhinkt und viele Frames überspringt (obwohl es auf einem niedrigen Frame läuft und nicht viel rendert).Erzielen einer konstanten Bildrate in SDL

Haben Sie irgendwelche Vorschläge, um mein Programm reibungsloser laufen zu lassen?

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

Antwort

6

Schlafen Sie nicht.

Verwenden Sie stattdessen eine lineare Interpolationsfunktion, um Ihre Position mit der aktuellen Zeit jedes Mal durch die Hauptschleife zu berechnen. Auf diese Weise können Sie sicherstellen, dass Raumschiffe unabhängig von der Hardware gleichzeitig an ihrem Zielort ankommen (obwohl Sie auf einer schnellen Maschine mehr Zwischenschritte sehen).

Es gibt auch andere Interpolation/Blending-Funktionen (wie lineares Ein- und Aussteigen, quadratisches Ein-/Aussteigen, kubisches usw.) für andere coole Effekte.

prüfen Link aus: Frame Rate Independent Linear Interpolation

+16

Ich denke, es wäre eine gute Idee zu schlafen, um Batterien zu sparen. Interpolation ist gut und in einigen Spielen ist es gut, es trotzdem zu machen, aber wenn mein Spiel 60FPS während der Benutzung erreichen kann, sagen wir 20% der CPU, gibt es ABSOLUT keine Notwendigkeit schneller zu laufen, da das Display höchstwahrscheinlich mit 60Hz läuft trotzdem verschwende ich nur die Akkulaufzeit auf Notebooks und Geräten. –

+0

@TomA Führt SDL nicht VSync durch, welches die Framerate sowieso kappt? –

+0

Sie können zwischen drei Arten von V-Sync mit SDL 2.x wählen. Siehe SDL_GL_SetSwapInterval() – Michaelangel007

4

Es ist ein kleines Beispiel, wie dies bei http://www.libsdl.org/release/SDL-1.2.15/docs/html/guidetimeexamples.html zu tun:

#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

dieser Link ist tot – user1040495

+0

@Jjpx: nicht mehr, aber ich denke, das war eine Link-only-Antwort, also denke ich, ich werde es hier einfügen ... – SamB

3

Wie dicroce sagte, nicht schlafen. Warum? Da die meisten Desktop-Betriebssysteme keine harten Echtzeitsysteme sind, bedeutet nicht "wecken Sie mich in genau 10 Millisekunden", bedeutet es "sicherstellen, dass ich für mindestens 10 Millisekunden schlafen". Dies bedeutet, dass Sie manchmal viel länger schlafen als Sie wollten. Das ist selten was du willst. Wenn flüssiges Gameplay wichtig ist, solltest du es nur so oft rendern, wie du kannst - SDL_Flip erledigt das für dich, vorausgesetzt, dass VSync in deinen Videotreibern nicht deaktiviert ist.

Anstatt zu schlafen, schlug dicerace einen linearen Interpolationsalgorithmus vor, um die korrekten Positionen für Ihre Entitäten zu jeder beliebigen Zeit zu berechnen. Während dies eine vernünftige Strategie für viele Spiele ist, und eine, die ich normalerweise selbst benutze, kann es in einigen Fällen Probleme verursachen, wenn nicht sorgfältig behandelt wird: der Artikel "Integration Basics" erklärt einiges davon. Eine Alternative, die im nächsten Artikel des gleichen Autors angeboten wird, genannt "Fix Your Timestep".