프로그래밍 언어 입문서가 아닌 프로그래밍 기초 개념 입문서
문과생, 비전공자를 위한 프로그래밍 입문책입니다.
jobGuid 꽃미남 프로그래머 "Pope Kim"님의 이론이나 수학에 치우치지 않고 실무에 곧바로 쓸 수 있는 실용적인 셰이더 프로그래밍 입문서 #겁나친절 jobGuid "1판의내용"에 "새로바뀐북미게임업계분위기"와 "비자관련정보", "1판을 기반으로 북미취업에 성공하신 분들의 생생한 경험담"을 담았습니다.
Posted by 디퍼드H

안녕하세요. 이번에 새로 3일자와 18일에 연재글을 맞게된 디퍼드H입니다.

간단한 제 소개를 해드린다면 현재 디지펜-계명대 복수학위 이수하면서 현재 미국에서 공부하고 졸업을 앞둔 학생입니다. 학교 커리큘럼에 맞추어 GAM프로젝트 (GAM100, GAM150(텍스트 게임), GAM200, GAM250(1년 2D 게임 프로젝트), GAM300, GAM350(1년 3D 프로젝트)) 겪었던 여러경험들을 여러분들과 공유해보고자 합니다.

이번에 제가 연재할 첫번째 내용은 '자기만의 게임엔진을 만들어보기' 입니다. 사실 여러분들 중 게임 프로그래머를 지망하는 학생분들도 많을거라고 생각됩니다. 전문적인 내용 예로 들어 저같은경우 그래픽(렌더링) 프로그래밍 지망생으로 디퍼드 셰이딩이라던가 여러 전문적인 렌더링 테크닉을 다루기 보다는 우선 게임을 쉽게 만들수 있도록 도와줄 연재글을 작성해보려고 합니다. (이부분에 대해서는 포프님이나 다른분들께서 다루어주실거라고 믿어 의심치 않습니다.)

'자기만의 게임엔진을 만들기부분에서 연재글이 몇화나 될지는 잘 모르겠지만 빨리빨리 넘어가기 보다는 프로그래밍을 막 시작하는 분들을 위한 초점으로 천천히 진행해보고자 합니다. 허나 혹시 여러분들중에서 C/C++에 대해서 전혀 모르신다면 미리 공부하고 저의 글을 보시는게 도움이 되실거라고 생각합니다. 저는 여러분들이 이미 C/C++언어에 대해서 잘아신다는 전제하에 진행하도록 하겠습니다.

자, 그럼 이제 오늘의 강의를 시작하도록하죠. 보통 게임엔진하면 대표적으로 언리얼 엔진, 크라이 엔진, 하복 엔진, 떠오르는 유니티 엔진등이 있습니다. '우와, 이런 게임엔진을 어떻게 만들어?' 물론 우리가 만들어나갈 게임 엔진은 이런 상용엔진은 아닙니다. 허나, 우리만의 게임엔진을 만들어 나가면서, 여러분들의 게임 프로그래밍에 대한 지식을 한층 더 높여줄거라고 확신합니다. 사실 프로그래밍 실력을 확실하고 빠르게 늘릴 수 있는 방법은 직접 프로그래밍을 많이 해보는 길입니다. 여러분들이 새로운 기술 또는 테크닉을 익혔을 경우 여러분들이 만든 엔진에서 구현을 해본다면 크게 도움이 될 것입니다. 

자자, 여러분들만의 게임 엔진 구현의 장점 나열은 여기까지하고 이제 여러분이 만드실 게임엔진에 대해 전체적 구조를 알아보도록 하죠. 아래의 그림을 보도록 합시다. 우리가 만들어갈 게임 엔진을 기본구조를 잘 표현하고 있는 그림입니다.

우선 그림 보면 CoreEngine 클래스가 보입니다. 이 클래스 우리가 만들 게임엔진에 핵심이 될 부분입니다. 이 클래스는 시스템과 관련된 메소드와 게임 루프 함수를 들고 있습니다. 게임 루프 함수는 게임 엔진에서 메인 심장이라고 보면되는데, 게임 루프는 CoreEngine 클래스에 속해있는 시스템들은 주기적으로 업데이트 시켜주는 메소드라고 생각하시면 됩니다. 자세한 내용은 후일 CoreEngine을 다룰때 알아보도록 합시다. CoreEngine 클래스 안에는 여러 시스템을 가지고 있는 컨테이너를 가지고 있는데, 그럼 시스템에는 무엇이 있겠는가 살펴보죠.

