Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Code im Editor ausführen

Was ist @tool?

@tool ist eine leistungsstarke Codezeile, die im Editor ausgeführt wird, wenn man sie oben im Skript hinzufügt. Sie können auch entscheiden, welche Teile des Skripts im Editor ausgeführt werden, welche im Spiel und welche in beiden.

Sie können es für viele Dinge verwenden, aber es ist vor allem im Level-Design nützlich, um Dinge visuell darzustellen, die selbst schwer vorherzusagen sind. Hier sind einige Anwendungsfälle:

  • Wenn Sie eine Kanone haben, die Kanonenkugeln abschießt, die von der Physik (Schwerkraft) beeinflusst werden, können Sie die Flugbahn der Kanonenkugel im Editor zeichnen, was das Leveldesign sehr erleichtert.

  • Wenn Sie Sprungfelder mit unterschiedlichen Sprunghöhen haben, können Sie die maximale Sprunghöhe einzeichnen, die ein Spieler erreichen würde, wenn er auf ein Sprungfeld springt, was die Levelgestaltung ebenfalls erleichtert.

  • Wenn Ihr Spieler kein Sprite verwendet, sondern durch Code gezeichnet wird, können Sie diesen Zeichencode im Editor ausführen lassen, um Ihren Spieler anzuzeigen.

Gefahr

@tool-Skripte laufen innerhalb des Editors und erlauben den Zugriff auf den Szenenbaum der aktuell bearbeiteten Szene. Dies ist eine mächtige Funktion, die aber auch ihre Tücken hat, da der Editor keinen Schutz gegen möglichen Missbrauch von @tool-Skripten bietet. Seien Sie äußerst vorsichtig, wenn Sie den Szenenbaum manipulieren, besonders über Node.queue_free, da es zu Abstürzen führen kann, wenn Sie einen Node freigeben, während der Editor eine Logik ausführt, die ihn betrifft.

Wie man @tool verwendet

Um ein Skript in ein Tool zu verwandeln, fügen Sie das Schlüsselwort @tool am Anfang Ihres Codes ein.

Um zu prüfen, ob Sie sich gerade im Editor befinden, verwenden Sie: Engine.is_editor_hint().

Wenn Sie beispielsweise Code nur im Editor ausführen möchten, verwenden Sie:

if Engine.is_editor_hint():
    # Code to execute when in editor.

Wenn Sie dagegen Code nur im Spiel ausführen möchten, negieren Sie einfach dieselbe Anweisung:

if not Engine.is_editor_hint():
    # Code to execute when in game.

Codeteile, auf die keine der beiden oben genannten Bedingungen zutreffen, werden sowohl im Editor als auch im Spiel ausgeführt.

Hier sieht man wie eine _process() Funktion aussehen könnte:

func _process(delta):
    if Engine.is_editor_hint():
        # Code to execute in editor.

    if not Engine.is_editor_hint():
        # Code to execute in game.

    # Code to execute both in editor and in game.

Bemerkung

Änderungen im Editor sind dauerhaft. Wenn wir zum Beispiel im folgenden Fall das Skript entfernen, behält der Node seine Drehung bei. Seien Sie vorsichtig, um unerwünschte Änderungen zu vermeiden.

Bemerkung

Das Erweitern eines @tool-Skripts macht das erweiternde Skript nicht automatisch zu einem @tool. Das Weglassen von @tool im erweiternden Skript deaktiviert das Tool-Verhalten der Superklasse. Daher sollte das erweiternde Skript auch das @tool-Schlüsselwort enthalten.

Probieren Sie @tool aus

Fügen Sie einen Sprite2D-Node zu Ihrer Szene hinzu und setzen Sie die Textur auf das Godot Icon. Fügen Sie ein Skript hinzu, öffnen Sie es und ändern Sie es wie folgt:

@tool
extends Sprite2D

func _process(delta):
    rotation += PI * delta

Speichern Sie das Skript und kehren Sie zum Editor zurück. Sie sollten jetzt sehen, wie Ihr Objekt rotiert. Wenn Sie das Spiel ausführen, rotiert es ebenfalls.

../../_images/rotating_in_editor.gif

Bemerkung

Wenn Sie die Änderungen nicht sehen, laden Sie die Szene neu (schließen Sie sie und öffnen sie erneut).

Wählen wir nun aus, welcher Code wann ausgeführt wird. Ändern Sie Ihre _process()-Funktion so ab:

