SceneTree

소개

여기서 내용이 추상적으로 되기 시작합니다, 하지만 당황하지 마세요. 여기보다 훨씬 더 깊게 보는 곳은 없습니다.

이전 튜토리얼에서, 모든 것은 노드 개념을 중심으로 돌아갔습니다. 씬은 간단히 노드의 집합입니다. 그들이 씬 트리(scene tree) 에 들어가면 활성화됩니다.

이 개념은 조금 더 자세히 설명할 가치가 있습니다. 사실, 씬 시스템은 Godot의 핵심 구성 요소도 아니기에 넘어가서 바로 서버와 직접 대화하는 스크립트를 (혹은 C++ 코드를) 쓸 수 있습니다, 하지만 그런 방식으로 게임을 만드는 일은 많은 작업이 될 것입니다.

MainLoop

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

초기화를 마칠 때, OS 를 실행하기 위해 MainLoop 가 공급되어야 합니다. 여기까지, 이 모든 것이 내부 작업입니다 (어떻게 내부 작업이 이루어지는지 관심이 있으시다면, 소스 코드의 main/main.cpp 파일에서 이를 확인하실 수 있습니다).

사용자 프로그램, 게임은 MainLoop에서 시작합니다. 이 클래스는 몇 가지 메소드를 갖고 있는데, 초기화, 휴식(Idle)(프레임 동기화된 콜백), 고정된(fixed)(물리 동기화된 콜백), 그리고 입력입니다. 이것은 로우 레벨이며, Godot에서 게임을 만들 때 당신만의 MainLoop를 만드는 일은 드뭅니다.

SceneTree

Godot가 어떻게 작동하는지 설명하는 방법으로 이것은 로우 레벨 미들웨어에 비해 높은 수준의 게임 엔진이란 것입니다.

씬 시스템은 게임 엔진입니다, 반면에 OS 와 서버는 로우 레벨 API입니다.

어쨌든, 씬 시스템은 고유의 메인 루프(main loop)인, SceneTree 를 OS로 보냅니다. 이것은 자동으로 씬이 실행되는 동안 자동으로 인스턴스 되고 설정됩니다, 다른 추가 작업은 필요가 없습니다.

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

  • 처음 열렸을 때 씬 트리 의 일부분이 되도록 씬이 자식으로 추가되는, 루트 Viewport 를 포함합니다, (자세한 설명은 다음에)
  • 그룹에 관한 정보를 포함하고 그룹의 모든 노드를 호출하거나 그룹의 목록을 가져옵니다.
  • 일시 정지 모드 설정이나 프로세스 종료하기와 같은, 일부 전역 상태 기능성을 포함합니다.

노드가 씬 트리의 일부분일 때, SceneTree 싱글톤(Singleton)은 간단히 Node.get_tree() 를 호출해서 포함될 수 있습니다.

루트 뷰포트(Root viewport)

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

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

이 노드는 메인 뷰포트를 갖고 있습니다, 어떤 것이든 Viewport 의 자식으로 기본적으로 안에 있습니다, 그래서 모든 노드의 맨 위에는 이 노드가 있고 그렇지 않다면 아무것도 볼 수 없을 것입니다!

반면에 다른 뷰포트는 씬에서 만들 수 있지만(분리 화면 효과와 같은 것을 위해), 사용자가 절대 만들 수 없는 유일한 것입니다. 씬 트리에서 자동으로 생성됩니다.

씬 트리

노드가 뷰포트에 연결될 때, 직접적이든 아니든, 그것은 씬 트리 의 일부분이 됩니다.

이전 튜토리얼에서 설명했듯이, 그것은 (_exit_tree()과 마찬가지로) _enter_tree()와 _ready() 콜백을 가질 것입니다.

../../_images/activescene.png

노드가 씬 트리 에 들어오게 되면, 활성화됩니다. 그들은 프로세스, 입력, 2D와 3D 디스플레이, 알림, 소리 재생, 그룹 등 필요로 하는 모든 것을 액세스 합니다. 그들이 씬 트리 에서 제거될 때, 액세스를 잃습니다.

트리 순서

2D 그리기, 프로세싱, 혹은 알림과 같은 대부분의 노드 운영은 트리 순서에서 완료됩니다. 이는 트리 순서에서 부모와 더 낮은 등급의 형제 노드들이 현재 노드 이전에 알림을 받을 것을 의미합니다.

../../_images/toptobottom.png

씬 트리 에 들어가서 "활성화하기"

  1. 씬은 디스크에서 불러오거나 스크립트에 의해 만들어집니다.
  2. 씬의 루트 노드 (단 하나의 루트, 기억하시나요?) 는 "루트" 뷰포트의 자식으로, 혹은 노드의 자식으로 (씬 트리에서) 추가됩니다.
  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")
public void _MyLevelWasCompleted()
{
    GetTree().ChangeScene("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)
public void _MyLevelWasCompleted()
{
    PackedScene nextScene = ResourceLoader.load("res://levels/level2.tscn") as PackedScene;
    GetTree().ChangeSceneTo(nextScene);
}

이것은 씬을 바꾸기에 빠르고 유용하지만 새로운 씬이 불러오고 실행될 때까지 멈춰있는 단점이 있습니다. 게임의 어느 시점에서, 진행 막대, 애니메이션 표시기, 혹은 스레드(배경) 로딩으로 적절한 로딩 화면을 만드는 것이 좋습니다. 이것은 수동으로 오토로드(Autoload)를 사용하거나(다음 챕터를 보십시오!) Background loading으로 해결할 수 있습니다.