본문 바로가기

IT 번역/Cocos2d-x 메뉴얼[manual] 번역

씬과 씬 그래프 | Scenes and the Scene Graph

게임에는 메인 메뉴가 필요할 거에요, 몇가지 게임 레벨과 엔딩씬도 필요하겠죠. 어떻게 해야 이렇게 여러가지 조각들을 잘 묶을 수 있을까요? 맞아요, 씬(Scene)입니다. 좋아하는 영화에 대해서 떠올려보면, 씬 단위로 확연하게 나뉘던지, 스토리 라인에따라 여러 부분들로 나뉘어 있다는 것을 이해하실 겁니다. 이런 개념을 게임에 적용해본다면, 게임이 아무리 간단하더라도 최소한 몇개의 씬(Scene)들로 구성되어야 한다는 것을 자연스럽게 이해하실 겁니다.

일전의 글에서 보셨던 익숙한 이미지를 다시 한번 볼까요?

자, 이 화면을 보시면, 메인 메뉴가 있는 단일 씬(Scene)이라는 것을 확인 하실 수 있습니다. 이 하나의 씬(Scene)은 여러개의 요소들이 한대 어울려, 최종 결과물을 보여주고 있습니다. 씬(Scene)은 렌더러(renderer)가 만들어냅니다. 렌더러(renderer)는 화면에 표시되어야 하는 모든 것들을 모으고, 어떻게 표현해야 하는지를 담당합니다. 이 개념을 이해하시기 위해서는 씬 그래프(Scene Graph)에 대해서 알아봐야 하겠군요.

씬 그래프 | Scene Graph

씬 그래프(Scene Graph)란 시각적인 씬을 구성하는 데이터 구조입니다. 이 씬 그래프(Scene Graph)는 트리 구조에 노드 객체들을 담고 있습니다. (네, 씬 그래프(Scene Graph)라 부르지만, 실제로는 트리입니다.)

좀 복잡해보이죠? "아니, Cocos2d-x가 기반 기술들을 다 담당한다면서 왜 이런 상세 기술을 알아야 하냐?"고 묻고 싶은 마음이 굴뚝같을 거라고 짐작됩니다. 하지만, 씬(Scene)들이 렌더러(renderer)를 통해 어떻게 화면에 그려지는지 이해하는건 되게, 정말정말 중요합니다.

게임에 노드(Node)랑 스프라이트(Sprite), 애니메이션(Animation) 객체들을 넣기 시작하면, 얘들이 생각한대로 화면에 그려지길 원하시잖아요? 근데, 만약 생각한대로 화면에 안나오면요? 스프라이트(Sprite) 객체가 배경에 가려진 상태라서, 걔들을 화면 최상위에 그리고 싶으시면요? 자, 걱정하지 마세요, 한발 물러서서 종이에다가 씬 그래프(Scene Graph)를 한번 그려보세요. 뭔 실수를 했는지 쉽게 찾으실 수 있을 거에요, 장담합니다.

씬 그래프(Scene Graph)가 트리(Tree)라고 했잖아요? 그러니 이 나무(Tree)를 따라가보시면 됩니다. Cocos2d-x는 중외순회 알고리즘(in-order walk algorithm)을 사용합니다. 중외순회(in-order walk)는 트리의 왼쪽 자식노드로 갔다가 부모노드를 거쳐 오른쪽 자식노드 순으로 갑니다. 트리의 오른쪽 자식노드가 가장 나중에 그려지니니, 씬 그래프(Scene Graph)에서 가장 최상위에 그려진다는 것이죠.

씬 그래프(Scene Graph)는 쉽게 살펴보실 수 있어요. 예시로 든 게임 씬(Scene)를 분해해서 살펴보죠.

위 화면은 트리 구조로 구성이 되니까, 간단히 생각해보자면 다음과 같습니다:

다른 관점에서 생각해본다면, 트리 구조의 왼편에 있는 요소들은 마이너스 z-오더(negative z-order)를 갖고 있고, 오른편에 있는 요소들은 플러스 z-오더(positive z-order)를 갖고 있다라는 점입니다.

이 개념을 기반으로, 노드(Node) 객체들의 묶음으로서 씬(Scene)을 생각해볼 수도 있지요. 그럼, 위의 씬(Scene)을 한번 분해해서, 씬 그래프(Scene graph)가 z-오더(z-order)를 사용하여 위의 씬(Scene)을 어떻게 구성하는지 보겠습니다:

