我正在尝试制作一个以恒定帧速率运行的SDL程序。然而,我发现即使我的程序滞后很多并且跳过很多帧(即使它在低帧运行并且渲染不多)。
你们有什么建议让我的程序运行得更顺畅吗?
#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;
}
答案 0 :(得分:7)
有一个小例子,说明如何在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;
}
答案 1 :(得分:6)
不要睡觉。
相反,使用线性插值函数计算您每次通过主循环时的当前时间的位置。这样做可以保证无论硬件如何,太空船都会同时到达目的地(尽管在快速机器上,你会看到更多的步骤)。
还有其他插值/混合功能(如线性缓入,缓出,二次缓入/缩小,立方等)以用于其他炫酷效果。
答案 2 :(得分:3)
正如dicroce所说,不要睡觉。为什么?因为大多数桌面操作系统不是硬实时系统,因此sleep(10)
并不意味着“在10毫秒内唤醒我”,这意味着“确保我睡着了至少10毫秒“。这意味着有时候你的睡眠时间比你想要的长很多。这很少是你想要的。如果流畅的游戏玩法很重要,那么通常你只想尽可能频繁地渲染 - SDL_Flip会为你处理,只要你的视频驱动程序没有禁用VSync。
而不是睡觉,dicroce建议使用线性插值算法在任何给定时间计算实体的正确位置。虽然对于许多游戏来说这是一个合理的策略,而且我经常使用自己的游戏,但如果不仔细处理,它会在某些情况下导致问题:“Integration Basics”文章解释了其中的一些内容。同一作者下一篇文章中提供的替代方案,名为“Fix Your Timestep”。