[HTML5 Game]Calculating FPS
게임 루프(http://m.mkexdev.net/242)를 다루는 글에서 초당 프레임 수인 FPS의 개념과 샘플을 작성해 보았다. 이번 글에서는 실제 초당 얼마의 프레임률을 보이는지 파악할 수 있는 초당 프레임 수 계산기를 작성해 보자.
초당 프레임 수는 게임 실행환경이나 가변적인 연산처리 등으로 일정하지 않거나, 목표한 프레임 률(framerate) 보장하지 못하는 등의 문제가 발생하기 때문에 게임 개발과 디버깅 시 관심있게 살펴봐야 하는 데이터이다.
특히 가변 프레임 방식이라면 초당 몇 프레임이 나오는지에 대한 실제적 자료가 필요하며 고정 프레임 방식일지라도 항상 고정값을 보장하지 않는 환경이 될 수도 있으니 실제 프레임 수를 살펴보는 것이 여전히 도움이 된다.
또한 만들고자 하는 게임이, 초당 몇 프레임에서 가장 원활한 동작을 보이는 지를 확인할 때도 유용하다 하겠다.
아래 사이트는 tree.js의 3D 샘플인데, 이 샘플에서도 좌측 상단에 초당 프레임 수를 보여주고 있다.
http://threejs.org/examples/ (이 사이트의 예제는 날 감탄스럽게 만들어 버렸다)
초당 프레임 수 계산 방식
초당 프레임수를 계산하기 위해서는 크게 두 가지 접근방식을 취할 수 있다.
먼저 밀리세컨드 단위의 이전 프레임의 실행 시간과 현재 프레임의 실행 시간을 비교해서 그 간격을 보고 프레임 수를 역으로 계산하는 방식과 실제 프레임 실행시마다 카운팅하는 방식이 그것이다. 두 방식 모두 큰 의미에서는 동일하다 할 수 있으나, 두 번째 방식이 좀 더 직관적이고 명료한 듯 하여 이 글에서도 두번째 방식으로 샘플을 작성해 볼 것이다.
예제가 복잡하지 않으니 바로 작성해 보자. 더 이상 HTML 파일은 언급하지 않겠다.(너무 심플하뉘...)
다음과 같이 초당 프레임 수를 계산하기 위한 객체 기반을 작성한다. 코드의 핵심은 현재 시간과 직전 시간을 (밀리세컨드 단위로) 비교하여 1000 즉, 1초가 지났을 경우 계속 증가시켜오던 callCount 값을 framePerSecond에 대입하는 부분이다. 참고로 자바스크립트의 Date.now()는 1970년 1월 1일 자정으로부터 현재 시간 사이의 밀리초를 반환하는 함수인데 new Date().getTime()으로도 동일한 결과를 받을 수 있으나 검색한 자료에 의하면 성능상 Date.now()가 더 좋은 효율을 보인다고 한다.
this.callCount = 0;
this.framePerSecond = 0;
this.beforeTime = 0;
this.countFps = function(){
//(Date.now() is returns the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC)
var nowTime = Date.now(); //1970년 1월 1일 자정과 현재 날짜 및 시간 사이의 밀리초 값입니다
//If one second has passed
if(nowTime - this.beforeTime >= 1000){
this.framePerSecond = this.callCount;
this.beforeTime = nowTime;
this.callCount = 0;
}
//Increase frame count per second
this.callCount++;
}
}
이어지는 코드는 앞서 생성한 FrameCounter 인스턴스를 생성해서 게임루프마다 fps를 증가시키기 위해
countFps 함수를 호출하는 것이다. 초당 프레임 수는 좌측 상단에 표시하며 전체 누적 프레임 수는 중앙에 표시하도록 한다.
var canvasElement;
var gameContext;
var totalFrameCount = 0;
var frameCounter;
function init(){
canvasElement = document.getElementById('GameCanvas');
gameContext = canvasElement.getContext('2d');
frameCounter = new FrameCounter();
setInterval(gameLoop, 1000/fps);
}
function gameLoop(){
update();
display();
}
function update(){
frameCounter.countFps(); //Call countFps function
++totalFrameCount; //Increase total frame count
}
function display(){
gameContext.clearRect(0, 0, canvasElement.width, canvasElement.height);
gameContext.textBaseline = 'top';
gameContext.font = '10pt Arial';
gameContext.fillText(frameCounter.framePerSecond + '/second' ,5, 5);
gameContext.font = '18pt Arial';
gameContext.fillText(totalFrameCount ,130, 80);
}
window.addEventListener('load', init, false);
브라우저로 실행하면 가운데 누적 프레임 수와 좌측 상단의 초당 프레임 수를 확인할 수 있다