C언어를 배우고 컴퓨터 그래픽스 및 다이렉트X와 같은 것들을 공부했지만, 여전히 C언어를 이용해 게임을 만들지 못하고 있었다. 그 이유는 내가 원하는 게임을 혼자서 만들기가 너무 어렵기 때문이었다.
“더는 혼자 그림도 그리고 음악도 만들고 프로그래밍까지 할 순 없어!”
그림을 아주 못 그리는 수준은 아니었고 음악적인 재능이 아예 없던 것도 아니었지만, 그나마 가장 잘하는 게 프로그래밍이었으니 그냥 프로그래밍만 해야겠다는 생각이 들었다. 그렇게 고등학교 시절을 마무리하나 싶었다. 그런데 우연한 계기로 취직의 기회가 왔다.
어느 개인 사업가였는데 게임을 개발하고 싶다고 했다. 내가 고3인데도 불구하고 월급을 주고 게임을 개발하자고 했다. 당연히 묻지도, 따지지도 않고 일하겠다고 했다. 사장님이 만들고 싶은 게임은 <코만도스>와 같은 온라인 밀리터리 게임이었다. 취직하자마자 확고한 목표가 생겼다.
“게임을 만들자!”
첫 상업용 게임(내가 2,000 원이나 번 게임이 첫 번째 상용 게임이긴 하지만….)을 만들 기회가 생긴 것이다. 그리고 이 프로젝트는 C언어를 사용할 것이었다. 지금까지 열심히 공부한 것을 드디어 써먹을 수 있게 되었다. 게다가 월급까지!
3D 게임이 아니었기 때문에 당시에 DirectDraw를 이용해서 게임 엔진을 만들어야 했다. 하지만 처음부터 내가 모든 걸 만들기가 사실 상당히 버거웠다. 우연히 인터넷에 2D DirectDraw 라이브러리가 공개돼 있었고 이것을 이용해 게임 엔진의 기반을 갖추게 되었다.
이때 상당히 도움이 많이 되었던 서적이 있었는데 바로 이 책이다.
<실시간 전략 게임 프로그래밍>
이 책의 저자는 <에이지 오브 엠파이어> 개발자였고 당시에 보기 드물게 실제 게임 개발자가 쓴 게임 프로그래밍 책이었다. 공개된 2D 엔진과 이 책을 공부하면서 새롭게 만든 기능들을 추가하고 GUI 시스템을 구축했다. 그렇게 해서 2.5D 배경에 캐릭터가 돌아다니는 데모를 만들 수 있었다. 그 당시에 특히 버튼을 만들 때 고민했던 것이 있었는데 바로 버튼 위에서 마우스 버튼을 누르자마자 로직이 동작할 것인가, 마우스 버튼을 눌렀다가 뗐을 때 로직을 동작시킬 것인가였다.
윈도우 UI나 <스타크래프트>를 보면 버튼을 눌렀다가 뗐을 때 동작한다. 만일 버튼을 누른 채로 버튼이 아닌 위치에 마우스를 움직인 후에 손을 떼면 버튼은 동작하지 않는다. 이런 모든 내용을 코드로 작성해 줘야 프로그램이 정상적으로 동작한다.
※ 노트: 현재 나와 있는 모든 게임의 버튼 테스트를 해보는 것도 재밌을 것이다. 실제로 누르자마자 동작하는 게임들도 있고 눌렀다가 뗐을 때 동작하는 게임도 있다. 또는 버튼이 아닌 위치에서 마우스 버튼을 누른 채 버튼 위로 마우스를 움직인 후 뗐을 때 동작하는 게임들도 있다. 이 모든 것들을 제대로 처리하려면 코드를 작성할 때 많은 노력이 필요하다.
|
두 달 정도를 열심히 밤을 새우며 게임 월드, 충돌 처리, 캐릭터 애니메이션, UI 시스템을 만들었는데 사장이 사업을 접겠다고 했다. 자금 사정 때문에 잠시 회사를 관둬야 한다는 것이다. 좀 안타까웠지만, 시작도 해보기 전에 그렇게 첫 회사는 문을 닫았다.
회사는 문을 닫았지만 확고한 목적의식을 갖고 실전 문제들을 해결하다 보니까 더 많은 것들을 배울 수 있었다. 책만 읽고 배울 수 있는 내용과는 차원이 달랐다.
“백견이 불여일행이라….”
회사를 그만둔 후에 내가 부족한 점이 무엇인지 더 확실하게 알 수 있었다. 그래서 더 악착같이 책들을 읽게 되었다. 자료구조, 수학, API 사용법 등등….
특히 충돌 처리를 위해 다각형 안에 점이 있는지 없는지 판단하는 로직을 작성해야 했는데 이를 위해서 벡터(Vector)를 사용해야 했다. 벡터란 크기와 방향을 갖고 화살표로 표기하는데, 이 벡터를 이용하면 다각형 안에 점이 있는지 없는지 판단이 가능했다.
※ 노트: 벡터란? //ko.wikipedia.org/wiki/%EB%B2%A1%ED%84%B0 를 참고하자.
|
4개의 벡터와 1개의 빨간 점.
예를 들어 캐릭터가 빨간색 점이고 4개의 벡터로 이루어진 암석이 있다고 치자. 캐릭터는 다른 곳은 모두 움직일 수 있지만 암석 안에는 들어갈 수가 없다. 즉, 우리는 빨간색 점이 다각형 바깥에 있으면 움직임이 유효하고 빨간색 점이 다각형 안에 있으면 충돌했다고 하고 그 움직임을 무효화해야 한다.(그렇지 않으면 개발자가 의도하지 않은 지형 안으로 뚫고 들어가서 영원히 나오지 못하는 버그를 경험하게 될 수도 있다.)
우리는 이걸 눈으로 보고 바로 알 수 있지만, 컴퓨터는 사실 멍청하다. 이 모든 사실을 숫자로 말해주어야 한다. 여기서 벡터의 내적(Dot Product)이 유용하게 사용된다.
우리가 작업할 게임은 2차원이라고 생각하고 위치를 표현하기 위해서 x, y라는 좌표를 사용해 보자. 그리고 위 그림에 있는 빨간색 점의 위치를 px, py라고 하자. 그리고 각각의 벡터에 수직으로 향하는 노말(Normal) 벡터를 그린다.
파란색 노말 벡터는 4개의 벡터로부터 수직이다.
수직이 아닌 것처럼 보인다면 착각이다. 아무튼, 이 4개의 수직 벡터를 이용해서 빨간색 점이 다각형 안에 있는지 없는지 검사할 수 있다. 벡터의 내적은 다음과 같은 계산이다.
u ● v = (u1, u2, …, un) * (v1, v2, …, vn) = u1v1 + u2v2 + … + unvn
현재는 2차원이니까 u벡터의 요소는 (ux, uy)이고 v벡터의 요소는 (vx, vy)이다. 이 각각의 요소들을 각각 곱하고, 그것들의 총합이 벡터의 내적이다. 이건 곱하기와 더하기만 할 수 있으면 누구나 할 수 있다!
여기서 v를 빨간색 점이라고 생각하면 vx, vy는 각각 px, py다. 앞서 말했지만 px, py는 빨간색 점의 x, y 좌표의 위치 값이다.
벡터의 내적에는 특징이 있는데 u, v가 단위 벡터(벡터의 길이가 1이다.)일 때 내적의 결과는 두 벡터 사이의 각도라는 것이다.
이것은 다음과 같이 표현한다.
u ● v = ||u|| ||v|| cosθ
여기서 u, v를 || ||로 감싸고 있는데 이것은 u, v의 길이를 뜻한다.
각도를 얻기 위해서는
θ = cos^(-1) (u ⋅ v)/(||u|| ||v||)
그리고 이 내적 값의 크기에 따라서 더 재밌는 사실을 알 수 있다.
뒤쪽, 수직, 앞쪽.
여기서 u가 다각형에 있던 각각의 벡터의 수직 벡터라고 생각해 보자. 그리고 v가 플레이어의 위치라고 생각해보면 내적의 결과가 0이거나 0보다 클 때만 u 벡터의 앞쪽에 있다고 볼 수 있다. 내적의 결과가 0보다 작다면(음수라면) u의 뒤쪽에 있다고 볼 수 있다. 즉, 다각형의 안쪽 혹은 바깥쪽을 구분할 수 있다는 말이다.
빨간 선, 하늘색 선으로 두개의 벡터만 비교.
빨간색 선과 수직 벡터의 내적은 0보다 작으므로 해당 벡터의 뒤쪽에 있다고 볼 수 있다. 실제로 뒤쪽에 있다. 그리고 하늘색 선의 경우 수직 벡터와 내적 값이 0보다 크므로 벡터의 앞쪽에 있다고 볼 수 있다. 4개의 벡터로 이루어진 다각형에 플레이어와 내적을 각각 구해 보면 모든 내적 값이 0보다 작을 때 플레이어가 다각형 내부에 있다는 것을 알 수 있다.
벡터 라인 4개를 각각 line1, line2, line3, line4라고 하고 플레이어를 p라고 할 때,
// 플레이어가 다각형 내부에 있다.
if ( line1 ● p < 0 && line2 ● p < 0 && line3 ● p && line4 ● p < 0 )
{
// 그러므로 충돌을 알린다.
}
이 코드는 단순히 다각형이 4개의 벡터로 이루어졌을 때만 동작한다. 그리고 생각해 보면 게임에는 이러한 다각형이 엄청나게 많이 존재한다. 상상할 수 없겠지만, 우리가 게임을 할 때 1/30 혹은 1/60초당 충돌이 가능한 객체들(플레이어, 총알 등등)이 이러한 계산을 수행한다. 실로 어마어마한 것이다.
예를 들어 삼각형 하나에 3개의 벡터가 있다. 이것을 보통 1폴리곤이라고 한다. 이러한 삼각형이 게임 월드에는 몇 백만 개 이상이 있고, 이 폴리곤마다 충돌 처리할 객체와 위와 같은 계산을 하고 충돌 처리를 한다.
물론 모든 삼각형과 다 계산하지 않는다는 게 속도 향상을 위한 팁 중의 하나고, 더 자세한 내용은 다른 서적을 참고하는 게 좋을 것이다.
※ 참고서적: 충돌 처리는 이 책 하나면 충분할 정도로 괜찮은 책이다. 클라이언트 개발자라면 소장해야 할 책 중에 하나. //www.amazon.com/exec/obidos/tg/detail/-/1558607323?tag=realtimecolli-20
|
※ 참고서적: ‘리얼 타임 렌더링’이라는 책을 추천한다. 렌더링 속도 향상에 관한 내용들이 있으며 렌더링 분야에서는 필독 서적이다. 이 책은 번역서도 있다!
|
실무 프로젝트를 하게 되면서 확고한 목표 의식, 도망칠 곳이 없다는 것이 나에게 더 많은 도움이 되었다. 그리고 부족한 점을 꾸준히 책을 읽거나 사이드 프로젝트, 책을 쓰면서 더 공부하게 되었다. 그렇게 계속 하다 보니까 내 경력에 비해 다른 경력자들보다 이론적인 것을 더 많이 알게 되었다.
하지만 이론은 이론일뿐 실무에 적용하는 것은 별개였다. 그래서 책으로 배운 내용을 실제로 돌아가는 데모를 만들려고 노력하고 실무 프로젝트에 적용 가능한 것들은 최대한 적용해 보려고 시도했다.
그렇게 첫 회사는 문을 닫았지만 나는 배운 것이 많았다. 공부가 더 필요했으며 책으로 배우는 것은 또 실제로 해보는 것과 다르다는 것을 말이다.