La réalisation d'une fréquence de trame constante dans SDL
-
23-09-2019 - |
Question
Je suis en train de faire un programme SDL qui fonctionne avec une fréquence d'image constante. Cependant je trouve que même si mon programme accuse beaucoup et sauter beaucoup de cadres (même si elle est en cours d'exécution à un cadre faible et ne rendant beaucoup plus).
Avez-vous les gars avez des suggestions à faire exécuter mon programme plus lisse?
#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;
}
La solution
Ne pas dormir.
Au lieu de cela, utilisez une fonction d'interpolation linéaire pour calculer votre position donnée l'heure actuelle chaque fois dans la boucle principale. Faire cela garantira que peu importe le matériel, les vaisseaux spatiaux arrivent à destination en même temps (bien que sur une machine rapide, vous verrez plusieurs des étapes entre les deux).
En outre, il existe d'autres interpolation / fonctions de mélange (comme linéaire facilité dans, Décélération, quadratic in / out, cube, etc.) pour d'autres effets sympas.
Vérifier ce lien sur: Frame Rate indépendant interpolation linéaire
Autres conseils
Il y a un petit exemple de la façon de le faire à #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;
}
Comme dit DiCroce, ne pas dormir. Pourquoi? Parce que la plupart des systèmes d'exploitation de bureau ne sont pas difficiles systèmes en temps réel, et donc sleep(10)
ne veut pas dire « me réveiller exactement 10 millisecondes » , cela signifie "assurer que je suis endormi pendant au moins 10 millisecondes ". Cela signifie que, parfois, vous passez beaucoup plus dormir que vous vouliez. Ce qui est rarement ce que vous voulez. Si un gameplay lisse est important alors généralement vous voulez juste rendre aussi souvent que vous le pouvez -. Poignées SDL_Flip pour vous, fournir vos pilotes vidéo n'ont pas VSync désactivé
Au lieu de dormir, DiCroce a proposé un algorithme d'interpolation linéaire pour calculer les positions correctes pour vos entités à un moment donné. Bien que ce soit une stratégie raisonnable pour de nombreux jeux, et je l'emploie habituellement, il peut causer des problèmes dans certains cas, en cas de manipulation avec soin: le « Principes de base d'intégration » article explique une partie de cette. Une alternative proposée à l'article suivant du même auteur, appelé « Fix Votre Timestep ».