그림에서 보면 가장 처음으로 윈도우 시스템이 보입니다. 우선 윈도우 시스템에 대해서 간단히 설명하자면 윈도우 운영체제와 관련된 윈도우 창 만들기, 윈도우 메세지 제어등을 관리할 시스템이라고 생각하면 됩니다.

그 다음 시스템은 그래픽 시스템을 보도록 하죠. 그림을 보면, 어~! 그래픽 시스템에서는 뭔가 화살표 방향으로 Transform, Model, 또 Light로 연결이 되어있네요? 막 복잡하고 그렇게 보이지만, 간단히 말하자면 그냥 컴포넌트 클래스 입니다. 여기서 컴포넌트 클래스가 무엇인가 궁금해 하는 분들이 있을거라고 생각합니다. 잠깐 여기서 간단히 살펴보고 가봅시다. 아래의 그림을 봅시다.

그림에서 보면 GameObject 클래스가 있습니다. 이 게임 오브젝트 클래스는 우리가 흔히 게임상에서 말하는 적, 플레이어, 나무, 장애물, 추상적으로는 빛까지 이르는 오브젝트라고 말할 수 있습니다. 게임 오브젝트는 컴포넌트 컨테이너를 가지고 있는데, IComponent 클래스에서 상속받는 컴포넌트들로 구성이 되어있습니다. 사실 이 컴포넌트를 가장 쉽게 설명한다면 오브젝트들이 가지고 있는 유니크한 특징들을 객체 또는 클래스를 표현 했다고 생각한다는 것이 쉬울것 같습니다. 예로 들어 빛을 게임 오브젝트로 표현하고 싶다라고 한다면, 게임 오브젝트 클래스에 Light라는 컴포넌트를 가지고 있으면 빛 오브젝트를 정의할 수 있습니다. 한가지 더 해보도록 하죠. 만약 캐릭터 오브젝트를 표현하고 싶다라고 한다면, Transform과 Model 컴포넌트를 가지고 있다면 캐릭터 오브젝트를 만들 수 있죠. 이렇듯, 컴포넌트 구성요소에 의해 우리는 게임 오브젝트 종류를 설정할 수 있습니다. 여러 게임 오브젝트를 추가시킬때 우린 굳이 클래스를 따로 정의 할 필요가 없게 되는거죠. 이외 컴포넌트를 이용한 게임 오브젝트를 만들면서 또다른 여러가지 이점이 있지만 예로 들어 Data-Driven 구조로 Multi-threading 구현이 쉬워진다라는 등, 이외의 이점은 다음에 우리가 오브젝트와 컴포넌트를 실제로 구현할때 더 자세히 다루어 보도록 하겠습니다.

자, 다시 그래픽 시스템으로 돌아와서, 그래픽에서는 Light, Transform, 그리고 Model 컴포넌트가 연결되어 있습니다. 이게 무슨뜻일까요? 컴포넌트 기반의 게임엔진에서는 각 시스템에서 특정 컴포넌트들의 업데이트 담당하게 됩니다. 예로 들어 Transform 컴포넌트는 게임 오브젝트의 위치를 나타냅니다. 이 위치는 주로 그래픽 시스템에서 랜더링할때 담당하기때문에 그래픽에서 담당하게 됩니다. 빛 컴포넌트도 마찬가지입니다. 이 빛 컴포넌트는 빛 오브젝트에 속해질 컴포넌트로 오직 그래픽에서 랜더링할때 사용될거기 때문에 그래픽 시스템에 속해 질것입니다. 모델 컴포넌트로 마찬가지입니다. 정리해보면, 시스템들은 보통 1가지 이상의 컴포넌트 업데이트를 담당하게 됩니다. 또 다른 예를 들게 되면 여러분들이 쉽게 이해 되실겁니다. 자, RigidBody 컴포넌트가 있다고 가정합시다. 여러분들 중에 물리 엔진을 한번이라도 만져 보셨거나 직접 만들어 보신 분이라면 이 컴포넌트는 물리에 관련이 있다는 것을 바로 직감하셨을 겁니다. 그렇습니다 그럼 이 컴포넌트는 물리 시스템에서 관리를 하게 될것입니다. 이제 감이 오시나요? 혹시 난 아직 이해가 안된다 하시는 분들이 있다면 걱정마세요. 지금은 '아 이런게 있구나.' 라는 정도만 알아도 충분합니다. 또 자세히 돌아볼 기회가 있으니깐요.

