게임 루프는 게임개발의 핵심이다. 이 포스트를 통해서 게임루프에 깊게 이해했으면 하는 바람이다.
게임 루프(Game Loop)란 게임 소프트웨어의 전체적인 흐름을 컨트롤하는 것을 말한다. 그럼 단순하게 루프라고 부르는 것이 아니라, 왜 게임 루프라는 용어를 사용할까? 게임 루프는 사실상 다른 프로그램과 다르게 게임프로그램의 특징을 보여주는 프로그래밍 패턴이기 때문이다. 게임 루프를 사용하지않는 프로그램은 사실상 없다고 해도 무방하다.
예전의 프로그래밍 방식과 비교를 한 번 해보자. 예전 프로그래밍은 하나로 묶어 입력한다. 그 다음 한번에 과정을 거쳐 또 한 번 만에 출력하는 과정을 거쳤다. ( 각각 input, processing, output 이라고 할 수 있다.) 예를들어 전자레인지에 음식을 다때려넣은 다음,(입력) 타이머를 돌려 작동시키고,(과정) 조리된 음식을 꺼내기만 하면됐다(출력). 즉 일이 얼추 임무만 마치면 프로세스는 멈춘다는 뜻이다.이런방식을 Batch Mode 프로그램이라고 한다.
그럼 이와달리 게임에서 프로그램 작동 방식은 어떠한가? 당연히 이렇게 Batch Mode로 간단하게 돌아가진 않을 것 같은 게 직관적으로 느껴진다. 모든 게임은 사용자의 입력 다음으로 게임 상태의 업데이트 ,유저 인터페이스 처리, 음향 효과 재생 등으로 구성이 된다. 밑의 그림 처럼 표현할 수 있는데, 이러한 한 과정을 시퀀스라고 부른다.
근데 게임개발을 처음 접할 때,고전적인 게임만을 주로 본다면 업데이트과정이 굳이 없어도 게임구현에 별 문제가 없다고 생각 할 수 있다.(고전게임 조차도 게임루프를 활용한 업데이트과정은 거의 필수로 들어간다.) 게임루프에서 고려할 것이 사용자의 입력(콘솔게임을 예로 들자면 여러가지 컨트롤 조작)만을 의미한다고 여길 수 있기 때문이다. 하지만 게임은 사용자의 입력자체가 게임에 미치는 모든 요소가 업데이트 되어야 게임상에서 또 표시가 되고 다음 유저의 행동에 적용이 될 수 있다.
▼(참고)위 시퀀스에서 가운데 부분인 업데이트만 따로 떨어트려서 본다면 밑의그림처럼 나오는데, 사실 요즘게임은 이것보다 훨씬 더 복잡한 게임이 많다.
대략적으로 게임이 어떻게 돌아가는지 봤으니,업데이트 요소에 집중할 게 아니라 게임 루프가 어떻게 돌아가는지 를 제대로 보자. 게임 루프의 이해를 위해 시퀀스를 크게 분할하여 사용자 입력(input) - 업데이트(Update) - 표시(Redner)라고 부른다. 예를들어 최고로 아주아주 간단한 게임을 만드는 경우에는 다음과같은 코드를 작성할 수 있다.
-게임루프 코드예시-
While(true)
{
업데이트();
렌더();
}
이렇게 간단하게 만들면, 코드에서 보이는 것 처럼, 이 게임루프는 시간을 어떻게 분할하거나 관리할 건지 전혀 고려하지 않고 게임이 실행되게 된다.이렇게 되면 게임속도는 전적으로 하드웨어 속도에 의존하게 된다. 이 경우는 특히 타이밍이 중요한 게임 에서 큰 문제가 있을 수 있다. 타이밍 게임인데 타이밍 맞추는게 프로그램의 무성의함(?) 때문에 불편하다면? 바로 게임이 나락으로 가버리는 지름길이다. 사실 타이밍이 상대적으로 중요하지 않더라도 왠만한 게임에서 타이밍이 안맞는 다는 건 아주 큰 리스크를 감수하는 일이다. 다시말해서 느린하드웨어가 타이밍을 감당할 수 없다면 차라리 프레임을 건너 뛰는게 나을 수 있다..
근데 여기서 게임루프를 큰 그림으로서 이해하기 위한 매우 중요한 개념이 나온다. 이러한 코드의 반복, 즉 이 루프는 프레임(Frame)이라고 불린다는 것이다. 프레임이라고 하니 루프랑 프레임이랑 무슨상관인가 싶겠을 것이다.
일단 여기서 프레임은 이는 우리가 흔히 아는 프레임률,FPS(Frames Per Second)에 나오는 Frame이 맞다. 즉 Frame이란 예시코드 #1에서 나온코드에 Update와 Render가 1초에 몇회 호출되었는지를 표현하는 수치이다.
그럼 여기서 주어진 조건으로 유추해보면서 FPS랑 게임루프랑 어떤 상관관계가 있는지 알아보자. FPS는 30 혹은 60 으로 보통 업계표준이라는 명목으로 자주 사용된다. 여기서 의문점을 “FPS는 무조건 높은 수치 일 수록 실사화 되는거라 좋은 거 아닌가 왜 더 안올리지?” 라는 생각으로 출발하자.
먼저 FPS가 높은데 하드웨어가 성능이 느린경우를 먼저 살펴보자. 대략적으로 30FPS가 적당한 하드웨어라고 가정한다. 일단 더 시각적으로 호소력이 있는 게임을 만들기 위해서 60FPS로 올렸다고 가정한다. 그럼 상대적으로 느린하드웨어는 60FPS가 너무나 버겁기 시작한다. 초당 60을 계산해야되는데 50,40,30…이렇게 느려지다보면 게임은 점점 더 느려지게 되고 캐릭터가 절뚝거리기 시작한다.정상적으로 출력된 프레임과 비정상출력이 혼재되는데, 이것이 흔히 말하는 테어링이 발생하는 원인이 된다. 유저들은 보통 렉 이라고 표현하지만 정확히는 틀린표현이다.
이러한
반대로 FPS가 60인데 하드웨어가 좋은 경우를 한 번 보자. 의문에 대한 나름의 해답으로 60FPS 게임을 만들었다고 가정하는 것이다. 내가 아주 아주 좋은 하드웨어를 장착한 하드웨어를 가지고 있다고 한다면 전혀 문제가없다. 60FPS를 문제없이 가동하는 컴퓨터에서 포카드나 핀볼게임이나 하진 않을테니까. 하지만 일단 전의 상황처럼 느린하드웨어는 플레이 하기 어려운 게임일 뿐더러, 하드웨어 입장에서는 포카드나 핀볼게임을 플레이 하는것처럼 하드웨어 자원낭비라고 표현 한다.
따라서,“FPS는 무조건 높은 수치 일 수록 실사화 되는거라 좋은 거 아닌가 왜 더 안올리지?”라는 질문의 답변은 한 문장으로 요약할 수 있다. 첫번째로 조금 문장이 길지만,"업계표준을 정함으로서 실사화를 위한 노력과,느린하드웨어에서도 사용자가 불편없이 게임을 구동할 수 있도록 하는 범용성의 타협점" 이라고 볼 수 있다.
여담이지만 사실 이런 FPS로 인한 타협점을 찾는 노력(사실상 분쟁같기도 하다.)은 게임뿐 아니라 그래픽이 들어가는 영화,애니메이션등에서 많이 볼 수 있다. 48~60 fps로 개발돼던 게임이나 영상이 2016년도에 최초로 120프레임으로 촬영하기도 하고 이러한 FPS의 업계표준은 하드웨어의 발전에 따라 올라갈 여지가 있다. 다만 FPS가 높아지지 않는 원인을 먼저 하드웨어를 꼽았지만, 고려해야 할 요소가 매우 많은 편이라 간단한 문제로 보이지는 않는다. 게다가, FPS만을 올려서 실사화 한다고 되는게 아니라 모션블러(:동작선에 따른 화면왜곡 효과) 로 실제로 보는 것 처럼 자연스럽게 하는 기술 및 광량에 대한 고려 같은 것도 실사화에 큰 영향을 미치기에, 꼭 FPS가 절대적인 실사화의 기준이라고 보기도 어렵다.
의외로 게임루프와 깊게 연관된 이론으로 멀티스레드가 있다. 멀티코어 CPU나, 멀티스레드 기법이 보편화 되면서 게임에서도 이러한 환경에서 최적의 성능을 내기위해 게임루프는 이러한 환경을 최대한 활용하는 쪽으로 설계된다. 물론 이런 메소드를 설명하려는 건 아니지만, 멀티스레드는 게임루프 설계에 있어서 아주 중요한 역할을 하고 있다.(당연히 게임루프 뿐만은 아니다.)
처리하는 시간을 예시로 멀티스레드가 활용되는 것을 이해해보자. 트리플 A 게임(대량의 자본을 들여서 수백만 판매량을 기본으로 하는게임을 말한다. 영화의 블록버스터나 베스트셀러 느낌으로 받아들여도 좋다.)에서는 그래픽적으로 CPU,GPU가 계산할 양이 만만치가 않다. 이때 30 밀리초(0.030초)당 한 프레임을 만들고 20 밀리초(0.020초) 동안 업데이트를 한다고하면 50밀리초(0.050초)가 걸릴것이다. 근데 멀티스레드로 직렬,순차적 수행이 아닌 평행적으로 수행한다면 30 밀리초면 된다.
이렇게 하기위해서 게임루프는 모든 입출력 및 업데이트를 처리하도록 다시 설계할 수 있는데 이렇게 처리가 되면 바로 다음 루프를 처리하기 위한 2차 데이터를 넘겨주게 된다. 이러한 데이터를 토대로 다음 그래픽을 표현한다.
즉 이런 일련의 과정을 멀티스레드를 활용함으로써 하드웨어 자원을 적극활용한다. 메인스레드는 렌더링을 수행하는 스레드가 그래픽을 모니터에 나타내고 있을때 단순히 쉬고있는게 아니다. 렌더링을 한프레임 메인 프레임보다 늦춰서 렌더가 되는중에도 메인스레드를 계속 동작시켜 더욱더 효율적인 하드웨어 자원을 활용하게 된다.
근데 이렇게 프로세스 자원을 최대로 활용하기위해 게임루프 설계상, 한프레임 늦추는게 큰 단점이 되기도 하는데, 입력에 대한 지연을 발생 (렉) 시키기 때문이다. 위 그림을 보면 조금 더 이해하기 쉬운데, 메인스레드가 2를 처리하고 있는 도중에 입력이 들어오면 일단 처리 도중이기에 렌더에도 2는 표현이 되지않는다. 그럼 2가 표현 되고나서 3작업에 착수할때 처리과정에 들어가게 되는데 이는 비로소 3번째 프레임에 나오게된다. 사용자 입장에서는 1에서 눌렀던 동작이 3에 나오는 것이다. 사실 철권같이 타이밍이 중요한 게임에서는 이러한 단점이 받아들여지기는 쉽지않다. 하지만 다른 장르의 게임에서는 그렇게 까지 지연이 큰 문제가 되지 않는다고 판단한다.
사실 이러한 지연 현상은 대부분의 LCD 패널이 가지고 있다. 그래서 타이밍에 민감한 프로게이머 선수들은 이 점 때문에 일부러 브라운관 TV나 CRT 모니터(뚱뚱한 모니터)로 플레이하려고 고집하기도 했다.
The attention to detail and meticulous craftsmanship evident in your work is astounding, as every aspect of the experience has been thoughtfully designed to Drift Boss provide a seamless and enchanting journey.