Up to date

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

Benutzerdefinierte Module in C++

Module

Godot ermöglicht das modularen Erweitern der Engine. Neue Module können erstellt und dann aktiviert bzw. deaktiviert werden. Dies ermöglicht das Hinzufügen neuer Enginefunktionen auf jeder Ebene, ohne den Kern zu ändern, die zur Verwendung und Wiederverwendung in verschiedenen Modulen aufgeteilt werden können.

Module befinden sich im Unterverzeichnis modules/ des Buildsystems. Standardmäßig sind Dutzende von Modulen aktiviert, z.B. GDScript (das ja nicht Teil der Basis-Engine ist), die Mono-Runtime, ein Modul für reguläre Ausdrücke und andere. Es können beliebig viele neue Module erstellt und kombiniert werden. Das SCons-Buildsystem kümmert sich transparent darum.

Wofür?

Es wird zwar empfohlen, den größten Teil eines Spiels in Skripten zu schreiben (da dies eine enorme Zeitersparnis bedeutet), es ist jedoch durchaus möglich, stattdessen C++ zu verwenden. Das Hinzufügen von C++-Modulen kann in den folgenden Szenarien hilfreich sein:

  • Binden einer externen Bibliothek an Godot (wie PhysX, FMOD usw.).

  • Optimieren kritischer Teile eines Spiels.

  • Hinzufügen neuer Funktionen zur Engine oder zum Editor.

  • Portierung eines bestehenden Spiels nach Godot.

  • Schreiben eines ganz neuen Spiels in C++, weil Sie ohne C++ nicht leben können.

Neues Modul erstellen

Bevor Sie ein Modul erstellen, laden Sie den Quellcode von Godot herunter und kompilieren Sie ihn.

Um ein neues Modul zu erstellen, müssen Sie zunächst ein Verzeichnis in modules/ erstellen. Wenn Sie das Modul separat warten möchten, können Sie ein anderes Repository in Module auschecken und verwenden.

Das Beispielmodul wird "summator" heißen (godot/modules/summator). Darin werden wir eine Summierer-Klasse erstellen:

/* summator.h */

#ifndef SUMMATOR_H
#define SUMMATOR_H

#include "core/object/ref_counted.h"

class Summator : public RefCounted {
    GDCLASS(Summator, RefCounted);

    int count;

protected:
    static void _bind_methods();

public:
    void add(int p_value);
    void reset();
    int get_total() const;

    Summator();
};

#endif // SUMMATOR_H

Und hier die cpp Datei.

/* summator.cpp */

#include "summator.h"

void Summator::add(int p_value) {
    count += p_value;
}

void Summator::reset() {
    count = 0;
}

int Summator::get_total() const {
    return count;
}

void Summator::_bind_methods() {
    ClassDB::bind_method(D_METHOD("add", "value"), &Summator::add);
    ClassDB::bind_method(D_METHOD("reset"), &Summator::reset);
    ClassDB::bind_method(D_METHOD("get_total"), &Summator::get_total);
}

Summator::Summator() {
    count = 0;
}

Dann muss die neue Klasse irgendwie registriert werden, sodass zwei weitere Dateien erstellt werden müssen:

register_types.h
register_types.cpp

Wichtig

Diese Dateien müssen sich im obersten Ordner Ihres Moduls befinden (neben Ihren Dateien SCsub und config.py), damit das Modul ordnungsgemäß registriert werden kann.

Diese Dateien sollten Folgendes enthalten:

/* register_types.h */

#include "modules/register_module_types.h"

void initialize_summator_module(ModuleInitializationLevel p_level);
void uninitialize_summator_module(ModuleInitializationLevel p_level);
/* yes, the word in the middle must be the same as the module folder name */
/* register_types.cpp */

#include "register_types.h"

#include "core/object/class_db.h"
#include "summator.h"

void initialize_summator_module(ModuleInitializationLevel p_level) {
    if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
            return;
    }
    ClassDB::register_class<Summator>();
}

void uninitialize_summator_module(ModuleInitializationLevel p_level) {
    if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
            return;
    }
   // Nothing to do here in this example.
}

Als nächstes müssen wir eine SCsub Datei erstellen, damit das Buildsystem dieses Modul kompiliert:

# SCsub

Import('env')

env.add_source_files(env.modules_sources, "*.cpp") # Add all cpp files to the build

