Up to date

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

Kerntypen

Godot hat eine Vielzahl von Klassen und Vorlagen, aus denen sich sein Kern zusammensetzt, und alles baut darauf auf.

Diese Referenz wird versuchen, sie aufzulisten, um sie besser zu verstehen.

Definitionen

Godot verwendet die Standard-C99-Datentypen wie uint8_t, uint32_t, int64_t usw., die heutzutage von jedem Compiler unterstützt werden. Das Rad hier neu zu erfinden wäre keine Freude, da es das Lesen von Code erschwert.

Im Allgemeinen wird nicht darauf geachtet, den effizientesten Datentyp für eine bestimmte Aufgabe zu verwenden, es sei denn, Sie verwenden große Strukturen oder Arrays. int wird im größten Teil des Codes verwendet, sofern nicht anderweits erforderlich. Dies geschieht, weil heutzutage jedes Gerät mindestens einen 32-Bit-Bus hat und solche Operationen in einem Zyklus ausführen kann. Es macht Code auch lesbarer.

Für Dateien oder Speichergrößen wird size_t verwendet, das garantiert 64 Bit hat.

Für Unicode-Zeichen wird CharType anstelle von wchar_t verwendet, da viele Architekturen ein 4 Bytes langes wchar_t haben, wo 2 Bytes erwünscht sein könnten. Standardmäßig wurde dies jedoch nicht erzwungen und CharType wird direkt wchar_t zugeordnet.

Referenzen:

Speichermodell

Der PC ist eine wunderbare Architektur. Computer verfügen häufig über Gigabytes an RAM, Terabytes an Speicher und Gigahertz an CPU. Wenn eine Anwendung mehr Ressourcen benötigt, lagert das Betriebssystem die inaktiven Anwendungen aus. Andere Architekturen (wie Mobilgeräte oder Konsolen) sind im Allgemeinen eingeschränkter.

Das gebräuchlichste Speichermodell ist der Heap, bei dem eine Anwendung einen Speicherbereich anfordert und das zugrunde liegende Betriebssystem versucht, ihn irgendwo anzupassen und zurückzugeben. Dies funktioniert oft am besten und ist flexibel, aber im Laufe der Zeit und bei Falschanwendung kann dies zu einer Segmentierung führen.

Durch die Segmentierung werden langsam Löcher erzeugt, die für die meisten gängigen Allokationen zu klein sind, sodass Speicherplatz verschwendet wird. Es gibt viel Literatur über Heap und Segmentierung, daher wird auf dieses Thema hier nicht weiter eingegangen. Moderne Betriebssysteme verwenden Paged Memory, wodurch das Segmentierungsproblem zwar gemindert, aber nicht gelöst wird.

Viele Studien und Tests haben jedoch gezeigt, dass die Segmentierung bei ausreichendem Speicherplatz kein Problem darstellt, wenn die maximale Allokationsgröße unter einem bestimmten Schwellenwert liegt, der im Verhältnis zur maximalen Heap-Größe und dem Anteil des ungenutzten Speichers steht, da er konstant bleibt. Mit anderen Worten: Lassen Sie 10-20% Ihres Speichers frei und führen Sie alle kleinen Allokationen durch, und alles ist gut.

Godot stellt sicher, dass alle Objekte, die dynamisch allokiert werden können, klein sind (höchstens einige KB). Aber was passiert, wenn eine Allokation zu groß ist (z.B. ein Bild oder eine Mesh-Geometrie oder ein großes Array)? In diesem Fall hat Godot die Möglichkeit, einen dynamischen Speicherpool zu verwenden. Dieser Speicher muss gelockt sein, damit auf ihn zugegriffen werden kann. Wenn einer Allokation der Speicherplatz ausgeht, wird der Pool bei Bedarf neu angeordnet und komprimiert. Abhängig von den Anforderungen des Spiels kann der Programmierer die Größe des dynamischen Speicherpools konfigurieren.

Speicher-Allozierung

