Szenenorganisation in Godot 4
Szene, Skript oder Resource
- Szene (
.tscn): Ein wiederverwendbarer Baum von Knoten mit eigenen Resourcen: ein Spieler, ein Gegner, ein Aufsammelgegenstand, ein UI-Panel, ein Level. Alles, was Sie mehrfach platzieren oder allein ausführen möchten (F6), ist eine Szene. - Skript (
.gd): Verhalten, das an einen Knoten angehängt wird. Hängen Sie es an den Stamm der Szene an, die es steuert, nicht an einen übergeordneten Knoten, der darauf zugreift. - Resource-Skript (
extends Resourcemitclass_name): Daten ohne Knoten, wie Gegenstandsstatistiken, Wellendefinitionen oder Spieldaten, die im Inspektor bearbeitet und als.tresgespeichert werden.
Eine Szene sollte funktionieren, wenn sie allein ausgeführt wird. Wenn sie etwas von außen benötigt (ein Ziel, einen Erzeugungsknoten), stellen Sie es mit @export oder einem Signal bereit, anstatt get_parent()-Ketten zu verwenden.
Szenen instanziieren
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("Level not found: " + path)
return
get_tree().change_scene_to_packed(packed)
@export var x: PackedScenewird im Inspektor gesetzt und überlebt Dateiverschiebungen, da die Szene die Referenz speichert.const BULLET := preload("res://bullet.tscn")wird zur Parse-Zeit aufgelöst: Eine fehlende Datei verursacht einen Parse-Fehler (Preload file "res://bullet.tscn" does not exist.). Gut für feste Assets.load()wird zur Laufzeit aufgelöst und gibtnullmit einem Fehler zurück, wenn der Pfad falsch ist. Verwenden Sie es für Pfade, die zur Laufzeit erstellt werden.instantiate()(nicht Godot 3sinstance()) gibt einenNodezurück; typisieren Sie ihn in den erforderlichen Typ. Freigeben von Instanzen mitqueue_free().
Knoten finden
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 = "Main menu"
start_button.grab_focus()
if optional_hint:
optional_hint.visible = false
music.play()
$Pathistget_node("Path"), relativ zu diesem Knoten. Es gibt einen Fehler aus, wenn der Knoten fehlt; verwenden Sieget_node_or_null()für optionale Knoten.%Nameerreicht einen Knoten, der als „Access as Unique Name“ markiert ist (Rechtsklick im Szenendock), überall in derselben Szene, sodass es eine Neuzuordnung innerhalb der Szene überlebt. Es erreicht keine instanziierten Kinderszenen: Verwenden Sie$Child/%Nameoder%Child/%Name, wenn die Instanz selbst eindeutig ist.@onready-Variablen werden direkt vor_ready()zugewiesen. Sie sindnullin_init()und_enter_tree()._ready()wird bei Kindern vor ihrem Elternteil ausgeführt, daher kann das_ready()eines Elternteils seine Kinder verwenden, aber das_ready()eines Kindes darf sich nicht darauf verlassen, dass das Elternteil bereit ist.- Typisieren Sie
@onready-Variablen (: Label), damit der Parser Membernamen prüft;$Label.txtauf einem nicht typisierten Pfad wird nur zur Laufzeit abgefangen.
Gruppen
Gruppen taggen Knoten szenenübergreifend. Fügen Sie sie im Knotendock (Registerkarte Gruppen) oder im Code hinzu und fragen Sie dann den Baum ab:
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() ruft in Godot 4 sofort auf. Verwenden Sie get_tree().call_group_flags(SceneTree.GROUP_CALL_DEFERRED, ...), um zu verzögern.
Autoloads
Ein Autoload ist ein Knoten, der vor der Hauptszene erstellt und über Szenenwechsel hinweg beibehalten wird. Verwenden Sie ihn für Zustände, die eine Szene überdauern (Einstellungen, Spieldaten, ein Szenenwechsler) und für einen Signal-only-Ereignisbus. Registrieren Sie ihn in Projekteinstellungen > Globals > Autoload; project.godot enthält dann:
[autoload]
Events="*res://autoload/events.gd"
Das * bedeutet „Enable“ ist aktiviert, sodass Skripte den Namen direkt verwenden können (Events.player_died.emit()). Einen Autoload nicht free() oder queue_free() aufrufen. Halten Sie Autoloads gering: Alles, was zu einem Level gehört, sollte in der Szene dieses Levels leben.
Hinweis für Tools: godot --check-only --script lädt keine Autoloads, daher meldet ein Skript, das einen Autoload-Namen verwendet, dort Identifier not found: Events, obwohl es einwandfrei läuft. Überprüfen Sie solche Skripte, indem Sie die Szene ausführen (siehe die godot-verify-Fähigkeit).
class_name
class_name Player registriert einen globalen Typ, sodass andere Skripte var player: Player schreiben und eine Memberprüfung erhalten können. Der Editor behält einen globalen Klassen-Cache in .godot/; nach dem Hinzufügen eines class_name außerhalb des Editors öffnen Sie den Editor oder führen Sie godot --headless --path . --import aus, bevor Sie Skripte überprüfen, die es verwenden.
UIDs, .uid-Dateien und Dateien verschieben
Godot 4 referenziert Ressourcen sowohl über UID als auch über Pfad. Szenen und Resourcen speichern ihre eigene UID im Dateikopf, importierte Assets in ihrer .import-Datei, und seit Godot 4.4 erhalten Skripte und Shader eine Begleitdatei (player.gd.uid, water.gdshader.uid). Eine im Editor gespeicherte Referenz sieht so aus:
[ext_resource type="Script" uid="uid://dxxoiuob4eoum" path="res://game_manager.gd" id="1_feb5d"]
Regeln:
*.uid-Dateien in die Versionskontrolle einchecken. Nicht zu.gitignorehinzufügen.- Dateien nach Möglichkeit im Godot-Dateisystemdock verschieben und umbenennen; es aktualisiert Referenzen.
- Wenn Sie ein Skript oder einen Shader außerhalb von Godot verschieben (Shell, IDE, Agent), verschieben Sie seine
.uid-Datei mit und öffnen Sie dann den Editor oder führen Siegodot --headless --path . --importaus, damit der UID-Cache den neuen Pfad lernt. Bis zu diesem Scan wird der alte Pfad noch verwendet und das Laden schlägt fehl. - Wenn die
.uid-Datei zurückbleibt, generiert Godot eine neue UID für das verschobene Skript, und Szenen, die auf die alte verwiesen haben, fallen auf ihren veralteten Pfad zurück:WARNING: ... invalid UID: uid://... - using text path instead: res://old/path.gd, dannERROR: ... referenced non-existent resource. - Wenn Sie eine
.tscnmanuell schreiben, erfinden Sie keineuid=-Werte. Lassen Sie das Attribut weg und verwenden Sie einen korrektenpath; der Editor fügt UIDs hinzu, wenn er die Szene das nächste Mal speichert. - Eine handgeschriebene Godot 4-Szene beginnt mit
[gd_scene format=3]und referenziert Resourcen über die String-ID:[ext_resource type="Script" path="res://main.gd" id="1_main"], dannscript = ExtResource("1_main")auf dem Knoten. Kindknoten benötigenparent="."oder einen Pfad von der Wurzel. Godot 4.7 schreibt auchunique_id=auf Knoten; manuell weglassen. load("uid://...")undpreload("uid://...")akzeptieren UID-Strings. Kopieren Sie eine UID aus dem Kontextmenü des Dateisystemdocks;ResourceUID.id_to_text(ResourceLoader.get_resource_uid(path))gibt sie aus Code zurück.
Häufige Fehler
- Nach oben greifen mit
get_parent().get_parent()oder absoluten Pfaden wie/root/Main/Player. Exportieren Sie eine Referenz, verwenden Sie eine Gruppe oder geben Sie ein Signal aus. - Verwenden eines Knotens in
_init()oder bevor er in den Baum eingetreten ist. - Hartcodieren von
res://-Pfaden zu Szenen in vielen Skripten anstatt einer exportiertenPackedScene. - Verschieben von
.gd-Dateien ohne ihre.uid-Dateien oder Ignorieren von*.uidin Git. - Alles zu einem Autoload machen, weil es bequem ist.