Bei mehreren Quellen können Sie jede Datei auch einzeln zu einer Python-String-Liste hinzufügen:

src_list = ["summator.cpp", "other.cpp", "etc.cpp"]
env.add_source_files(env.modules_sources, src_list)

Dies erlaubt leistungsstarke Möglichkeiten mit Python, die Dateiliste mithilfe von Schleifen und logischen Anweisungen zu erstellen. Schauen Sie sich einige der Module an, die standardmäßig mit Godot geliefert werden.

Um Include-Verzeichnisse hinzuzufügen, die der Compiler anzeigen kann, können Sie sie an die Pfade der Umgebungvariable anhängen:

env.Append(CPPPATH=["mylib/include"]) # this is a relative path
env.Append(CPPPATH=["#myotherlib/include"]) # this is an 'absolute' path

Wenn Sie beim Bauen Ihres Moduls eigene Compilerflags hinzufügen wollen, müssen Sie zuerst env klonen, damit diese Flags nicht zum gesamten Godot-Build hinzugefügt werden (was zu Fehlern führen kann). Beispiel SCsub mit eigenen Flags:

# SCsub

Import('env')

module_env = env.Clone()
module_env.add_source_files(env.modules_sources, "*.cpp")
# Append CCFLAGS flags for both C and C++ code.
module_env.Append(CCFLAGS=['-O2'])
# If you need to, you can:
# - Append CFLAGS for C code only.
# - Append CXXFLAGS for C++ code only.

Und schließlich die Konfigurationsdatei für das Modul, ein Python-Skript, das den Namen config.py tragen muss:

# config.py

def can_build(env, platform):
    return True

def configure(env):
    pass

Das Modul wird gefragt, ob es für die jeweilige Plattform in Ordnung ist, zu bauen (in diesem Fall bedeutet True, dass es für jede Plattform erstellt wird).

Und das war's, hoffentlich war es nicht zu komplex. Ihr Modul sollte folgendermaßen aussehen:

godot/modules/summator/config.py
godot/modules/summator/summator.h
godot/modules/summator/summator.cpp
godot/modules/summator/register_types.h
godot/modules/summator/register_types.cpp
godot/modules/summator/SCsub

Sie können es dann zippen und das Modul mit allen anderen teilen. Beim Erstellen für jede Plattform (Anweisungen in den vorherigen Abschnitten) wird Ihr Modul einbezogen.

Bemerkung

In C++-Modulen gibt es eine Parametergrenze von 5 für Dinge wie Unterklassen. Dies kann durch Einfügen der Header-Datei core/method_bind_ext.gen.inc auf 13 erhöht werden.

Das Modul verwenden

Sie können Ihr neu erstelltes Modul jetzt in jedem Skript verwenden:

var s = Summator.new()
s.add(10)
s.add(20)
s.add(30)
print(s.get_total())
s.reset()

Die Ausgabe wird 60 sein.

Siehe auch

Das vorherige Summator-Beispiel eignet sich hervorragend für kleine, benutzerdefinierte Module. Was ist jedoch, wenn Sie eine größere externe Bibliothek verwenden möchten? Weitere Informationen zum Binden an externe Bibliotheken finden Sie unter Binden an externe Bibliotheken.

Warnung

Wenn auf Ihr Modul vom laufenden Projekt aus zugegriffen werden soll (nicht nur vom Editor), müssen Sie auch jede Exportvorlage, die Sie verwenden möchten, neu kompilieren und dann in jeder Exportvoreinstellung den Pfad zur benutzerdefinierten Vorlage angeben. Andernfalls werden beim Ausführen des Projekts Fehler angezeigt, da das Modul nicht in der Exportvorlage kompiliert ist. Weitere Informationen finden Sie auf den Seiten Kompilieren.

Ein Modul extern kompilieren

