모바일/HTML5

[HTML5 Game] Game Loop

박종명 2013. 9. 25. 01:30
728x90

모든 마법은 게임루프(Game Loop)에서 일어난다!!!

 

처음 HTML5 Game 개발에 대한 학습을 시작할 때 가장 충격적(?)이었던 것이 바로 게임루프라는 개념이었다. 좀 과장된 표현이긴 하지만, 서버 측 어플리케이션 개발에 대부분의 시간을 보낸 나에게는 꽤나 신선한 느낌을 주었다. 물론 서버 측 어플리케이션에도 무한 반복 실행을 위한 루프 로직이 없는 것은 아니다. TCP 서버에서 입력 소켓을 지속적으로 리스닝 하는 것도 일종의 루프라 할 수 있고 주기적인 폴링을 위한 루프 로직도 심심찮게 구현해왔다. 하지만 초당 프레임 수에 기반한 매우 빠른 속도의 루프와 이벤트 처리, 상태 업데이트, 랜더링 등 거의 모든 로직이 스스로 살아 움직이는 게임 루프상에서 이뤄지는 개념은 적어도 나에게는 입가에 미소를 짓게 만들만큼 신선한 느낌이었다.

 

게임루프는 비단 HTML5 게임개발에만 적용되는 개념이 아니다. 어떤 프로그래밍 환경의 게임이라도 게임루프가 구현되며 큰 맥락에서는 동일한 개념과 로직이라고 할 수 있다.

 

혹자는 게임루프를 게임의 심장박동이라고 표현한다. 심장이 계속 뛰어야 하는 것처럼 게임이 살아있기 위해서는 게임루프가 지속적으로 실행되어야 하며 분당 심박 수처럼 게임 루프도 초당 프레임 수에 기반하므로 꽤 그럴싸한 비유라 하겠다.

 

 

업데이트와 디스플레이

게임 루프에서 모든 마법이 일어나지만 개념을 단순화 시키면 크게 두 가지 마법(?)이 일어난다고 할 수 있다.

바로 업데이트와 디스플레이다. 게임은 실행 중에 캐릭터가 이동하거나 레벨이 업데이트 되거나 하는 여러가지 상태 값의 업데이트가 필요하며 이렇게 업데이트 된 데이터를 기반으로 화면을 갱신해 줘야 한다. 이러한 게임 루프의 로직을 의사코드로 표현하면 다음과 같다.

 

gameLoop(){

update()

display()

}

 

 

FPS

FPS는 Frame Per Second의 약자로 초당 프레임 수를 말한다. 1초 동안 보여주는 화면의 수를 일컫는데 보통 영상을 상영할 때 필름의 프레임이 교체되는 속도 즉 프레임률(frame rate)과 동일한 개념이다. 보통 인간은 초당 15프레임 이상이면 깜빡임 현상을 거의 느끼지 못한다고 하며 25프레임 이상이면 비교적 자연스러운 영상으로 인식한다고 한다. 60프레임이상이면 잔상을 느끼지 못하게 된다.

 

프레임 수가 높을수록 더 부드러운 처리가 가능하지만 과도하게 높은 프레임 수는 게임 실행에 지장을 주게 되므로 성능과 하드웨어 환경 및 게임 상황을 고려해 적절한 프레임 수를 지정할 필요가 있다.

 

1) 고정 프레임 방식

초당 프레임 수를 일정하게 고정시키는 것을 고정 프레임 방식이라 한다. 이 방식은 한 프레임이 수행되는 시간이 아니라 초당 프레임 수행 횟수에 의존하는 방식이며 이 프레임 수행 횟수를 매 초 마다 고정시키는 방식이다.자료에 의하면 고정 프레임 방식은 하드웨어 환경을 미리 파악할 수 있어서, 하나의 프레임에 걸리는 시간을 미리 결정할 수 있는 콘솔 게임들에서 흔히 사용되어 왔다고 한다. HTML5 게임 개발에서 고정 프레임 방식을 적용할 경우 자바스크립트의 setInterval() 함수를 사용할 수 있다.

 

