Godot 4에서 씬 구성하기
씬, 스크립트, 리소스
- 씬 (
.tscn): 고유한 리소스를 가진 노드의 재사용 가능한 트리입니다. 플레이어, 적, 아이템, UI 패널, 레벨 등. 한 번 이상 배치하거나 단독으로 실행(F6)하려는 것은 모두 씬입니다. - 스크립트 (
.gd): 하나의 노드에 연결되는 동작입니다. 제어하는 씬의 루트에 연결하고, 부모가 그 안으로 접근하도록 하지 마십시오. - 리소스 스크립트 (
extends Resource+class_name): 노드가 없는 데이터입니다. 아이템 능력치, 웨이브 정의, 저장 데이터 등이 있으며, 인스펙터에서 편집하고.tres로 저장합니다.
씬은 단독으로 실행될 때도 동작해야 합니다. 외부에서 무언가(대상, 스폰 부모)가 필요하다면 get_parent() 체인 대신 @export나 시그널로 노출하십시오.
씬 인스턴싱
extends Node2D
@export var enemy_scene: PackedScene
@export var spawn_parent: Node2D
func spawn_enemy(at: Vector2) -> void:
var enemy := enemy_scene.instantiate() as Node2D
enemy.position = at
spawn_parent.add_child(enemy)
func load_level(path: String) -> void:
var packed := load(path) as PackedScene
if packed == null:
push_error("레벨을 찾을 수 없음: " + path)
return
get_tree().change_scene_to_packed(packed)
@export var x: PackedScene은 인스펙터에서 설정되며 파일 이동에도 참조가 유지됩니다(씬이 참조를 저장하기 때문).const BULLET := preload("res://bullet.tscn")는 파싱 시점에 해석됩니다. 파일이 없으면 파싱 에러가 발생합니다(Preload file "res://bullet.tscn" does not exist.). 고정된 에셋에 적합합니다.load()는 런타임에 해석되며 경로가 잘못되면null과 에러를 반환합니다. 런타임에 경로가 결정되는 경우 사용하십시오.instantiate()는Node를 반환합니다. 필요한 타입으로 캐스팅하십시오. 인스턴스는queue_free()로 해제합니다.
노드 찾기
extends Control
@onready var title: Label = %Title
@onready var start_button: Button = %StartButton
@onready var music: AudioStreamPlayer = $Music
@onready var optional_hint: Label = get_node_or_null("Hint")
func _ready() -> void:
title.text = "메인 메뉴"
start_button.grab_focus()
if optional_hint:
optional_hint.visible = false
music.play()
$Path는get_node("Path")와 동일하며, 이 노드를 기준으로 상대 경로입니다. 노드가 없으면 에러가 발생합니다. 선택적 노드는get_node_or_null()을 사용하십시오.%Name은 같은 씬 내에서 "고유 이름으로 접근"(씬 독에서 우클릭)으로 표시된 노드에 어디서든 접근할 수 있으므로, 씬 내부에서의 재부모화에 강합니다. 인스턴스화된 자식 씬에는 접근할 수 없습니다.$Child/%Name또는 인스턴스 자체가 고유한 경우%Child/%Name을 사용하십시오.@onready변수는_ready()직전에 할당됩니다._init()와_enter_tree()에서는null입니다._ready()는 자식이 부모보다 먼저 실행되므로, 부모의_ready()에서 자식을 사용할 수 있지만, 자식의_ready()는 부모가 준비되었다고 가정하면 안 됩니다.@onready변수에 타입(: Label)을 지정하면 파서가 멤버 이름을 검사합니다. 타입이 없는 경로에서$Label.txt는 런타임에만 오류가 잡힙니다.
그룹
그룹은 여러 씬에 걸쳐 노드에 태그를 지정합니다. 노드 독(그룹 탭)에서 추가하거나 코드에서 추가한 후 트리를 쿼리할 수 있습니다:
extends Node
func _ready() -> void:
add_to_group("enemies")
func alert_all_enemies() -> void:
get_tree().call_group("enemies", "set_alerted", true)
for enemy in get_tree().get_nodes_in_group("enemies"):
print(enemy.name)
var player := get_tree().get_first_node_in_group("player") as Node2D
if player:
print("Player at ", player.global_position)
call_group()은 Godot 4에서 즉시 호출합니다. 지연하려면 get_tree().call_group_flags(SceneTree.GROUP_CALL_DEFERRED, ...)를 사용하십시오.
오토로드
오토로드는 메인 씬보다 먼저 생성되어 씬 전환 사이에도 유지되는 노드입니다. 한 씬보다 오래 지속되는 상태(설정, 저장 데이터, 씬 전환기)와 시그널 전용 이벤트 버스에 사용하십시오. 프로젝트 설정 > 전역 > 오토로드에서 등록합니다. 그러면 project.godot에 다음이 포함됩니다:
[autoload]
Events="*res://autoload/events.gd"
*는 "활성화"가 체크되었음을 의미하므로 스크립트에서 이름을 직접 사용할 수 있습니다(Events.player_died.emit()). 오토로드를 free() 또는 queue_free()하지 마십시오. 오토로드는 적게 유지하십시오. 한 레벨에 속하는 것은 해당 레벨의 씬에 있어야 합니다.
도구 참고: godot --check-only --script는 오토로드를 로드하지 않으므로, 오토로드 이름을 사용하는 스크립트는 실제로는 잘 실행되지만 Identifier not found: Events 오류를 보고합니다. 이러한 스크립트는 씬을 실행하여 확인하십시오(godot-verify 스킬 참조).
class_name
class_name Player는 전역 타입을 등록하므로, 다른 스크립트에서 var player: Player를 작성하고 멤버 검사를 받을 수 있습니다. 에디터는 .godot/에 전역 클래스 캐시를 유지합니다. 에디터 외부에서 class_name을 추가한 후에는 이를 사용하는 스크립트를 확인하기 전에 에디터를 열거나 godot --headless --path . --import를 실행하십시오.
UID, .uid 파일, 파일 이동
Godot 4는 경로 외에도 UID로 리소스를 참조합니다. 씬과 리소스는 파일 헤더에 자신의 UID를 저장하고, 임포트된 에셋은 .import 파일에 저장하며, Godot 4.4부터 스크립트와 셰이더는 함께 제공되는 파일(player.gd.uid, water.gdshader.uid)을 갖습니다. 에디터가 저장한 참조는 다음과 같습니다:
[ext_resource type="Script" uid="uid://dxxoiuob4eoum" path="res://game_manager.gd" id="1_feb5d"]
규칙:
*.uid파일을 버전 관리에 커밋하십시오..gitignore에 추가하지 마십시오.- 가능하면 Godot 파일 시스템 독에서 파일을 이동하고 이름을 변경하십시오. 참조가 업데이트됩니다.
- Godot 외부(셸, IDE, 에이전트)에서 스크립트나 셰이더를 이동할 때는 해당
.uid파일도 함께 이동한 다음, 에디터를 열거나godot --headless --path . --import를 실행하여 UID 캐시가 새 경로를 알게 하십시오. 이 검사가 완료될 때까지는 이전 경로가 계속 사용되어 로딩이 실패합니다. .uid파일이 남겨지면 Godot은 이동된 스크립트에 대해 새 UID를 생성하고, 이전 UID를 참조하던 씬은 오래된 경로로 폴백합니다:WARNING: ... invalid UID: uid://... - using text path instead: res://old/path.gd, 이어서ERROR: ... referenced non-existent resource..tscn파일을 수동으로 작성할 때는uid=값을 임의로 만들지 마십시오. 해당 속성을 생략하고 올바른path를 사용하십시오. 에디터가 다음에 씬을 저장할 때 UID를 추가합니다.- 수동으로 작성된 Godot 4 씬은
[gd_scene format=3]으로 시작하고 리소스를 문자열 id로 참조합니다:[ext_resource type="Script" path="res://main.gd" id="1_main"], 그런 다음 노드에script = ExtResource("1_main")을 사용합니다. 자식 노드는parent="."또는 루트로부터의 경로가 필요합니다. Godot 4.7은 노드에unique_id=도 기록합니다. 수동으로는 생략하십시오. load("uid://...")와preload("uid://...")는 UID 문자열을 허용합니다. 파일 시스템 독 컨텍스트 메뉴에서 UID를 복사하십시오. 코드에서ResourceUID.id_to_text(ResourceLoader.get_resource_uid(path))가 UID를 반환합니다.
흔한 실수
get_parent().get_parent()또는/root/Main/Player같은 절대 경로로 위로 접근하기. 참조를 내보내거나, 그룹을 사용하거나, 시그널을 방출하십시오._init()또는 트리에 들어가기 전에 노드 사용하기.- 여러 스크립트에서 씬 경로를 하드코딩(
res://)하고PackedScene을 내보내지 않기. .uid파일 없이.gd파일을 이동하거나 git에서*.uid를 무시하기.- 편리하다는 이유로 모든 것을 오토로드로 만들기.