Ressourcen

Nodes und Ressourcen

Bisher haben wir uns auf die Node Klasse in Godot konzentriert, da dies die Klasse ist, die Sie zum Kodieren von Verhalten verwenden. Die meisten Funktionen der Engine sind darauf angewiesen. Ein anderer Datentyp ist genauso wichtig: Resource.

Nodes geben Ihnen Funktionalität: Sie zeichnen Sprites, 3D-Modelle, simulieren Physik, ordnen Benutzeroberflächen usw. an. Ressourcen sind Datencontainer. Sie machen nichts alleine: Stattdessen verwenden Nodes die in Ressourcen enthaltenen Daten.

Alles, was Godot speichert oder von der Festplatte lädt, ist eine Ressource. Sei es eine Szene (eine .tscn- oder eine .scn-Datei), ein Bild, ein Skript ... Hier einige Beispiele für Resource: Texture, Script, Mesh, Animation, AudioStream, Font, Translation.

Wenn die Engine eine Ressource von der Festplatte lädt, wird sie nur einmal geladen. Wenn sich bereits eine Kopie dieser Ressource im Speicher befindet, wird beim erneuten Laden der Ressource jedes Mal dieselbe Kopie zurückgegeben. Da Ressourcen nur Daten enthalten, müssen sie nicht dupliziert werden.

Jedes Objekt, sei es ein Node oder eine Ressource, kann Eigenschaften exportieren. Es gibt viele Arten von Eigenschaften wie String, Integer (Ganzzahl), Vector2 usw., und jeder dieser Typen kann zu einer Ressource werden. Dies bedeutet, dass sowohl Nodes als auch Ressourcen weitere Ressourcen als Eigenschaften enthalten können:

../../_images/nodes_resources.png

Extern im Vergleich zu integriert

Es gibt zwei Möglichkeiten, Ressourcen zu speichern. Diese können sein:

  1. Extern zu einer Szene, die als einzelne Dateien auf der Festplatte gespeichert ist.

  2. Integriert, gespeichert in der .tscn oder .scn Datei, an die sie angehängt sind.

Um genauer zu sein, hier ist eine Texture in einem Sprite Node:

../../_images/spriteprop.png

Wenn Sie auf die Ressourcenvorschau klicken, können Sie die Eigenschaften der Ressource anzeigen und bearbeiten.

../../_images/resourcerobi.png

Die Pfadeigenschaft gibt an, woher die Ressource stammt. In diesem Fall kommt sie von einem PNG-Bild namens robi.png. Wenn die Ressource aus einer solchen Datei stammt, handelt es sich um eine externe Ressource. Wenn Sie den Pfad löschen oder dieser Pfad leer ist, wird sie zu einer integrierten Ressource.

Der Wechsel zwischen integrierten und externen Ressourcen erfolgt beim Speichern der Szene. Wenn Sie im obigen Beispiel den Pfad `"res://robi.png "` löschen und speichern, speichert Godot das Bild in der .tscn Szenen-Datei.

Bemerkung

Selbst wenn Sie eine integrierte Ressource speichern, lädt die Engine bei einer mehrmaligen Instanzierung einer Szene nur eine Kopie davon.

Laden von Ressourcen via Code

Es gibt zwei Möglichkeiten, Ressourcen im Code zu laden. Erstens können Sie jederzeit die Funktion load() verwenden:

func _ready():
        var res = load("res://robi.png") # Godot loads the Resource when it reads the line.
        get_node("sprite").texture = res

Sie können auch preload verwenden, um Ressourcen vorzuladen. Im Gegensatz zu load liest diese Funktion die Datei von der Festplatte und lädt sie erst zur Kompilierzeit. Daher können Sie preload nicht mit einem variablen Pfad aufrufen: Sie müssen eine konstante Zeichenkette (String) verwenden.

func _ready():
        var res = preload("res://robi.png") # Godot loads the resource at compile-time
        get_node("sprite").texture = res

Laden von Szenen

Szenen sind auch Ressourcen, aber es gibt einen Haken. Auf der Festplatte gespeicherte Szenen sind Ressourcen des Typs PackedScene. Die Szene ist in eine Ressource gepackt.