2) 가변 프레임 방식

초당 프레임 수가 일정하지 않고 유동적으로 변하는 것을 가변 프레임 방식이라 한다. 가변 프레임 환경에서 한 프레임의 수행 시간은 그 프레임에서 그려야 할 화면의 디스플레이 시간에 의존적이기 때문에 게임 상황에 따라 달라질 수 있다. 즉 초당 프레임 횟수가 아니라 프레임 수행 시간에 의존적인 방식이다. 따라서 하드웨어의 성능이나 게임 상황에 따라 초당 프레임 수가 달라질 수 있다는 것이다. 대부분의 PC게임이 이 방식으로 구현된다고 한다. HTML5 게임 개발에서 고정 프레임 방식을 적용할 경우 자바스크립트의 setTimeout() 함수를 사용할 수 있다.

 

고정 프레임 방식의 게임 루프를 코드로 표현하면 대략 다음과 같다.

var fps = 10;

setInterval
(gameLoop, 1000/fps);

 

자바스크립트의 setInterval() 함수는, 두 번째 매개변수로 지정된 시간 간격으로 함수를 반복해서 실행한다. 이때 시간 단위는 1/1000초 즉, 밀리세컨드 단위로 지정하게 된다.

 

코드에서는 1000/fps = 1000/10은 1초에 10번 gameLoop() 함수를 실행하라는 의미가 된다. 다시말해 1000/10 = 100 즉, 100ms (0.1초) 마다 함수를 호출하도록 한다.

 

게임 루프 구현

게임 루프와 FPS의 개념을 알아봤으니 이 개념을 기반으로 간단한 게임 루프를 HTML5 기반으로 구현해보자.

여기서 구현해 볼 예제는 게임 루프 상에서 Canvas 영역안에 임의의 색상의 사각형을 랜덤하게 반복적으로 그려주는 예이다.

 

먼저 HTML 파일을 다음과 같이 작성한다.

<!DOCTYPE html>
<html lang="en">
 <head>  
  <script type="text/javascript" src="js/gameLoop.js"></script>
 </head> 
 <body>  
  <canvas id="GameCanvas" width="500" height="400" style="border: 1px solid #000;">
   HTML5 Canvas를 지원하지 않습니다. 크롬 또는 사파리와 같은 HTML5 지원 브라우저를 이용해 주세요
  </canvas>        
 </body>
</html>

 

그리고 다음과 같이 자바스크립트를 작성한다. 게임 루프가 어떤 식으로 구현되는지 자세히 살펴보기 바라며 사각형의 위치와 색상이 랜덤하게 지정되도록 했다.

var fps = 10;
var canvasElement;
var gameContext;
var position = {};

function init(){
   canvasElement = document.getElementById('GameCanvas');
   gameContext = canvasElement.getContext('2d'); 
   setInterval(gameLoop, 1000/fps);
}

 

function gameLoop(){ 
   update();
   display();
}

 

function update(){
   //Set Rectangle Position(Random Positioning In Canvas)
   position.x = Math.floor(Math.random() * (canvasElement.width - 20));  //0~480
   position.y = Math.floor(Math.random() * (canvasElement.height - 20)); //0~380
 
   //Set Random Coloring
   gameContext.fillStyle = 'rgb(' + Math.floor(Math.random() * 255) + ','
                       + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ')';  
}

 

function display(){  
   gameContext.fillRect(position.x, position.y, 20, 20);
}

 

window.addEventListener('load', init, false);

 

 

이제 예제를 브라우저로 실행해보면 다음과 같은 화면을 볼 수 있을 것이다.

fps를 10으로 지정했기 때문에 1초에 10번 사각형이 그려질 것이며 이를 무한 반복하게 되는 것을 확인할 수 있다.