왼쪽에 있는 씬(Scene)은 실제 여러 노드(Node) 객체들이 한대 어우러져있는 것입니다. 이 노드(Node)들은 각자 다른 z-오더(z-order)를 갖고있으며, 그 z-오더(z-order)에 따라 차곡차곡 쌓이게됩니다.

Cocos2d-x에서는, 씬 그래프(Scene graph)를 구성할 때 addChild() API를 사용하시면 됩니다:

// z-오더(z-order)값을 -2로 하는 자식노드를 추가합니다.
// 즉, 이 추가되는 노드는 트리의 "왼편"에 자리하게 됩니다.
// (z-오더(z-order)가 마이너스니까요.)
//		Adds a child with the z-order of -2, that means
//		it goes to the "left" side of the tree (because it is negative)
scene->addChild(title_node, -2);

// 노드의 z-오더(z-order)값을 지정하지 않으면 기본값은 0 입니다.
//		When you don't specify the z-order, it will use 0
scene->addChild(label_node);

// z-오더(z-order)값을 1로 하는 자식노드를 추가합니다.
// 다시 말해, 새로 추가하는 노드는 트리의 "오른편"에 놓인다는 것이죠.
// (z-오더(z-order)가 플러스니까요.)
//		Adds a child with the z-order of 1, that means
//		it goes to the "right" side of the tree (because it is positive)
scene->addChild(sprite_node, 1);

 

게임을 만들어보자 - 4 단계 | Let's Build A Game - Step 4

게임을 만들어가면서, 어떤 씬(Scene) 객체가 필요한 것인지 생각해야 합니다. 어떤 게임들은 단 하나의 씬(Scene) 객체만을 사용하기도 합니다. 그렇게 하려면, 해당 씬(Scene)에 추가된 모든 노드를 제거하고 다음 씬에 필요한 새로운 노드들로 교체 혹은 추가하는 방법을 사용합니다. 이 방식도 한가지 방법이죠. 또 다른 방법으로는 게임을 메인 메뉴와 게임 씬(game scene)으로 나누어 구성하는 것입니다. 3번째 방법은 메인 메뉴, 레벨1 -> 레벨 N 그리고 마지막으로 마무리 씬(closing scene)까지 더욱 세세하게 나누어 구성하는 것이죠. 다양한 씬(Scene) 객체들 사이에 가벼운 전환효과(Transition)을 넣거나 컷 씬(Cut Scene)을 추가하실지도 모르지요. 그렇게 추가되는 컷 씬(Cut Scene)들을 이용해서 이야기를 이어갈 수도 있고, 화면 뒷편에서 (눈에 보이지 않게) 다음 레벨을 불러오는 동안, 그냥 단순히 플레이어가 심심하지 않도록 뭔가를 보여줄 수도 있습니다.

이 게임에서는, 인트로도입 씬(Intro Scene)과 실제 게임 씬(Game Scene) 그리고 마무리 씬(Closing Scene)으로 구성해볼까 합니다. 그러기 위해서는, 3개의 거의 똑같은 클래스를 만들어야 합니다. 최소한 시작할 때는 말이죠. 이 클래스들은 게임의 각 부분을 만들어가면서 달라질겁니다. 프로그래머들 사이에 끝나지 않는 논쟁의 떡밥으로 클래스를 많이 만드는 게 좋으냐 아니면 적게 만드는게 좋으냐하는 것이 있습니만, 이 이야기는 다음으로 미뤄두죠. 지금은 가급적 명확한 부분만 짚고 가도록 하겠습니다. C++하고 게임 개발 두가지를 동시에 배운답시고 시간을 허비하는 것은 현명한 일이 아니니까요.

일단 위에 거론된 클래스들을 추가하죠. 클래스들은 그냥 소스파일들입니다. 컴맨드 라인(command-line)에서 추가하셔도 좋고, 텍스트 편집기를 사용하셔도 상관없습니다. (비쥬얼 스튜디오같은) IDE를 사용하신다면, 위자드 같은 걸 이용하셔서 추가하셔됩니다. 클래스 생성에 익숙치 않으면, 그것도 좋은 방법이니까요.

처음 만드실 클래스는 인트로 클래스(intro class)입니다. 기본 클래스는 일단 신경꺼주세요.

사자와 호랑이와 스프라이트(Sprites).. 오 이런!
(Lions and tigers and Sprites.. oh my! 이게 무슨 말장난 같은데 아직은 모르겠네요.)