지금까지 좀 많은걸 배운것 같은데 잠시 정리하고 지나가 봅시다.

- CoreEngine이란?

- 게임 루프 ; 게임의 심장

- 시스템들을 초기화와 관리한다.

- 컴포넌트란?

- 게임 오브젝트의 특징을 클래스 또는 객체화한 것이다.

- 컴포넌트가 모여 하나의 게임 오브젝트를 구성하게 된다.

- 각 시스템들은 하나 이상의 컴포넌트를 관리하게 된다.

- Data-Driven ; Multi-threading 구현

마지막으로 살펴볼 내용은 메세지 시스템입니다. 메세지 시스템이 왜 필요할까요? 윈도우 API에 있는 메세지 시스템으로 도 충분하지 않을까? 물론, 충분하지만, 커스텀 메세지 시스템 도입은 여러가지 이점들을 주는데 우선 대표적으로 클래스 사이 포인터 참조 사용을 줄이므로써 클래스 간의 엉킴이 적어집니다. 사실 포인터 참조는 너무 많은 곳에서 쓰이게 된다면 클래스가 서로서로 거미줄처럼 엉키게 됩니다. 이럴경우 나중에 새로운 함수 또는 리팩토링할때 너무 고쳐야할 부분이 많아지게 됩니다. 우선 아래의 그림을 보면 무슨 내용인가 쉽게 이해 될것이라고 생각합니다.

첫번째 그림은 만약 우리가 메세지 시스템을 사용하지 않는다는 것을 가정했을때의 모습을 그림으로 그려보았습니다. 메세지 시스템을 사용하지 않는다면, 서로 다른 메소드를 가져올때 하는 수 없이 포인터 참조를 할 수 밖에 없어집니다. 그러면 첫번째 그림과 같이 시스템들은 서로 서로 거미줄처럼 엮어질 것입니다. 물론, 디자인 패턴중 퍼사드 패턴을 이용하게 된다면, 클래스 간의 의존성을 상당히 줄일 수 있긴 합니다. 두번째 그림에서는 우리가 만약 메세지 시스템을 사용했을때의 모습입니다. 만약 입력시스템(InputSystem)에서 어떤 키가 입력 되었다고 가정합시다. 입력시스템에서는 키가 입력되었다는 사실을 우선 메세지 시스템에 보내게 됩니다. 메세지 시스템에서는 그 메세지를 큐에 저장을 해놨다가 한 프레임 지나고 메세지 큐에 있는 메세지를 딜레이 시간을 비교하여 메세지를 알맞은 발신자에게로 보내게 됩니다. 첫번째 그림과 두번째 그림을 비교해보면, 여러분들은 메세지 시스템을 사용한 부분이 훨씬 상호 의존성이 적다고 알 수 있을것입니다. 이와 같은 이점이 있는 메세지 시스템을 우리가 만들 게임엔진에 구현할 것입니다.

지금까지 우리가 만들 게임엔진에 대해 핵심적인 내용을 다루어보았는데요. 다음 시간에는 본격적으로 게임 엔진을 만들기 시작해 볼 겁니다. 물론 여기에서 다루었던 내용은 게임엔진에 중요한 부분만 다루었고 이제 본 강의에서는 하나하나 세세히 다루면서 나갈 생각입니다. Precompile Header를 어떻게 만들고 실행시키는가 하는 부분도 진도를 나가면서 다루어 나갈 생각입니다. 오늘 했던 내용이 혹시 이해 안되는 부분이 있더라도 걱정하세요. '아, 이런걸 할거구나.' 정도만 아시면 충분합니다. 다음시간부터는 절대 이런 생각을 가지면 안되고 철저히 해야하구요.

혹시 오늘 강의에서 궁금했던 점은 댓글에 남겨주시면 답해 드릴게요. 이 긴 강의를 읽어 주셨던 분들 수고하셨습니다. 비록 허접한 강의가 여러분들에게 도움이 되었기를 바랍니다.

