2006 년 2 학기윈도우게임프로그래밍 제 8 강프레임속도의조절 이대현 한국산업기술대학교 오늘의학습내용 프레임속도의조절 30fps 맞추기 스프라이트프레임속도의조절
프레임속도 (Frame Rate) 프레임속도란? 얼마나빨리프레임 ( 일반적으로하나의완성된화면 ) 을만들어낼수있는지를나타내는척도 일반적으로초당프레임출력횟수를많이사용한다. FPS(Frame Per Sec) 현대의컴퓨터게임에서는일반적으로최소 25~30 fps 이상이기준임. 프레임시간 (frame time) 이란? 한프레임을만들어내는데걸리는시간. 프레임시간과프레임속도의관계 Frame per sec = 1 / Frame time 게임루프에서프레임속도의조절이필요! 일반적으로게임루프의마지막부분에서프레임속도를동기화시킴.
실습 Lecture08-01: 프레임속도의출력 Lecture08-01 프로젝트의구성 C++ 소스파일들 gameengine.cpp 실습시간에작성. main.cpp 실습시간에작성. introstate.cpp playstate.cpp sprite.cpp C++ 헤더파일들 gameengine.h gamestate.h introstate.h playstate.h sprite.h
gameengine.cpp (1) void CGameEngine::Init(const char* title, int width, int height, int bpp, bool fullscreen) int flags = 0; SDL_Init(SDL_INIT_EVERYTHING); if ( fullscreen ) flags = SDL_FULLSCREEN; screen = SDL_SetVideoMode(width, height, bpp, flags); m_fullscreen = fullscreen; m_running = true; TTF_Init(); font = TTF_OpenFont("HYNAMB.ttf", 20); curticks = SDL_GetTicks(); void CGameEngine::UpdateScreen(void) SDL_Flip(screen); gameengine.cpp (2) void CGameEngine::RegulateFPS() SDL_Color fgcolor=0,0,0, bgcolor = 128, 128, 128; char fps[40]; Uint32 elapsedticks = SDL_GetTicks() - curticks; curticks += elapsedticks; sprintf(fps, "%3d ms, %6.1f fps", elapsedticks, 1000.0 / (float)elapsedticks); SDL_Surface *fpsmsg = TTF_RenderText_Shaded(font, fps, fgcolor, bgcolor); SDL_Rect pos = 10, 240, 0, 0; SDL_BlitSurface(fpsMsg, NULL, screen, &pos); SDL_FreeSurface(fpsMsg);
main.cpp int main(int argc, char *argv[]) CGameEngine game; game.init("engine Test v1.0"); freopen("con", "w", stdout); freopen("con", "w", stderr); game.changestate(&introstate); while ( game.running() ) game.handleevents(); game.update(); game.draw(); game.regulatefps(); game.updatescreen(); game.cleanup(); return 0; 실행화면
시간의계산 Uint32 SDL_GetTicks(void); void CGameEngine::Init(const char* title, int width, int height, int bpp, bool fullscreen) int flags = 0; SDL_Init(SDL_INIT_EVERYTHING); if ( fullscreen ) flags = SDL_FULLSCREEN; screen = SDL_SetVideoMode(width, height, bpp, flags); m_fullscreen = fullscreen; m_running = true; TTF_Init(); font = TTF_OpenFont("HYNAMB.ttf", 20); curticks = SDL_GetTicks(); SDL 라이브러리의초기화 (SDL_Init() 함수호출 ) 이후경과된시간을얻음. ms 단위로표현.(ms 보다작은시간은표현못함.) SDL_Flip 의중앙처리 void CGameEngine::UpdateScreen(void) SDL_Flip(screen); 앞선강의에서는, SDL_Flip 의호출을각 State 의 Draw 에서했으나, 여기서는 gameegine 클래스에서중앙처리. 프레임속도를출력하고, 최종적으로 SDL_Flip() 을호출하여, 화면을업데이트하기위해. while ( game.running() ) game.handleevents(); game.update(); game.draw(); game.regulatefps(); game.updatescreen();
프레임처리시간의계산 CGameEngine::Init() 에서 SDL_GetTicks() 호출. CGameEngine::RegulateFPS 에서 SDL_GetTicks 호출. SDL_Init() 호출. CGameEngine::RegulateFPS 에서 SDL_GetTicks 호출. curticks elapsedticks curticks elapsedticks curticks 경과시간 elapsedticks = SDL_GetTicks() - curticks; 프레임속도 FPS = 1000 / elapsedticks; 코드 void CGameEngine::RegulateFPS() SDL_Color fgcolor=0,0,0, bgcolor = 128, 128, 128; char fps[40]; 경과시간의계산 Uint32 elapsedticks = SDL_GetTicks() - curticks; curticks += elapsedticks; curticks 의갱신. sprintf(fps, "%3d ms, %6.1f fps", elapsedticks, 1000.0 / (float)elapsedticks); 프레임시간및프레임속도를문자열로변환. SDL_Surface *fpsmsg = TTF_RenderText_Shaded(font, fps, fgcolor, bgcolor); 사각박스안에문자출력. SDL_Rect pos = 10, 240, 0, 0; SDL_BlitSurface(fpsMsg, NULL, screen, &pos); SDL_FreeSurface(fpsMsg);
실습 Lecture08-02: 프레임속도의조절 프레임속도를낮추는무식한방법 int main(int argc, char *argv[]) CGameEngine game; game.init("engine Test v1.0"); freopen("con", "w", stdout); freopen("con", "w", stderr); game.changestate(&introstate); while ( game.running() ) game.handleevents(); game.update(); game.draw(); 강제로쓸데없는반복을돌린다. for (int i = 0; i < 100; i++) printf("slowing the logic"); game.regulatefps(); game.updatescreen(); game.cleanup(); return 0;
실행결과 : fps 가낮아진다! 왜무식한방법인가? 일단, PC 의성능에따라, fps 가달라진다. 더심각한것은, 운영체제의시간자원을모두다잡아먹는다.
똘똘한방법 : gameengine.cpp #define TARGET_FPS 30 void CGameEngine::RegulateFPS() SDL_Color fgcolor=0,0,0, bgcolor = 128, 128, 128; char fps[40]; Uint32 elapsedticks = SDL_GetTicks() - curticks; if (1000 / elapsedticks > TARGET_FPS) SDL_Delay(1000 / TARGET_FPS - elapsedticks); elapsedticks = SDL_GetTicks() - curticks; curticks += elapsedticks; sprintf(fps, "%3d ms, %6.1f fps", elapsedticks, 1000.0 / (float)elapsedticks); SDL_Surface *fpsmsg = TTF_RenderText_Shaded(font, fps, fgcolor, bgcolor); SDL_Rect pos = 10, 240, 0, 0; SDL_BlitSurface(fpsMsg, NULL, screen, &pos); SDL_FreeSurface(fpsMsg); SDL_Delay() 함수의사용 void SDL_Delay(Uint32 ms); Uint32 elapsedticks = SDL_GetTicks() - curticks; if (1000 / elapsedticks > TARGET_FPS) 현재 fps 가목표 fps 보다높으면 SDL_Delay(1000 / TARGET_FPS - elapsedticks); 목표 fps 를맞추기위해, 필요한시간만큼지연시킨다. SDL_Delay() 함수는단순히지연을시킬뿐만아니라, 운영체제의다른프로세스에게기회를준다.
실행결과 실습 Lecture08-03: 캐릭터프레임속도의조절
sprite.cpp void Sprite::updateFrame(void) static int count = 0; if (count % 3 == 0) frame = (frame + 1) % 8; count = (count + 1) % 3; 스프라이트애니메이션의초당프레임수를 1/3 로낮춘다.