Um eine Instanz der Szene zu erhalten, müssen Sie die Methode PackedScene.instance() verwenden.

func _on_shoot():
        var bullet = preload("res://bullet.tscn").instance()
        add_child(bullet)

Diese Methode erstellt die Nodes in der Hierarchie der Szene, konfiguriert sie und gibt den Stammnode der Szene zurück. Sie können es dann als untergeordnetes Element eines anderen Nodes hinzufügen.

Der Ansatz hat mehrere Vorteile. Da die Funktion PackedScene.instance() ziemlich schnell ist, können Sie neue Feinde, Schüsse, Effekte usw. erstellen, ohne sie jedes Mal erneut von der Festplatte laden zu müssen. Aber denken Sie daran, dass Bilder, Meshes usw. von den Szeneninstanzen immer gemeinsam genutzt werden.

Ressourcen freigeben

Wenn eine Ressource nicht mehr verwendet wird, wird sie automatisch freigegeben. Da in den meisten Fällen Ressourcen in Nodes enthalten sind, gibt die Engine bei der Freigabe eines Nodes alle Ressourcen frei, die ihm gehören, sofern kein anderer Node sie verwendet.

Eigene Ressourcen erstellen

Wie jedes Objekt in Godot können Benutzer auch Ressourcen schreiben. Ressourcenskripte erben die Fähigkeit, frei zwischen Objekteigenschaften und serialisiertem Text oder binären Daten (*.tres, *.res) zu übersetzen. Sie erben auch die Verwaltung des Referenzzählspeichers vom Referenztypen.

Gegenüber alternativen Datenstrukturen, wie JSON-, CSV- oder benutzerdefinierten TXT-Dateien, bietet dies viele entscheidende Vorteile. Benutzer können diese Assets nur als Dictionary (JSON) oder als File zum Analysieren importieren. Was Ressourcen auszeichnet, ist ihre Vererbung von Object, Reference und Resource Funktionen:

  • Sie können Konstanten definieren, sodass Konstanten aus anderen Datenfeldern oder Objekten nicht benötigt werden.

  • Sie können Methoden definieren, einschließlich der Setter/Getter Methoden für Eigenschaften. Dies ermöglicht die Abstraktion und Einkapselung der zugrunde liegenden Daten. Wenn die Struktur des Ressource-Skripts geändert werden muss, muss das Spiel, das die Ressource verwendet, nicht ebenfalls geändert werden.

  • Sie können Signale definieren, sodass Ressourcen Antworten auf Änderungen in den von ihnen verwalteten Daten auslösen können.

  • Sie verfügen über definierte Eigenschaften, sodass Benutzer zu 100% wissen, dass ihre Daten vorhanden sind.

  • Die automatische Serialisierung und Deserialisierung von Ressourcen ist eine integrierte Funktion der Godot Engine. Benutzer müssen keine benutzerdefinierte Logik implementieren, um die Daten einer Ressourcendatei zu importieren oder zu exportieren.

  • Ressourcen können sogar Teilressourcen rekursiv serialisieren, sodass Benutzer noch ausgefeiltere Datenstrukturen entwerfen können.

  • Benutzer können Ressourcen als versionskontrollen-freundliche Textdateien (*. tres) speichern. Beim Exportieren eines Spiels serialisiert Godot Ressourcendateien als Binärdateien (*.res), um die Geschwindigkeit und Komprimierung zu erhöhen.

  • Der Inspektor der Godot Engine rendert die Ressourcendateien sofort. Daher müssen Benutzer häufig keine eigene Logik implementieren, um ihre Daten zu visualisieren oder zu bearbeiten. Doppelklicken Sie dazu auf die Ressourcendatei im Dateisystemdock oder klicken im Inspektor auf das Ordnersymbol und öffnen die Datei im Dialogfeld.

  • Sie können andere Ressourcentypen als nur die Basisressource erweitern.

Godot erleichtert es, im Inspektor benutzerdefinierte Ressourcen zu erstellen.

  1. Erstellen Sie im Inspektor ein einfaches Ressourcenobjekt. Dies kann sogar ein Typ sein, der Ressource ableitet, solange Ihr Skript diesen Typ erweitert.

  2. Stellen Sie die Eigenschaft script im Inspektor als Ihr Skript ein.