Beim Kompilieren eines Moduls wird der Quellcode des Moduls direkt in das Verzeichnis modules/ der Engine verschoben. Dies ist zwar die einfachste Methode zum Kompilieren eines Moduls, es gibt jedoch mehrere Gründe, warum dies möglicherweise nicht praktikabel ist:

  1. Sie müssen Modul-Quellcode jedes Mal manuell kopieren, wenn Sie die Engine mit oder ohne Modul kompilieren möchten, oder zusätzliche Schritte ausführen, um ein Modul während der Kompilierung mit einer Erstellungsoption ähnlich module_summator_enabled = no manuell zu deaktivieren. Das Erstellen symbolischer Links kann ebenfalls eine Lösung sein. Möglicherweise müssen Sie jedoch zusätzlich Betriebssystembeschränkungen überwinden, z.B. die Berechtigung für symbolische Links, wenn Sie dies über ein Skript tun.

  2. Abhängig davon, ob Sie mit dem Quellcode der Engine arbeiten müssen, ändern die direkt zu modules/ hinzugefügten Moduldateien den Arbeitsbaum so weit, dass sich die Verwendung eines VCS (wie git) als umständlich erweist, denn Sie müssen sicherstellen, dass nur der Code mit Bezug auf die Engine durch Filtern von Änderungen committed wird.

Wenn Sie also der Meinung sind, dass die unabhängige Struktur benutzerdefinierter Module benötigt wird, nehmen Sie unser "Summator"-Modul und verschieben Sie es in das übergeordnete Verzeichnis der Engine:

mkdir ../modules
mv modules/summator ../modules

Kompilieren Sie die Engine mit unserem Modul, indem Sie die Build-Option custom_modules bereitstellen, die eine durch Kommas getrennte Liste von Verzeichnispfaden akzeptiert, die benutzerdefinierte C++-Module enthalten, ähnlich wie im Folgenden:

scons custom_modules=../modules

Das Buildsystem erkennt alle Module im Verzeichnis ../modules und kompiliert sie entsprechend, einschließlich unseres "Summator" -Moduls.

Warnung

Jeder an custom_modules übergebene Pfad wird intern in einen absoluten Pfad konvertiert, um zwischen benutzerdefinierten und integrierten Modulen zu unterscheiden. Dies bedeutet, dass Dinge wie das Generieren der Moduldokumentation möglicherweise von einer bestimmten Pfadstruktur auf Ihrem Computer abhängen.

Initialisierung der Modultypen anpassen

Module können während der Laufzeit mit anderen Built-in Engine-Klassen interagieren und sogar die Art und Weise beeinflussen, wie Core-Typen initialisiert werden. Bisher haben wir register_summator_types verwendet, um Modulklassen in der Engine verfügbar zu machen.

Eine grobe Reihenfolge der Engine-Einstellung kann als Liste der folgenden Typregistrierungsmethoden zusammengefasst werden:

preregister_module_types();
preregister_server_types();
register_core_singletons();
register_server_types();
register_scene_types();
EditorNode::register_editor_types();
register_platform_apis();
register_module_types();
initialize_physics();
initialize_navigation_server();
register_server_singletons();
register_driver_types();
ScriptServer::init_languages();

Unsere Summator-Klasse wird während des register_module_types()-Aufrufs initialisiert. Stellen Sie sich vor, dass wir eine allgemeine Modul-Laufzeit-Abhängigkeit erfüllen müssen (wie Singletons), oder dass wir bestehende Methoden-Callbacks der Engine überschreiben müssen, bevor sie von der Engine selbst zugewiesen werden können. In diesem Fall wollen wir sicherstellen, dass unsere Modulklassen vor jedem anderen Built-in-Typ registriert werden.

Hier können wir eine optionale preregister_summator_types()-Methode definieren, die während der preregister_module_types()-Einrichtungsphase der Engine vor allem anderen aufgerufen wird.

Wir müssen nun diese Methode in die register_types-Header- und Quelldateien einfügen:

/* register_types.h */

#define MODULE_SUMMATOR_HAS_PREREGISTER
void preregister_summator_types();

void register_summator_types();
void unregister_summator_types();

Bemerkung

Im Gegensatz zu anderen Register-Methoden müssen wir MODULE_SUMMATOR_HAS_PREREGISTER explizit definieren, um dem Buildsystem mitzuteilen, welche relevanten Methodenaufrufe es zur Kompilierzeit einbinden soll. Der Name des Moduls muss ebenfalls in Großbuchstaben umgewandelt werden.

/* register_types.cpp */

#include "register_types.h"

#include "core/object/class_db.h"
#include "summator.h"

void preregister_summator_types() {
    // Called before any other core types are registered.
    // Nothing to do here in this example.
}

void register_summator_types() {
    ClassDB::register_class<Summator>();
}

void unregister_summator_types() {
   // Nothing to do here in this example.
}

Verbesserung des Buildsystems für die Entwicklung

Warnung