댓글을 달아 주세요

  1. Favicon of https://gamedevforever.com 김포프 2012.05.18 00:06 신고  댓글주소  수정/삭제  댓글쓰기

    어라? 이정도 내공의 글이 올라오면... 컴포넌트 글 쓰시던 끼로님이 설자리가 없어지는데..... 끼로님 어쩌죠? 레드불 더 마시면서 야근 두배로 더 하셔야겠어요(그럼 하루 36시간 일하나?) ㅋㅋ

  2. Favicon of https://gamedevforever.com 끼로 2012.05.18 00:34 신고  댓글주소  수정/삭제  댓글쓰기

    그나저나 그러면 기다리다보면 디퍼드H님이 컴포넌트 시스템에서의 메시지통신에 대해서 설명을 자세하게 해주시려나.. 사실 그거 이제 곧 써야 할 차례인데 귀찮아서 안쓰고 있..

    • Favicon of https://gamedevforever.com 디퍼드H 2012.05.18 04:33 신고  댓글주소  수정/삭제

      저같은 인디게임 밖에 안만들어봤던 초짜 프로그래머와 끼로 님의 메세지 통신 방법을 둘다 보여주는 것도 나쁘지 않도고 생각합니다. 서로 아마 방법이 약간 다를테니깐요. 끼로님꺼 메세지 기대할게요~^^ 저도 끼로님 메세지 통신 궁금합니다.

  3. Favicon of http://bluekms21.blog.me 크로스 2012.05.18 00:54  댓글주소  수정/삭제  댓글쓰기

    이제 여기 자료만 잘 봐도 게임한둘쯤 뚝딱 나오겠군요...ㄷㄷㄷ

  4. Favicon of https://gamedevforever.com 친절한티스 2012.05.18 01:46 신고  댓글주소  수정/삭제  댓글쓰기

    메시지 통신에 대해 자세히 알고 싶어요~

    • Favicon of https://gamedevforever.com 디퍼드H 2012.05.18 04:35 신고  댓글주소  수정/삭제

      우선 끼로님 메세지 통신이 먼저 올라오지 않을까요? 끼로님 메세지 통신이 더 좋을지도... 제가 만든건 우체국 시스템을 따서 만든거라~ 좋을지 않좋을지 우선 최대한 빨리 올릴게요~^^

    • Favicon of https://gamedevforever.com 끼로 2012.05.18 09:54 신고  댓글주소  수정/삭제

      음? 저는 메시지통신 이야기 안할 생각인데.. 참고로 저는 컴포넌트 기반 게임오브젝트를 쓰고 있긴 하지만 메시지통신은 안써요 ㅎㅎ 그래서 잘 몰름 그래서 고민중이었는데 디퍼드H님이 써주실꺼라 생각하고.. 걍 다른거 쓰려고 함 ㅋㅋ

    • Favicon of https://gamedevforever.com 디퍼드H 2012.05.20 10:29 신고  댓글주소  수정/삭제

      아... 저의 부담감이 배가 되겠군요..ㅜ

  5. flyingcode 2012.05.18 03:04  댓글주소  수정/삭제  댓글쓰기

    ㅎ 제가 지금 공부하려는 내용이 나온것 같네요.

    정주행하면서 따라가겠습니다. ㅋ 기대하고 있겠습니다.

  6. JazzEz2dj 2012.05.18 10:12  댓글주소  수정/삭제  댓글쓰기

    만쉐~!

  7. Favicon of https://toymaker.tistory.com 바하무트 2012.05.18 17:41 신고  댓글주소  수정/삭제  댓글쓰기

    오오... ^^ 이제 홈메이드 엔진 전성시대가~

  8. Favicon of https://gamedevforever.com 김포프 2012.05.20 08:02 신고  댓글주소  수정/삭제  댓글쓰기

    생각해보니 전 transform을 언제나 entity 컴포넌트에 넣곤 했었는데... transform이란 이름이 따로 있으니 좋네요....

    • Favicon of https://gamedevforever.com 디퍼드H 2012.05.20 10:27 신고  댓글주소  수정/삭제

      프로젝트를 하면서, transform을 컴포넌트로 하기보다 spatial컴포넌트를 만들어서 transform 클래스를 컴포지션하는게 scene graph 짜는데 도움 될 것 같다는 생각은 드는데 우선 그냥 transform 컴포넌트를 따로 두었어요~^^

  9. Favicon of https://jenemia.tistory.com 제네미아 2012.05.29 18:12 신고  댓글주소  수정/삭제  댓글쓰기

    게임 개발자 지망생입니다!
    좋은글 감사합니다 정주행해서
    이번 방학때 뭔가 한가지를 만들어 봐야 겠네요!
    메세지 통신에 대해 궁금하네요 맨날 객체 생성해서 했는데...

  10. letburn 2012.06.13 17:49  댓글주소  수정/삭제  댓글쓰기

    아아... 좋은 글입니다
    공들인 글 감사합니다~ ^^

  11. 이재원 2012.07.22 06:36  댓글주소  수정/삭제  댓글쓰기

    대단하시네요!! :)