게임에서 시간 계산
게임에서 발생하는 물리 현상(캐릭터 이동부터 물체 파괴까지)은 시간에 영향을 받습니다. 그러면 어떻게 컴퓨터에서 시간을 정확하게 계산할 수 있을까요?
컴퓨터 성능에 의존하는 경우
일반적으로 이와 같은 상황에서 언급되는 함수는 Sleep
입니다. Sleep
은 밀리세컨드(milliseconds) 단위로 ‘지연’하는 함수입니다. 따라서 다음과 같이 코드를 작성할 수 있겠죠. (아래 코드에 따라 게임이 동작한다고 가정해봅시다.)
1
2
3
4
5
6
7
8
while(false == bQuit)
{
Sleep(fTimeDelay);
Game::Update();
Game::Render();
Game::Collide();
}
문제점
그런데 이 Sleep
함수에는 문제가 있습니다. 우리가 원하는 정확한 시간을 주지 않는다는 것입니다. Sleep
을 사용한 프로그램을 CPU 부하가 큰 상황과 그렇지 않은 상황에서 실행할 경우 시간 지연이 다르다는 것을 얻을 수 있습니다.
우리에게는 컴퓨터 성능에 의존하지 않는 시간이 필요합니다. 그러면 어떻게 컴퓨터에서 정확한 시간을 계산할 수 있을까요?
그러면 어떻게 시간을 계산하는가
Windows에서는 profileapi.h
에 이전 프레임과 현재 프레임 사이의 시간을 정확하게 계산하기 위한 QueryPerformanceFrequency 와 QueryPerformanceCounter 가 있습니다.
1
BOOL QueryPerformanceFrequency( LARGE_INTEGER *lpFrequency );
QueryPerformanceFrequency
는 성능 카운터의 빈도를 돌려줍니다. 시스템 부팅시 고정되어 있으며 모든 프로세서에서 일관된 결과를 돌려줍니다.
1
BOOL QueryPerformanceCounter( LARGE_INTEGER *lpPerformanceCount );
QueryPerformanceCounter
는 시간 간격 측정에 사용할 수 있는 고해상도 (<1us) 타임 스탬프인 성능 카운터의 현재 값을 돌려줍니다.
이제 컴퓨터에서 고정된 시간 값을 계산할 수 있겠군요.
DeltaTime Class
Delta time은 이전 프레임과 현재 프레임 사이의 시간을 말합니다. 그러면 우선 Time
클래스를 작성해봅시다. 그리고 이를 통해 델타 타임을 얻어 봅시다.
이제 Timer
클래스로 델타 타임만 가져올 수 있도록 작성해봅시다. 주석도 달아놨습니다만, Time
클래스는 Timer
의 이너 클래스(inner class)입니다.
어떻게 쓰면 되나요?
1
2
3
4
5
6
7
8
while(false == bQuit)
{
Sleep(fTimeDelay);
Game::Update();
Game::Render();
Game::Collide();
}
이제 위 코드를 수정해봅시다.
1
2
3
4
5
6
7
8
9
10
11
// 게임 프레임 시작 전 Reset하면 됩니다.
Timer::Reset();
while(false == bQuit)
{
Timer::Update();
Game::Update();
Game::Render();
Game::Collide();
}
그리고 이제는 다음과 같이 작성하면 정확한 시간에 따라 플레이어가 오른쪽으로 움직일 수 있게 구현할 수 있습니다.
1
2
// Game::Update()
Player::MoveRight(speed * Timer::DeltaTime());