Der Inspektor zeigt jetzt die benutzerdefinierten Eigenschaften Ihres Ressourcen-Skripts an. Wenn Sie diese Werte bearbeiten und die Ressource speichern, serialisiert der Inspektor auch die benutzerdefinierten Eigenschaften! Um eine Ressource aus dem Inspektor zu speichern, klicken Sie auf das Menü des Inspektors (oben rechts) und wählen "Speichern" oder "Speichern unter ...".

If the script's language supports script classes, then it streamlines the process. Defining a name for your script alone will add it to the Inspector's creation dialog. This will auto-add your script to the Resource object you create.

Sehen wir uns einige Beispiele an.

# bot_stats.gd
extends Resource
export(int) var health
export(Resource) var sub_resource
export(Array, String) var strings

# Make sure that every parameter has a default value.
# Otherwise, there will be problems with creating and editing
# your resource via the inspector.
func _init(p_health = 0, p_sub_resource = null, p_strings = []):
    health = p_health
    sub_resource = p_sub_resource
    strings = p_strings

# bot.gd
extends KinematicBody

export(Resource) var stats

func _ready():
    # Uses an implicit, duck-typed interface for any 'health'-compatible resources.
    if stats:
        print(stats.health) # Prints '10'.

Bemerkung

Ressourcenskripte ähneln den ScriptableObjects von Unity. Der Inspektor bietet integrierte Unterstützung für benutzerdefinierte Ressourcen an. Auf Wunsch können Benutzer sogar eigene, auf Controls basierende Werkzeugskripte erstellen und diese mit einem EditorPlugin kombinieren, um benutzerdefinierte Visualisierungen und Editoren für ihre Daten zu erstellen.

Die DataTables und CurveTables der Unreal Engine 4 können mit Ressourcenskripten auch leicht neu erstellt werden. DataTables sind ein String, der einer benutzerdefinierten Struktur zugeordnet ist, ähnlich einem Dictionary, das einen String einem sekundären benutzerdefinierten Ressourcenskript zuordnet.

# bot_stats_table.gd
extends Resource

const BotStats = preload("bot_stats.gd")

var data = {
    "GodotBot": BotStats.new(10), # Creates instance with 10 health.
    "DifferentBot": BotStats.new(20) # A different one with 20 health.
}

func _init():
    print(data)

Anstatt nur die Dictionary-Werte einzugeben, können Sie alternativ auch ...

  1. eine Wertetabelle aus einer Kalkulationstabelle importieren und diese Schlüsselwertpaare generieren oder ...

  2. eine Visualisierung im Editor entwerfen und ein einfaches Plugin erstellen, das beim Öffnen dieser Ressourcentypen zum Inspektor hinzugefügt wird.

CurveTables sind dasselbe wie DataTables, außer dass sie einem Array von Float-Werten (Gleitkommawerten) oder einem Ressourcenobjekt, wie Curve/Curve2D zugeordnet sind.

Warnung

Beachten Sie, dass Ressourcendateien (*.tres /*.res) den Pfad des von Ihnen verwendeten Skripts in der Datei speichert. Wenn sie geladen sind, werden sie dieses Skript als Erweiterung ihres Typs abrufen und laden. Das bedeutet, dass der Versuch eine Unterklasse zuzuordnen, d.h. eine innere Klasse eines Skripts (z.B. das Schlüsselwort class 'in GDScript), nicht funktioniert. Godot wird die benutzerdefinierten Eigenschaften der Skriptunterklasse nicht ordnungsgemäß serialisieren.

Im folgenden Beispiel würde Godot das Node-Skript laden, prüfen, dass es Resource nicht erweitert, und dann feststellen, dass das Skript nicht für das Ressourcenobjekt geladen wurde, da die Typen nicht kompatibel sind.

extends Node

class MyResource:
    extends Resource
    export var value = 5

func _ready():
    var my_res = MyResource.new()

    # This will NOT serialize the 'value' property.
    ResourceSaver.save("res://my_res.tres", my_res)