func _process(delta):
    if Engine.is_editor_hint():
        rotation += PI * delta
    else:
        rotation -= PI * delta

Speichern Sie das Skript. Jetzt dreht sich das Objekt im Editor im Uhrzeigersinn, aber wenn Sie das Spiel ausführen, dreht es sich gegen den Uhrzeigersinn.

Variablen bearbeiten

Fügen Sie dem Skript eine variable Geschwindigkeit hinzu und exportieren Sie sie. Um die Geschwindigkeit zu aktualisieren und auch den Drehwinkel zurückzusetzen, fügen Sie einen Setter set(new_speed) hinzu, der mit der Eingabe vom Inspektor ausgeführt wird. Modifizieren Sie _process(), um die Rotationsgeschwindigkeit einzubeziehen.

@tool
extends Sprite2D


@export var speed = 1:
    # Update speed and reset the rotation.
    set(new_speed):
        speed = new_speed
        rotation = 0


func _process(delta):
    rotation += PI * delta * speed

Bemerkung

Code von anderen Nodes kann nicht im Editor ausgeführt werden. Ihr Zugriff auf andere Nodes ist eingeschränkt. Sie können auf den Baum und die Nodes sowie deren Default-Propertys zugreifen, aber nicht auf Benutzervariablen. Wenn Sie dies tun wollen, müssen andere Nodes ebenfalls im Editor laufen. Auf Autoloading-Nodes kann im Editor überhaupt nicht zugegriffen werden.

Meldung von Warnungen bei der Node-Konfiguration

Godot verwendet ein Node-Konfigurations-Warnsystem, um Benutzer vor falsch konfigurierten Nodes zu warnen. Wenn ein Node nicht korrekt konfiguriert ist, erscheint ein gelbes Warnzeichen neben dem Namen des Nodes im Scene-Dock. Wenn Sie mit dem Mauszeiger über das Symbol fahren oder darauf klicken, wird eine Warnmeldung eingeblendet. Sie können diese Funktion in Ihren Skripten verwenden, um Ihnen und Ihrem Team zu helfen, Fehler beim Einrichten von Szenen zu vermeiden.

Wenn Sie Node-Konfigurations-Warnungen verwenden, müssen Sie update_configuration_warnings aufrufen, wenn sich ein Wert ändert, der die Warnung beeinflussen oder entfernen soll. Standardmäßig wird die Warnung nur beim Schließen und erneuten Öffnen der Szene aktualisiert.

# Use setters to update the configuration warning automatically.
@export var title = "":
    set(p_title):
        if p_title != title:
            title = p_title
            update_configuration_warnings()

@export var description = "":
    set(p_description):
        if p_description != description:
            description = p_description
            update_configuration_warnings()


func _get_configuration_warnings():
    var warnings = []

    if title == "":
        warnings.append("Please set `title` to a non-empty value.")

    if description.length() >= 100:
        warnings.append("`description` should be less than 100 characters long.")

    # Returning an empty array means "no warning".
    return warnings

Ausführen von Einmal-Skripten mit EditorScript

Manchmal müssen Sie einen Code nur einmal ausführen, um eine bestimmte Aufgabe zu automatisieren, die im Editor nicht sofort verfügbar ist. Einige Beispiele könnten sein:

  • Verwenden Sie den Editor als Spielwiese für GDScript- oder C#-Skripte, ohne ein Projekt ausführen zu müssen. Die print() Ausgabe wird im Ausgabefenster des Editors angezeigt.

  • Skalieren Sie alle Lichtquellen-Nodes in der aktuell bearbeiteten Szene, da Sie bemerkt haben, dass Ihr Level am Ende zu dunkel oder zu hell aussieht, nachdem Sie die Lichter an den gewünschten Stellen platziert haben.

  • Ersetzen Sie Nodes, die durch Kopieren eingefügt wurden, durch Szeneninstanzen, damit sie später leichter geändert werden können.

Dies ist in Godot durch die Erweiterung EditorScript in einem Skript möglich. Dies ermöglicht es, einzelne Skripte im Editor auszuführen, ohne ein Editor-Plugin erstellen zu müssen.

Um ein EditorScript zu erstellen, klicken Sie mit der rechten Maustaste auf einen Ordner oder einen leeren Bereich im Dateisystem-Dock und wählen Sie Neu > Skript.... Klicken Sie im Dialogfenster für die Skripterstellung auf das Baumsymbol, um ein Objekt auszuwählen, das Sie erweitern möchten (oder geben Sie EditorScript direkt in das Feld auf der linken Seite ein, wobei die Groß- und Kleinschreibung beachtet werden muss):

