I'm trying to make an SDL program that runs with a constant frame rate. However I'm finding that even though my program is lagging a lot and skipping a lot of frames (even though it's running at a low frame and isn't rendering much).
Do you guys have any suggestions to make my program run smoother?
#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);
开发者_如何学JAVA }
}
}
TTF_CloseFont(font);
TTF_Quit();
SDL_Quit();
return 0;
}
There is a small example of how to do this at 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;
}
Don't sleep.
Instead, use a linear interpolation function to compute your position given the current time each time through the main loop. Doing this will guarantee that no matter the hardware, space ships arrive at their destinations at the same time (though on a fast machine, you'll see more of the steps in between).
Also there are other interpolation/blending functions (like linear ease in, ease out, quadratic ease in/out, cubic, etc.) for other cool effects.
Check this link out: Frame Rate Independent Linear Interpolation
As dicroce said, don't sleep. Why? Because most desktop operating systems are not hard real-time systems, and therefore sleep(10)
does not mean "wake me up in exactly 10 milliseconds", it means "ensure I am asleep for at least 10 milliseconds". This means that sometimes you spend a lot longer sleeping than you wanted. This is rarely what you want. If smooth gameplay is important then generally you just want to render as frequently as you can - SDL_Flip handles that for you, providing your video drivers don't have VSync disabled.
Instead of sleeping, dicroce suggested a linear interpolation algorithm to calculate the correct positions for your entities at any given time. While this is a reasonable strategy for many games, and one I usually use myself, it can cause problems in some cases if not handled carefully: the "Integration Basics" article explains some of this. An alternative offered in the same author's next article, called "Fix Your Timestep".
精彩评论