Community코딩 & 개발github.com

ziva-sh/godot-씬-구성

Godot 4 프로젝트에서 씬을 재사용 가능하게 유지하고 참조가 깨지지 않도록 구성합니다. 씬, 스크립트, 리소스를 만들 때, @export PackedScene, preload, load, @onready, %UniqueName 노드 접근, _ready 순서, 그룹, 오토로드, class_name, Godot 4.4부터 추가된 .uid 파일을 이용한 리소스 UID 관리 및 안전한 파일 이동/이름 변경 방법을 다룹니다.

godot-씬-구성란 무엇인가요?

이 스킬은 Godot 4 프로젝트에서 씬을 구조화하고 참조 무결성을 유지하는 모범 사례를 제공합니다. 씬(.tscn), 스크립트(.gd), 리소스(extends Resource) 각각의 적절한 사용 시점과 방법을 설명하며, @export PackedScene을 통한 인스턴싱, preload/load의 차이, @onready와 %UniqueName을 활용한 효율적인 노드 접근, _ready() 실행 순서, 그룹을 통한 크로스 씬 태깅, 오토로드를 이용한 전역 상태 관리, class_name 전역 타입 등록 방법을 다룹니다. 특히 Godot 4.4에서 도입된 .uid 파일을 올바르게 버전 관리에 포함하고, 에디터 외부에서 파일을 이동하거나 이름을 변경할 때 UID가 깨지지 않도록 하는 구체적인 절차를 제공합니다. 이 스킬은 새로운 씬이나 스크립트를 만들 때, 노드 간 참조 방식을 결정할 때, 전역 상태나 이벤트 버스를 추가할 때, 또는 파일을 안전하게 이동/이름 변경해야 할 때 유용합니다.

지원 대상~Claude Code~Codex CLI~Cursor
Part ofMobile
npx skills add https://github.com/ziva-sh/godot-skills/tree/HEAD/skills/godot-scene-organization

Installed? Explore more 코딩 & 개발 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

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를 무시하기.
  • 편리하다는 이유로 모든 것을 오토로드로 만들기.

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

ziva-sh/godot-4-api-pitfalls

Fixes Godot 3 APIs and GDScript syntax that AI assistants write into Godot 4 projects, such as KinematicBody2D, move_and_slide(velocity), export, onready, setget, yield, string connect(), instance(), rand_range, the Tween node, File, change_scene, Spatial, rect_* properties, Pool*Array, OS time functions and the old TileMap API. Use when writing, reviewing or porting GDScript for Godot 4.x, when a script fails with "not declared", "not found in base", "was removed in Godot 4" or "is not present

ziva-sh/godot-control-layout

Builds Godot 4 Control UIs that resize instead of clipping or overlapping - containers versus anchors, anchor presets from code, size flags, custom_minimum_size, MarginContainer margins, Label wrapping, mouse_filter, CanvasLayer HUDs, Godot 4 theme override names (add_theme_color_override and friends) and the display/window/stretch settings for multiple resolutions. Use when creating or fixing menus, HUDs, dialogs and inventory screens, when UI elements are cut off, zero-sized, overlapping, igno

ziva-sh/godot-signals

Godot 4 signal patterns and their failure modes - declaring typed signals, emit(), connect() and disconnect() with Callables, bind() and unbind(), lambdas, CONNECT_ONE_SHOT and CONNECT_DEFERRED, await on signals and timers, editor-made connections stored in .tscn files, and the call down, signal up rule. Use when wiring UI buttons, timers, Area2D or body events and custom game events, when replacing Godot 3 connect("signal", self, "method") or yield code, or when debugging "already connected", "

ziva-sh/godot-tilemaplayer

Correct Godot 4.3+ TileMapLayer code - set_cell(coords, source_id, atlas_coords), reading cells and custom data, erasing, coordinate conversion, terrains, tile collision through TileSet physics layers, finding the tile a body hit, and migrating from the deprecated TileMap node and its layer-index API. Use when placing, reading or erasing tiles from GDScript, building a TileSet in code, generating levels procedurally, handling tile collisions, or porting TileMap code from Godot 3 or Godot 4.0 to

관련 스킬