Diese Unterstützung für gemeinsam genutzte Bibliotheken ist nicht dafür gedacht, ein Modul an andere Benutzer weiterzugeben, ohne die Engine neu zu kompilieren. Verwenden Sie zu diesem Zweck stattdessen eine GDExtension.

Bisher haben wir eine saubere SCsub definiert, die es uns ermöglicht, die Quellen unseres neuen Moduls als Teil der Godot-Binärdatei hinzuzufügen.

Dieser statische Ansatz ist gut, wenn wir eine Release-Version unseres Spiels erstellen wollen, da wir alle Module in einer einzigen Binärdatei haben wollen.

Der Nachteil ist jedoch, dass jede einzelne Änderung eine vollständige Neukompilierung des Spiels erfordert. Auch wenn SCons in der Lage ist, nur die geänderte Datei zu erkennen und neu zu kompilieren, dauert es lange, solche Dateien zu finden und schließlich die endgültige Binärdatei zu linken.

Die Lösung, um solche Kosten zu vermeiden, besteht darin, ein eigenes Modul als Shared Library zu erstellen, die beim Starten der Binärdatei unseres Spiels dynamisch geladen wird.

# SCsub

Import('env')

sources = [
    "register_types.cpp",
    "summator.cpp"
]

# First, create a custom env for the shared library.
module_env = env.Clone()

# Position-independent code is required for a shared library.
module_env.Append(CCFLAGS=['-fPIC'])

# Don't inject Godot's dependencies into our shared library.
module_env['LIBS'] = []

# Define the shared library. By default, it would be built in the module's
# folder, however it's better to output it into `bin` next to the
# Godot binary.
shared_lib = module_env.SharedLibrary(target='#bin/summator', source=sources)

# Finally, notify the main build environment it now has our shared library
# as a new dependency.

# LIBPATH and LIBS need to be set on the real "env" (not the clone)
# to link the specified libraries to the Godot executable.

env.Append(LIBPATH=['#bin'])

# SCons wants the name of the library with it custom suffixes
# (e.g. ".linuxbsd.tools.64") but without the final ".so".
shared_lib_shim = shared_lib[0].name.rsplit('.', 1)[0]
env.Append(LIBS=[shared_lib_shim])

Einmal kompiliert, sollten wir ein bin Verzeichnis haben, das sowohl die godot*-Binärdatei als auch unseren libsummator*.so enthält. Da sich die .so jedoch nicht in einem Standardverzeichnis befindet (wie /usr/lib), müssen wir unserer Binärdatei helfen, sie zur Laufzeit mit der Umgebungsvariablen LD_LIBRARY_PATH zu finden:

export LD_LIBRARY_PATH="$PWD/bin/"
./bin/godot*

Bemerkung

Sie müssen die Umgebungsvariable exportieren. Andernfalls werden Sie nicht in der Lage sein, Ihr Projekt mit dem Editor zu starten.

Darüber hinaus wäre es schön, wenn wir auswählen könnten, ob unser Modul als Shared Library (für die Entwicklung) oder als Teil der Godot-Binärdatei (für die Veröffentlichung) kompiliert werden soll. Um dies zu tun, können wir ein eigenes Flag definieren, das mit dem Befehl ARGUMENT an SCons übergeben wird:

# SCsub

Import('env')

sources = [
    "register_types.cpp",
    "summator.cpp"
]

module_env = env.Clone()
module_env.Append(CCFLAGS=['-O2'])

if ARGUMENTS.get('summator_shared', 'no') == 'yes':
    # Shared lib compilation
    module_env.Append(CCFLAGS=['-fPIC'])
    module_env['LIBS'] = []
    shared_lib = module_env.SharedLibrary(target='#bin/summator', source=sources)
    shared_lib_shim = shared_lib[0].name.rsplit('.', 1)[0]
    env.Append(LIBS=[shared_lib_shim])
    env.Append(LIBPATH=['#bin'])
else:
    # Static compilation
    module_env.add_source_files(env.modules_sources, sources)

Standardmäßig erstellt der Befehl scons unser Modul als Teil von Godots Binärdatei und als gemeinsam genutzte Bibliothek, wenn summator_shared = yes übergeben wird.

Schließlich können Sie den Build sogar noch weiter beschleunigen, indem Sie Ihr freigegebenes Modul im Befehl SCons explizit als Target angeben:

scons summator_shared=yes platform=linuxbsd bin/libsummator.linuxbsd.tools.64.so