Erstellen eines Editor-Skripts im Dialogfeld "Skript-Editor erstellen

Erstellen eines Editor-Skripts im Dialogfeld "Skript-Editor erstellen

Dadurch wird automatisch eine Skriptvorlage ausgewählt, die für EditorScripts geeignet ist und bereits eine _run() Methode enthält:

@tool
extends EditorScript

# Called when the script is executed (using File -> Run in Script Editor).
func _run():
    pass

Diese _run()-Methode wird ausgeführt, wenn Sie Datei > Ausführen oder das Tastaturkürzel Strg + Umschalt + X verwenden, während das EditorScript das aktuell geöffnete Skript im Skript-Editor ist. Dieses Tastaturkürzel ist nur wirksam, wenn der Skript-Editor gerade fokussiert ist.

Skripte, die EditorScript erweitern, müssen @tool-Skripte sein, um zu funktionieren.

Warnung

EditorScripts haben keine Rückgängig-/Wiederherstellen-Funktion, also sichern Sie Ihre Szene, bevor Sie ein Skript ausführen, wenn das Skript Daten verändern soll.

Um auf Nodes in der aktuell bearbeiteten Szene zuzugreifen, verwenden Sie die Methode EditorScript.get_scene, die den Root-Node der aktuell bearbeiteten Szene zurückgibt. Hier ist ein Beispiel, das rekursiv alle Nodes in der aktuell bearbeiteten Szene abruft und den Bereich aller OmniLight3D Nodes verdoppelt:

@tool
extends EditorScript

func _run():
    for node in get_all_children(get_scene()):
        if node is OmniLight3D:
            # Don't operate on instanced subscene children, as changes are lost
            # when reloading the scene.
            # See the "Instancing scenes" section below for a description of `owner`.
            var is_instanced_subscene_child = node != get_scene() and node.owner != get_scene()
            if not is_instanced_subscene_child:
                node.omni_range *= 2.0

# This function is recursive: it calls itself to get lower levels of child nodes as needed.
# `children_acc` is the accumulator parameter that allows this function to work.
# It should be left to its default value when you call this function directly.
func get_all_children(in_node, children_acc = []):
    children_acc.push_back(in_node)
    for child in in_node.get_children():
        children_acc = get_all_children(child, children_acc)

    return children_acc

Tipp

Sie können die aktuell bearbeitete Szene im oberen Bereich des Editors ändern, auch wenn die Skriptansicht geöffnet ist. Dies wirkt sich auf den Rückgabewert von EditorScript.get_scene aus. Stellen Sie also sicher, dass Sie die Szene ausgewählt haben, die Sie bearbeiten wollen, bevor Sie das Skript ausführen.

Instanziierung von Szenen

Sie können gepackte Szenen ganz normal instanziieren und sie zu der gerade im Editor geöffneten Szene hinzufügen. Standardmäßig sind Nodes oder Szenen, die mit Node.add_child(node) hinzugefügt werden, nicht im Szenenbaum-Dock sichtbar und werden nicht auf der Festplatte gespeichert. Wenn Sie möchten, dass der Node oder die Szene im Szenenbaum sichtbar ist und beim Speichern der Szene auf der Festplatte gespeichert wird, müssen Sie die Property owner des Child-Nodes auf den aktuell bearbeiteten Szenen-Root setzen.

Wenn Sie @tool verwenden:

func _ready():
    var node = Node3D.new()
    add_child(node) # Parent could be any node in the scene

    # The line below is required to make the node visible in the Scene tree dock
    # and persist changes made by the tool script to the saved scene file.
    node.owner = get_tree().edited_scene_root

Wenn Sie EditorScript verwenden:

func _run():
    # `parent` could be any node in the scene.
    var parent = get_scene().get_node("Parent")
    var node = Node3D.new()
    parent.add_child(node)

    # The line below is required to make the node visible in the Scene tree dock
    # and persist changes made by the tool script to the saved scene file.
    node.owner = get_scene()

Warnung

Die falsche Verwendung von @tool kann zu vielen Fehlern führen. Es ist ratsam, zuerst den Code so zu schreiben, wie Sie ihn haben wollen, und erst dann das @tool-Schlüsselwort am Anfang hinzuzufügen. Stellen Sie außerdem sicher, dass Sie Code, der im Editor läuft, von Code, der im Spiel läuft, trennen. Auf diese Weise können Sie Bugs leichter finden.