Godot verfügt über viele Tools zum Tracken der Speichernutzung in einem Spiel, insbesondere während des Debuggens. Aus diesem Grund sollten die regulären C und C++-Bibliotheksaufrufe nicht verwendet werden. Stattdessen werden einige andere bereitgestellt.

Für die Allokation im C-Stil bietet Godot einige Makros:

memalloc()
memrealloc()
memfree()

Diese entsprechen dem üblichen malloc, realloc, free aus der Standard C-Bibliothek.

Für die Allokation im C++-Stil stehen spezielle Makros zur Verfügung:

memnew( Class / Class(args) )
memdelete( instance )

memnew_arr( Class , amount )
memdelete_arr( pointer to array )

die äquivalent zu new, delete, new[] und delete[] sind.

memnew/memdelete verwenden auch ein wenig C++-Magic und benachrichtigen Objekte direkt nach ihrer Erstellung und direkt vor dem Löschen.

Für den dynamischen Speicher wird das PoolVector<>-Template bereitgestellt. PoolVector ist eine Standardvektorklasse und dem Vektor in der C++-Standardbibliothek sehr ähnlich. Verwenden Sie Folgendes, um einen PoolVector-Buffer zu erstellen:

PoolVector<int> data;

Auf PoolVector kann mit dem Operator [] zugegriffen werden. Hierzu gibt es einige Helfer:

PoolVector<int>::Read r = data.read()
int someint = r[4]
PoolVector<int>::Write w = data.write()
w[4] = 22;

Diese Operationen ermöglichen schnelles Lesen/Schreiben von PoolVectors und halten sie gelockt, bis sie den Gültigkeitsbereich verlassen. PoolVectors sollten jedoch für kleine, dynamische Speicheroperationen verwendet werden, da read() und write() für eine große Anzahl von Zugriffen zu langsam sind.

Referenzen:

Container

Godot bietet auch eine Reihe gängiger Container:

  • Vektor

  • List

  • Set

  • Map

Sie sollen so minimal wie möglich sein, da Templates in C++ oft inlined sind und die Binärgröße sowohl in Debug-Symbolen als auch im Code aufblähen. List, Set und Map können mithilfe von Pointern iteriert werden, etwa so:

for(List<int>::Element *E=somelist.front();E;E=E->next()) {
    print_line(E->get()); // print the element
}

Die Vector<>-Klasse hat auch ein paar nette Features:

  • Sie kopiert beim Schreiben, daher ist das Erstellen von Kopien günstig, solange sie nicht geändert werden.

  • Sie unterstützt Multithreading durch Verwendung atomarer Operationen am Reference Counter.

Referenzen:

String

Godot bietet auch eine String-Klasse. Diese Klasse bietet eine Vielzahl von Features, vollständige Unicode-Unterstützung für alle Funktionen (z.B. Großschreibungs-Operationen) und das Parsen bzw. Extrahieren von utf8 sowie Helfer für die Konvertierung und Visualisierung.

Referenzen:

StringName

StringNames sind wie ein String, sind aber eindeutig. Das Erstellen eines StringName aus einem String führt zu einem eindeutigen internen Pointer für alle gleichen Strings. StringNames sind nützlich um Strings als Bezeichner zu verwenden, da beim Vergleich im Grunde genommen ein Pointer verglichen wird.

Die Erstellung eines StringName (insbesondere eines neuen) ist langsam, der Vergleich jedoch schnell.

Referenzen:

Mathe-Typen

Im Verzeichnis core/math stehen mehrere lineare Mathe-Typen zur Verfügung.

Referenzen:

NodePath

Dies ist ein spezieller Datentyp, mit dem Pfade in einem Szenenbaum gespeichert und schnell referenziert werden.

Referenzen:

RID

RIDs sind Ressourcen-IDs. Server verwenden diese, um auf darin gespeicherte Daten zu verweisen. RIDs sind undurchsichtig, was bedeutet, dass auf verwiesene Daten nicht direkt zugegriffen werden kann. RIDs sind eindeutig, auch für verschiedene Arten von Daten, auf die verwiesen wird.

Referenzen: