본문 바로가기

레퍼런스/고도엔진

고도엔진 튜토리얼 #12 씬트리(SceneTree)

도입


여기가 추상적으로 변해가기 시작하는 지점입니다. 하지만 이것보다 더 어려운 것은 없으니 겁내지 마세요.


앞선 튜토리얼에서 노드의 개념과 노드로 이루어진 씬들이 돌아다니고 있습니다. 이것들은 씬 트리에 들어가면 활성화됩니다.


이 개념은 좀 더 자세히 볼 필요가 있습니다. 사실 씬 시스템은 고도의 핵심 구성요소도 아닙니다. 서버에 직접 연결되는 스크립트(또는 C++ 코드_를 작성하고 건너뛸 수 있기 때문입니다. 하지만 그런 식으로 게임을 만드는 것은 많은 일을 해야 할 것입니다.



메인 루프


고도가 내부적으로 작동하는 방법은 다음과 같습니다. 여기에 처음에 실행되는 유일한 인스턴스인 운영체제 클래스가 있습니다. 그런 다음, 모든 드라이버, 서버, 스크립팅 언어, 장면 시스템 등이 로드됩니다.


초기화가 완료될 때, 운영체제는 실행되기 위해 메인루프가 제공되어야 합니다. 이 지점에서, 이 모든건 내부적인 작동입니다(여러분은 내부적으로 어떻게 작동하는지 보기 위해 소스 코드에서 main/main.cpp를 확인해 볼 수 있습니다).


유저 프로그램 혹은 게임은 메인 루프에서 시작합니다. 이 클래스는 초기화, 유휴(프레임-싱크로나이즈드 콜백), 고정(피직스-싱크로나이즈드 콜백), 그리고 입력을 위한 몇몇 메소드가 있습니다. 다시, 이것은 매우 낮은 단계이고 고도로 게임을 만들 때는 여러분의 메인루프를 만드는 것은 말이 되지 않습니다.



씬 트리


고도가 어떻게 작동하는 지 알려주는 방법 중에 하나는, 저수준 미들웨어에 비해 높은 수준의 게임 엔진이라는 것입니다. (One of the ways to explain how Godot works, is that it’s a high level game engine over a low level middleware.)


씬 시스템은 게임 엔진이고, OS와 서버는 저수준 API입니다.


어떤 경우에도 씬 시스템은 그 자신의 메인루프인 씬 트리를 운영체제에 제공해줍니다. 이는 자동적으로 인스턴스화되고 별다른 작업 없이 씬을 실행할 때 설정됩니다.


이 클래스가 몇몇 중요한 사용법을 가지는 것을 아는 것이 중요합니다 :

·

  • 이 클래스는 처음으로 열렸을 때 씬이 자식으로 추가되어 씬트리의 일부가 되는 루트 뷰포트를 포함합니다.
  • 그룹에 대한 정보를 포함하고, 그룹에 있는 모든 노드에게 호출하거나 해당 노드의 목록을 가져올 수 있습니다.
  • 일시 중지 모드 설정 또는 프로세스 종료와 같은 일부 글로벌 상태 기능을 포함합니다.

노드가 씬 트리의 부분이 될 때, 하나씩 일어나는 일인 씬 트리Node.get_tree()를 호출함으로써 쉽게 얻을 수 있다.


루트 뷰포트

루트 뷰포트는 언제나 씬의 최상위에 있습니다. 두 가지 방법으로 노드로부터 얻을 수 있는데 :

get_tree().get_root() # access via scenemainloop
get_node("/root") # access via absolute path


이 노드는 뷰포트의 자식이며 기본으로 내부적으로 그려지는 메인 뷰포트를 포함하고 있습니다. 그렇기 때문에 모든 노드의 최상위에 항상 이 타입의 노드가 있다는 것은 말이되며 그렇지 않으면 아무것도 보이지 않을 것입니다.


다른 뷰포트는 씬에서 생성될 수 있지만(분할 스크린 효과 등을 위해), 사용자가 결코 생성하지 않는 뷰포트는 이 뷰포트 뿐입니다. 씬 트리 내부에서 자동적으로 생성됩니다.



씬 트리

노드가 뷰포트에 직·간접적으로 연결되었을 때 씬 트리의 일부가 됩니다.

이것은 이전 튜토리얼에서도 설명했듯이 _enter_tree()와 _ready() 콜백으로 얻을 수 있음을 뜻합니다(_exit_tree()도 마찬가지입니다).


../../_images/activescene.png


노드가 씬 트리에 들어갔을 때, 활성화됩니다. 공정, 입력을 받기, 2D와 3D를 출력하고, 알리거나, 소리를 재생, 그룹 등 모든 곳에서 접근이 가능합니다. 하지만 씬 트리에서 삭제 되었을 때 그들은 이 접근을 잃게 됩니다.


트리 순서


고도에서의 그림을 그린다거나 프로세싱 혹은 알림을 받는 등의 대부분의 동작은 트리 순서대로 실행됩니다. 이것은 트리 순서가 낮은 부모 형제나 자매가 현재 노드보다 먼저 통보 받게 된다는 것을 의미합니다.



../../_images/toptobottom.png


씬 트리를 들어가며 "활성화가 되는 과정"

  1. 씬이 디스크에서 로드되거나 스크립팅으로 생성됩니다.
  2. 씬의 루트 노드(하나의 루트 뿐입니다, 기억하시죠?)는 "루트" 뷰포트(씬 트리의)에서의 자식이나 어떠한 자식 혹은 손자로도 추가됩니다. (The root node of that scene (only one root, remember?) is added as either a child of the “root” Viewport (from SceneTree), or to any child or grand-child of it.)
  3. 씬에 새로 추가된 모든 노드는 "enter_tree" 알림을 제일 위부터 아래의 순서대로 받게됩니다. (GDScript의 _enter_tree() 콜백입니다)
  4. 추가적인 알림으로 노드와 그 자식들이 모두 활성화 씬에 있을 때, "ready"가 편의상 제공됩니다. (GDScript의 _ready() 콜백입니다)
  5. 노드가 씬에서 (혹은 그 부분에서) 삭제되었을 때, "exit scene" 알림을 제일 위부터 아래의 순서대로 받게 됩니다. (GDScript의 _exit_tree() 콜백입니다.)


현재 씬을 바꾸기

씬이 로드되고 나서, 이 씬을 바꾸거나 다른 씬으로 전환하고 싶을 때가 많습니다. 간단하게 SceneTree.change_scene() 함수를 사용하면 쉽게 할 수 있습니다 : 

func _my_level_was_completed():
    get_tree().change_scene("res://levels/level2.scn")

이건 쉽게 장면을 전환할 수 있는 방법이지만, 게임이 새로운 씬을 전환하고 실행할 때 지연되는 결점이 있습니다. 이 점에서 여러분의 게임은 애니메이션된 진행바와 함께 적당한 로딩 화면을 만들고 싶으실 겁니다. 이 기능은 오토로드와 백그라운드 로딩을 사용해서 수동적으로 할 수 있습니다. (다음 장을 보세요!)