씬 트리(SceneTree) 사용하기

소개

이전 튜토리얼에서는 모든 것이 노드 개념을 중심으로 진행됐습니다. 씬은 노드의 모음입니다. 노드는 씬 트리(scene tree)에 들어가면 활성화됩니다.

메인루프(MainLoop)

Godot가 내부적으로 작동하는 방식은 다음과 같습니다. 처음에 실행되는 유일한 인스턴스인 OS 클래스가 있습니다. 그 이후에 모든 드라이버, 서버, 스크립팅 언어, 씬 시스템 등을 불러옵니다.

초기화가 완료될 때 OS를 실행하려면 MainLoop가 제공되어야 합니다. 여기까지는 이 모든 것이 내부적으로 작동하는 방식입니다(내부적으로 어떻게 작동하는지 알고 싶다면 소스 코드에서 main/main.cpp 파일을 확인하세요).

사용자 프로그램, 게임은 MainLoop에서 시작됩니다. 이 클래스에는 초기화, 유휴: 프레임에 동기화된 콜백(idle: frame-synchronized callback), 고정: 물리에 동기화된 콜백(fixed: physics-synchronized callback) 및 입력에 대한 몇 가지 메서드가 있습니다. 다시 말하지만, 이는 로우 레벨이며 Godot에서 게임을 만들 때 MainLoop를 작성하는 것은 거의 의미가 없습니다.

씬트리

Godot가 어떻게 작동하는지 설명하는 방법 중 하나는 Godot가 저수준 미들웨어보다 높은 수준의 게임 엔진이라는 것입니다.

씬 시스템은 게임 엔진이고 OS와 서버는 로우 레벨 API입니다.

씬 시스템은 OS, 즉 SceneTree에 자체 메인 루프를 제공합니다. 메인 루프는 씬이 실행되는 동안 자동으로 인스턴스화되고 설정되므로 추가 작업을 수행할 필요가 없습니다.

이 클래스는 몇 가지 중요한 용도로 쓰이기 때문에 이 클래스가 존재한다는 것을 아는 것이 중요합니다:

  • It contains the root Viewport, to which a scene is added as a child when it's first opened to become part of the Scene Tree (more on that next).

  • 그룹에 관한 정보가 포함되어 있어서 그룹의 모든 노드를 호출하거나 그룹의 목록을 가져옵니다.

  • 일시 정지 모드 설정이나 프로세스 종료와 같은, 일부 전역 상태 기능이 포함되어 있습니다.

노드가 씬 트리의 일부인 경우 Node.get_tree()를 호출해서 SceneTree 싱글톤(Singleton)을 가져올 수 있습니다.

루트 뷰포트(Root viewport)

루트 Viewport는 항상 씬의 맨 위에 있습니다. 노드에서 두 가지 다른 방법으로 가져올 수 있습니다:

get_tree().get_root() # Access via scene main loop.
get_node("/root") # Access via absolute path.

이 노드는 메인 뷰포트를 포함합니다. Viewport의 모든 자식은 기본적으로 그 안에 그려지므로 모든 노드의 맨 위는 항상 이 타입의 노드이며 그렇지 않으면 아무 것도 보이지 않을 것입니다.

씬에 다른 뷰포트를 만들 수도 있지만(분할 화면 효과 등을 위해서) 루트 뷰포트는 유저가 만들 수 없는 유일한 노드입니다. 씬 트리에서 자동으로 생성됩니다.

씬 트리

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

즉, 이전 튜토리얼에서 설명했듯이 _enter_tree(), _ready() 콜백 (및 _exit_tree())을 가져옵니다.

../../_images/activescene.png

노드는 씬 트리에 들어가면 활성화됩니다. 노드는 입력을 받거나 처리하고, 2D 및 3D 오브젝트를 화면에 표시하고, 알림을 송·수신하고, 소리를 재생하는 등 필요한 모든 것에 접근할 수 있습니다. 노드가 씬 트리에서 제거되면 이러한 능력을 잃게 됩니다.

트리 순서

2D 그리기, 처리, 알림 받기와 같은 Godot의 대부분의 노드 작업은 트리 순서로 수행됩니다. 이는 트리 순서에서 현재 노드보다 낮은 순위를 가진 부모와 형제가 현재 노드보다 먼저 알림을 받는다는 것을 의미합니다.

../../_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 grandchild 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.tscn")

파일 경로를 사용하는 대신 동일한 함수 SceneTree.change_scene_to(PackedScene scene)를 사용해 이미 만들어진 PackedScene 리소스를 사용할 수 있습니다:

var next_scene = preload("res://levels/level2.tscn")

func _my_level_was_completed():
    get_tree().change_scene_to(next_scene)

이는 씬을 전환하는 빠르고 유용한 방법이지만 새 씬을 불러와 실행할 때까지 게임이 중단된다는 단점이 있습니다. 게임 개발의 어느 시점에 프로그레스 바, 애니메이션 표시기나 스레드(배경) 로딩을 사용한 적절한 로딩 화면을 만드는 것이 바람직합니다. 오토로드(다음 장 참조) 및 백그라운드 로딩을 사용해서 수동으로 작업해야 합니다.