Benutzerdefinierte Dokumentation schreiben

Das Schreiben von Dokumentation mag wie eine langweilige Aufgabe erscheinen, aber es wird dringend empfohlen, Ihr neu erstelltes Modul zu dokumentieren, damit die Benutzer es leichter nutzen können. Ganz zu schweigen davon, dass der Code, den Sie vor einem Jahr geschrieben haben, möglicherweise nicht mehr von dem Code zu unterscheiden ist, den jemand anderes geschrieben hat - seien Sie also nett zu Ihrem zukünftigen Ich!

Es gibt mehrere Schritte, um benutzerdefinierte Dokumente für das Modul einzurichten:

  1. Erstellen Sie ein neues Verzeichnis im Stammverzeichnis des Moduls. Der Verzeichnisname kann beliebig sein, aber wir werden in diesem Abschnitt den Namen doc_classes verwenden.

  2. Jetzt müssen wir config.py bearbeiten und den folgenden Schnipsel hinzufügen:

    def get_doc_path():
        return "doc_classes"
    
    def get_doc_classes():
        return [
            "Summator",
        ]
    

Die Funktion get_doc_path() wird vom Buildsystem verwendet, um den Speicherort der Dokumente zu bestimmen. In diesem Fall befinden sie sich im Verzeichnis modules/summator/doc_classes. Wenn Sie dies nicht definieren, wird der Dokumentpfad für Ihr Modul auf das Hauptverzeichnis doc/classes zurückgesetzt.

Die Methode get_doc_classes() ist erforderlich, damit das Buildsystem weiß, welche registrierten Klassen zum Modul gehören. Sie müssen alle Ihre Klassen hier auflisten. Die Klassen, die Sie nicht auflisten, landen im Hauptverzeichnis doc/classes.

Tipp

Sie können Git verwenden, um zu überprüfen, ob Sie einige Ihrer Klassen übersehen haben, indem Sie die nicht getrackten Dateien mit git status überprüfen. Zum Beispiel:

user@host:~/godot$ git status

Beispielausgabe:

Untracked files:
    (use "git add <file>..." to include in what will be committed)

    doc/classes/MyClass2D.xml
    doc/classes/MyClass4D.xml
    doc/classes/MyClass5D.xml
    doc/classes/MyClass6D.xml
    ...
  1. Jetzt können wir die Dokumentation erstellen:

Wir können dies tun, indem wir Godots doctool ausführen, d.h. godot --doctool <Pfad>, wodurch die Engine-API-Referenz auf den angegebenen <Pfad> im XML-Format ausgegeben wird.

In unserem Fall verweisen wir auf das Stammverzeichnis des geklonten Repositorys. Sie können es auf einen anderen Ordner verweisen lassen und einfach die benötigten Dateien kopieren.

Führen Sie den Befehl aus:

user@host:~/godot$ ./bin/<godot_binary> --doctool .

Wenn Sie nun zum Ordner godot/modules/summator/doc_classes gehen, werden Sie sehen, dass er eine Summator.xml-Datei oder andere Klassen enthält, auf die Sie in Ihren get_doc_classes Funktion verwiesen haben.

Bearbeiten Sie die Datei(en) gemäß Einführung in die Klassenreferenz und kompilieren Sie die Engine neu.

Sobald der Kompilierungsprozess abgeschlossen ist, können Sie auf die Dokumente im integrierten Dokumentationssystem der Engine zugreifen.

Um die Dokumentation auf dem neuesten Stand zu halten, müssen Sie lediglich eine der XML-Dateien ändern und die Engine von nun an neu kompilieren.

Wenn Sie die API Ihres Moduls ändern, können Sie die Dokumente auch erneut extrahieren. Sie enthalten die zuvor hinzugefügten Elemente. Wenn Sie auf Ihren Godot-Ordner verweisen, stellen Sie sicher, dass Sie keine Arbeit verlieren, indem Sie ältere Dokumente aus einer älteren Engine extrahieren, die auf den neueren basiert.

Beachten Sie, dass möglicherweise ein Fehler auftritt, der dem folgenden ähnelt, wenn Sie keine Schreibzugriffsrechte für Ihren angegebenen <Pfad> haben:

ERROR: Can't write doc file: docs/doc/classes/@GDScript.xml
   At: editor/doc/doc_data.cpp:956

Schreiben von benutzerdefinierten Unit-Tests

Es ist möglich, in sich geschlossene Unit-Tests als Teil eines C++-Moduls zu schreiben. Wenn Sie mit dem Unit-Testing-Prozess in Godot noch nicht vertraut sind, lesen Sie bitte Unit-Tests.

Das Verfahren ist wie folgt:

  1. Erstellen Sie ein neues Verzeichnis mit dem Namen tests/ unter dem Stammverzeichnis Ihres Moduls:

cd modules/summator
mkdir tests
cd tests
  1. Erstellen Sie eine neue Testsuite: test_summator.h. Der Header muss mit dem Präfix test_ versehen werden, damit das Buildsystem ihn aufsammeln und als Teil der tests/test_main.cpp einbinden kann, in der die Tests ausgeführt werden.

  2. Schreiben Sie einige Test-Cases. Hier ist ein Beispiel:

// test_summator.h
#ifndef TEST_SUMMATOR_H
#define TEST_SUMMATOR_H

#include "tests/test_macros.h"

#include "modules/summator/summator.h"

namespace TestSummator {

TEST_CASE("[Modules][Summator] Adding numbers") {
    Ref<Summator> s = memnew(Summator);
    CHECK(s->get_total() == 0);

    s->add(10);
    CHECK(s->get_total() == 10);

    s->add(20);
    CHECK(s->get_total() == 30);

    s->add(30);
    CHECK(s->get_total() == 60);

    s->reset();
    CHECK(s->get_total() == 0);
}

} // namespace TestSummator

#endif // TEST_SUMMATOR_H
  1. Kompilieren Sie die Engine mit scons tests=yes, und führen Sie die Tests mit dem folgenden Befehl aus:

./bin/<godot_binary> --test --source-file="*test_summator*" --success

Sie sollten jetzt die durchlaufenen Assertions sehen.

Hinzufügen von benutzerdefinierten Editor-Symbolen

Ähnlich wie Sie eine in sich geschlossene Dokumentation innerhalb eines Moduls schreiben, können Sie auch eigene benutzerdefinierte Icons erstellen, damit Klassen im Editor angezeigt werden.

Informationen zum eigentlichen Erstellen von Editor-Icons für die Integration in die Engine finden Sie zuerst unter Editor-Icons.

Führen Sie die folgenden Schritte aus, nachdem Sie Ihre Icons erstellt haben:

  1. Erstellen Sie ein neues Verzeichnis im Stammverzeichnis des Moduls mit dem Namen icons. Dies ist der Standardpfad für das Modul, um nach den Editor-Icons des Moduls zu suchen.

  2. Verschieben Sie Ihre neu erstellten svg-Icons (optimiert oder nicht) in diesen Ordner.

  3. Kompilieren Sie die Engine neu und führen Sie den Editor aus. Jetzt werden die Icons gegebenenfalls in der Benutzeroberfläche des Editors angezeigt.

Wenn Sie Ihre Icons an einer anderen Stelle in Ihrem Modul speichern möchten, fügen Sie den folgenden Codeausschnitt zu config.py hinzu, um den Standardpfad zu überschreiben:

def get_icons_path():
    return "path/to/icons"

Zum Abschluss

Nicht vergessen:

  • Verwenden Sie das Makro GDCLASS für die Vererbung, damit Godot es einschließen kann.

  • Verwenden Sie _bind_methods, um Ihre Funktionen an Skripte zu binden, damit sie als Callbacks für Signale arbeiten können.

  • Vermeiden Sie Mehrfachvererbung für Klassen, die für Godot sichtbar sind, da GDCLASS dies nicht unterstützt. Sie können dennoch Mehrfachvererbung in Ihren eigenen Klassen verwenden, solange diese für die Godot-Skript-API sichtbar sind.

Aber das ist noch nicht alles - je nachdem, was Sie tun, werden Sie mit einigen (hoffentlich positiven) Überraschungen begrüßt.

  • Wenn Sie von Node (oder einem abgeleiteten Nodetyp wie Sprite2D) erben, wird Ihre neue Klasse im Editor im Vererbungsbaum im Dialogfeld "Node hinzufügen" angezeigt.

  • Wenn Sie von Resource erben, wird es in der Ressourcenliste angezeigt, und alle offengelegten Propertys können beim Speichern/Laden serialisiert werden.

  • Mit derselben Logik können Sie den Editor und fast jeden Bereich der Engine erweitern.