Unreal Mass mit DOTS: Zielsetzung von CPU-Cache-Effizienz und paralleler Verarbeitung für flüssige AAA-Spiele
Dieser Bericht vergleicht aus der Perspektive von Spieleentwicklern die Ansätze des datenorientierten Designs (DOD) und der traditionellen objektorientierten Programmierung (OOP) in den Spiel-Engines Unity und Unreal Engine 5. Die Untersuchung zielt darauf ab, die wesentlichen Leistungsergebnisse zu analysieren, insbesondere im Hinblick auf Speicherlayout-Optimierung, CPU-Cache-Nutzung und Multithreading-Unterstützung. Der Bericht geht anhand konkreter Codebeispiele und Integrationsschritte in aktuellen Engine-Versionen auf technische Details ein. Darüber hinaus werden die strategischen Auswirkungen dieser Architekturwahlen für Spiele mit hohem Budget (AAA) für Third-Person-, Open-World- und Mobilplattformen bewertet, inspiriert von Titeln wie Kena: Bridge of Spirits. Jede Behauptung wird anhand der bereitgestellten Quellen belegt.

Grundlegende Paradigmenunterschiede: Logik der Datenspeicherung und Leistungsergebnisse
Der wesentliche Unterschied zwischen dem datenorientierten Design (DOD) und der objektorientierten Programmierung (OOP) basiert darauf, wie Daten als logische Einheiten gruppiert und im Speicher abgelegt werden. Während sich OOP auf Objekte konzentriert, die Daten mit Funktionalität bündeln, zielt DOD darauf ab, den Zugriff auf den Speicher zu optimieren, indem Daten desselben Typs zusammengehalten werden. Diese grundlegende Unterscheidung der Paradigmen ist von entscheidender Bedeutung für die Fähigkeit, das Leistungspotenzial moderner Computerarchitekturen voll auszuschöpfen.
Die objektorientierte Programmierung (OOP) basiert im Allgemeinen auf der Logik „Speichere die Daten im Objekt“. Wenn man sich ein Charakterobjekt vorstellt, verfügt dieses über Eigenschaften, die verschiedene Datentypen wie Position, Gesundheit (Health) und Geschwindigkeit (Velocity) umfassen. Jedes einzelne Charakterobjekt belegt einen eigenen Adressraum im Speicher. Wenn ein komplexes Spiel Hunderte oder Tausende von Charakteren hat, sind diese Objekte zufällig im Speicher verteilt. Wird ein Vorgang wie das Bewegen aller Charaktere in einer Aktualisierungsschleife (Update-Schleife) ausgeführt, muss die CPU separat auf die Positionsdaten jedes einzelnen Charakters zugreifen. In diesem Fall ist es unwahrscheinlich, dass sich die Positionsinformationen und die Gesundheitsinformationen von CharacterA im selben Speicherblock befinden; da es sich um unterschiedliche Objekte handelt, liegen sie an verschiedenen Adressen. Ebenso befinden sich die Positionsinformationen von CharacterB wahrscheinlich ziemlich weit entfernt von den Daten von CharacterA. Dies führt dazu, dass die CPU jedes Mal auf unterschiedliche und nicht nahegelegene Speicherblöcke zugreifen muss, wenn sie Daten aus dem Speicher abrufen muss. Diese Situation erzeugt einen Leistungsengpass, der im Widerspruch zur Struktur moderner CPUs steht. Die plötzlichen Einbrüche und FPS-Abfälle in Spielen wie Kena: Bridge of Spirits sind ein typischer Indikator für Leistungsprobleme, die durch solche OOP-basierten, nicht-cache-freundlichen Speicherzugriffsmuster verursacht werden.
Das datenorientierte Design (DOD) kehrt diese Logik hingegen um. DOD stellt nicht die Objekte in den Mittelpunkt, sondern die Daten, aus denen sie bestehen, und zielt darauf ab, Daten desselben Typs so kompakt und zusammenhängend wie möglich im Speicher zu speichern. Die gängigste und formellste Anwendung dieses Ansatzes ist die Architektur des Entity Component Systems (ECS). ECS definiert komplexe Entitäten als einfache „Entitäten“, fügt das Verhalten und die Eigenschaften dieser Entitäten über unabhängige „Komponenten“ hinzu und verarbeitet sie durch „Systeme“, die diese Komponenten verwenden. Das Fundament dieser Architektur bilden Datenstrukturen wie Structure of Arrays (SoA) oder ähnliche . Im Gegensatz zur AoS-Logik (Array of Structures) bei OOP bezieht sich SoA auf das Erstellen eines separaten Arrays für jeden Datentyp. Beispielsweise werden die Positionsinformationen aller Charaktere in einem einzigen Array (positions[]) gespeichert, die Gesundheitsinformationen aller Charaktere in einem anderen Array (health[]) und die Geschwindigkeitsinformationen aller Charaktere in einem dritten Array (velocity[]), jeweils zusammenhängend. Dank dieser Anordnung erfordert die Aufgabe, die Positionen aller Charaktere gleichzeitig zu aktualisieren, dass die CPU nur einmal einen großen Datenblock lädt. Das zusammenhängende Speicherzugriffsmuster ermöglicht es der CPU, beschleunigte Caches wie L1 und L2 effizient zu nutzen, da beim Laden der ersten Daten auch die benachbarten Daten in den Cache geladen werden und diese Daten wiederholt verwendet werden können. Die ECS-Dokumentation von Unity betont, dass Daten in festen, zusammenhängenden Speicherblöcken, sogenannten Chunks, gespeichert werden und wie gut dies mit den CPU-Cache-Zeilen kompatibel ist. Diese einfache, aber effektive Änderung verbessert die Leistung von Algorithmen, die mit großen Datensätzen arbeiten, dramatisch.
FeatureObjektorientierte Programmierung (OOP)Datenorientiertes Design (DOD/ECS)Logik der Datengruppierung„Speichere die Daten im Objekt“ (AoS – Struct of Array)„Speichere gleiche Daten zusammen“ (SoA – Array of Struct)SpeicherlayoutDaten befinden sich im zufälligen und verteilten SpeicherDaten werden im Speicher zusammenhängend und kompakt abgelegtSpeicherzugriffsmusterVerstreute, kreuzweise Zugriffe sind üblichZusammenhängende, lokale Zugriffe dominierenCache-EffizienzIm Allgemeinen niedrig (hohe Anzahl an Cache-Misses)Im Allgemeinen hoch (hohe Anzahl an Cache-Hits)Architektonische KompositionVererbung (Inheritance) und Abstraktion stehen im MittelpunktFlexible Struktur aus KomponentenTypische AnwendungUnity GameObjects, Unreal ActorsUnity DOTS/Entities, Unreal Mass
Diese grundlegenden Paradigmen haben für moderne Spiel-Engines wie Unity und Unreal Engine 5 unterschiedliche Entwicklungswege eingeschlagen. Während Unity die OOP-basierte GameObject-Architektur beibehalten hat, hat es einen vollständig neuen datenorientierten Stack namens DOTS (Data-Oriented Technology Stack) eingeführt. Dies gibt Entwicklern die Flexibilität, beide Ansätze in verschiedenen Teilen des Projekts gemeinsam zu nutzen. Während beispielsweise die Benutzeroberfläche und einige spezielle Spielmechaniken mit OOP verwaltet werden, können die physikalische Simulation oder die Steuerung einer großen Menge von KI-Einheiten mit DOD durchgeführt werden. Die Kernarchitektur der Unreal Engine 5 ist jedoch durch die UObject-Vererbung tiefgehend auf OOP ausgerichtet. Dennoch hat Unreal auch spezifische Lösungen für Bereiche entwickelt, die eine hohe Leistung erfordern. Am wichtigsten ist hierbei das Mass Entity Framework. Mass ist ein Framework für datenorientierte Berechnungen, das speziell für Szenarien entwickelt wurde, in denen Hunderte oder Tausende von KI-Einheiten gleichzeitig ausgeführt werden. Das Ziel von Mass ist es, die Leistungsgrenzen der Actor/Component-Architektur zu überwinden, und es bietet die Möglichkeit zur Parallelisierung, indem bestimmte Aufgaben (z. B. großflächiges Einheitenmanagement) auf datenorientierte Weise organisiert werden. Darüber hinaus hat sich auch das Chaos-Physiksystem zu datenorientierten Ansätzen entwickelt und enthält Caching-Mechanismen, um Neuberechnungen von Simulationen zu vermeiden. Daher sind beide Engines auf dem Weg, die Flexibilität von OOP und die Leistung von DOD zu vereinen, verfolgen dabei jedoch unterschiedliche Strategien, die sich aus ihren jeweiligen architektonischen Hintergründen ergeben.
Analyse des Speicherlayouts und der CPU-Cache-Effizienz
Die Leistung moderner Spiel-Engines wird durch die Tatsache eingeschränkt, dass die Geschwindigkeit, mit der die CPU Daten aus dem RAM abruft, viel langsamer ist als die Rechengeschwindigkeit. Der Weg, diesen „Von-Neumann-Engpass“ zu überwinden, besteht darin, die extrem schnellen, aber kleinen L1-, L2- und L3-Caches der CPU so effizient wie möglich zu nutzen. Wenn die CPU auf eine Speicheradresse zugreift, liest sie die Daten an dieser Adresse nicht nur aus dem Speicher, sondern zieht sofort auch einige Bytes in der unmittelbaren Umgebung (in der Regel eine 64 Byte große „Cache-Line“) mit in den Cache. Wenn die als Nächstes benötigte Datum in dieser Cache-Line enthalten ist, kann die CPU schnell darauf zugreifen; dieser Zustand wird als „Cache-Hit“ bezeichnet. Andernfalls muss sie einen neuen Datenblock aus dem langsamen RAM laden, was als „Cache-Miss“ bezeichnet wird und einen erheblichen Leistungsengpass darstellt. Das datenorientierte Design (DOD) bietet eine architektonische Lösung, die darauf abzielt, die Cache-Hit-Rate zu erhöhen, indem insbesondere die durch OOP verursachten verstreuten Speicherzugriffsmuster vermieden werden.
Der Ansatz der objektorientierten Programmierung (OOP) führt naturgemäß zu einem verstreuten Speicherlayout. Ein Character-Objekt enthält Mitglieder verschiedener Datentypen wie Position, Gesundheit (health) und Rotation. Jedes einzelne Character-Objekt beginnt mit einer eigenen Adresse im Speicher. Wenn in einer Schleife die Update-Funktion aller Charaktere aufgerufen werden soll, muss die CPU zum Anfang jedes Character-Objekts im Speicher gehen. Die Mitglieder (Daten) dieser Objekte müssen nicht nahe beieinander liegen. Beispielsweise befindet sich das Position-Mitglied von CharacterA und das Health-Mitglied von CharacterB möglicherweise nicht in derselben 64-Byte-Cache-Line. Dies führt dazu, dass die CPU jedes Mal, wenn wir Daten sequenziell verarbeiten möchten, zu unterschiedlichen und weit entfernten Speicheradressen springen muss. Der Übergang zu einer neuen Adresse bedeutet jedes Mal das Verwerfen der vorherigen Cache-Line, was zu einer hohen Rate an Cache-Misses führt. Für mobile Plattformen ist dieser Umstand noch kritischer; mehr Operationen bei geringerem Stromverbrauch durchzuführen, ist ein grundlegender Vorteil für mobile Geräte.
Das datenorientierte Design (DOD) bietet eine direkte Lösung für dieses Problem. Die DOTS-Architektur in Unity speichert Daten in fest dimensionierten, vollständig zusammenhängenden Speicherblöcken, den sogenannten „Chunks“. Jeder Chunk enthält ein „Structure of Arrays“-Array (SoA), das aus Komponenten desselben Typs besteht. Beispielsweise werden alle Daten im Zusammenhang mit einer Komponente namens Translation (Position) in einem einzigen kontinuierlichen Speicherblock gespeichert. Ebenso befinden sich Rotationsdaten (Rotation) in einem anderen Chunk oder nacheinander in einem separaten SoA-Array innerhalb desselben Chunks. Diese Anordnung ermöglicht es einem System (z. B. MovementSystem), alle Translation-Daten in einer einzigen For-Schleife zu verarbeiten. Bei der Ausführung dieser Schleife lädt die CPU nur einmal einen großen Datenblock aus dem Speicher und verwendet diesen Datenblock wiederholt, da alle relevanten Daten sehr nahe beieinander liegen. Dies ermöglicht eine effiziente Nutzung der CPU-Caches und reduziert die Cache-Miss-Rate drastisch. Die Tatsache, dass die Entitäten in der ECS-Architektur von Unity alle ihre Komponentendaten in einem einzigen Speicherblock zusammenfassen, maximiert diese Effizienz. Noch wichtiger ist, dass das Layout der Daten im Speicher innerhalb der DOTS-Architektur von Unity perfekt mit dem eigenen Speicherlayout der CPU übereinstimmt (z. B. den 64-Byte-Zeilen des L1-Datencaches). Die Größen und Ausrichtungen der Datenfelder werden entsprechend den Anforderungen der Cache-Lines optimiert. Dies verwandelt sich insbesondere bei modernen mobilen CPUs wie dem Arm Cortex-X4 in einen erheblichen Vorteil, da die Leistung dieser Architekturen direkt damit zusammenhängt,
dass die Speicherbandbreite und die Cache-Effizienz auf höchstem Niveau sind.
Ein ähnliches Konzept ist auch in der Unreal Engine 5 zu finden. Das Mass Entity Framework ermöglicht eine effizientere Speicherung im Speicher, indem Entitäten und ihre Komponenten nach komplexen Datenstrukturen, den sogenannten Archetypes, gruppiert werden. Ein Archetype definiert einen bestimmten Satz von Komponenten. Sie können beispielsweise einen Archetype erstellen, der „beweglich ist und eine Waffe besitzt“ (Hareket edebilen ve Silahi Olan). Alle Entitäten mit solchen Komponenten (z. B. 500 Soldaten) werden dann automatisch in den Chunks gespeichert, die zu diesem Archetype gehören. Dies ermöglicht eine effizientere Ausführung von Abfragen und verschwendet weniger CPU-Cache. Dass in neueren Versionen wie UE 5.7 Low-Level-Optimktionen für Mass vorgenommen werden, ist ein klarer Beweis dafür, dass dieses Framework leistungsorientiert ist. Darüber hinaus hat sich auch das Chaos-Physiksystem zu datenorientierten Ansätzen entwickelt und enthält Caching-Mechanismen, um Neuberechnungen von Simulationen zu vermeiden. Tools wie der Chaos Cache Manager stellen sicher, dass eine Simulation einmal berechnet und mehr als einmal abgespielt werden kann, wodurch verhindert wird, dass die CPU dieselbe Operation wiederholt ausführt. Dies bringt einen signifikanten Leistungsgewinn, insbesondere bei rechenintensiven CPU-Vorgängen wie dynamischer Zerstörung oder Flüssigkeitssimulationen.
Zusammenfassend lässt sich sagen, dass die Optimierung des Speicherlayouts und die CPU-Cache-Effizienz zu den kritischsten Faktoren gehören, die die Leistung moderner Spiel-Engines bestimmen. Während der OOP-Ansatz das Potenzial von CPU-Caches verschwendet, indem er Datenzugriffsmuster von Natur aus verstreut, bietet DOD eine direkte Lösung für dieses Problem. Unity DOTS und das Mass-Framework der Unreal Engine 5 sind so konzipiert, dass beide Engines die Leistung steigern, indem sie verstreute Speicherzugriffsmuster vermeiden und CPU-Caches effizient nutzen. Diese architektonische Änderung ist von vitaler Bedeutung, um das gewünschte flüssige Erlebnis zu gewährleisten, insbesondere in Spielen, die eine reiche und lebendige Welt wie Kena: Bridge of Spirits bieten. Für mobile Plattformen hingegen bieten diese Optimierungen Energieeinsparungen, indem sie die Möglichkeit bieten, mehr Arbeit bei geringerem Stromverbrauch zu leisten.
Mehrthreadschnittstelle und parallele Verarbeitungskapazität

Moderne Prozessoren verfügen über mehrere CPU-Kerne, von denen jeder eigenständig arbeiten kann. Multithreading ist die Fähigkeit, diese parallele Rechenleistung in der echten Spiellogik zu nutzen. Allerdings erfordert eine OOP-basierte Code-Struktur komprimierte Synchronisationsmechanismen, um Datenkonflikte zu vermeiden, was zu unerwarteten Einbrüchen und Leerlaufzeiten der CPU-Kerne führen kann. Data-Oriented Design (DOD) bietet eine architektonische Lösung für diese Probleme und macht die parallele Ausführung von Code von Natur aus einfacher.
Beim objektorientierten Programmieransatz (OOP) läuft Code in der Regel synchron auf einem einzigen Haupt-Thread (zum Beispiel GameThread in Unreal oder Main Thread in Unity). Dieser Thread verarbeitet vieles von der Spiellogik wie Spielereingaben, KI-Logik und Physik-Updates. Während andere Subsysteme (Rendering, Audio, Physik) oft in separaten Threads laufen, arbeiten diese im Allgemeinen unabhängig vom Haupt-Thread. Da ein großer Teil Ihres Codes auf einem einzigen Thread läuft, warten die anderen CPU-Kerne meist im Leerlauf. Wenn Entwickler in einem OOP-basierten Projekt Parallelität hinzufügen möchten, müssen sie Synchronisationsmechanismen wie Locks, Mutexe oder Semaphoren verwenden, um Datenkonflikte zu verhindern. Diese Mechanismen können dazu führen, dass andere Threads darauf warten, dass ein Thread einen kritischen Bereich (zum Beispiel einen Schreibvorgang in einer Liste) beendet. Wartezeit bedeutet, dass ein CPU-Kern untätig bleibt, was zu unerwarteten Rucklern (Hitches) und einem allgemeinen Leistungsabfall führen kann. Unreal Engine 5 bietet nativ Unterstützung für Multithreading, aber die Engine bleibt manchmal an einen einzigen Thread gebunden, und die Möglichkeiten der Entwickler, dies voll auszuschöpfen, sind eingeschränkt. Das bedeutet, dass ein Großteil der potenziellen CPU-Leistung verschwendet wird.
Data-Oriented Design (DOD) ist ein architektonisches Paradigma, das für parallele Verarbeitung entwickelt wurde. DOD verfolgt Prinzipien, die Datenkonflikte zwischen Threads eliminieren, indem Daten von einem einzigen Ort gelesen und an einen einzigen Ort geschrieben werden. Die DOTS-Architektur von Unity ist das klarste Beispiel für diese Philosophie und kombiniert zwei Haupttechnologien: Job System und Burst Compiler. Das Job System unterteilt Ihren Code in Teile und ermöglicht es Ihnen, diese parallel auf verschiedenen CPU-Kernen auszuführen. Eine Entities.ForEach-Schleife innerhalb eines SystemBase wird tatsächlich als Job kompiliert. Dieser Job verhindert das Ändern von Daten auf einem einzigen Thread und eliminiert dadurch Data Races. Jeder Job kann sicher auf verschiedenen CPU-Kernen ausgeführt werden. Dies ermöglicht eine Parallelisierung, ohne dass komplexer Synchronisationscode zur Vermeidung von Datenkonflikten erforderlich ist. Der Burst Compiler ist eine Compiler-Optimierung, die C#-Code in hochoptimierten, nativen C++-Code übersetzt. Burst verwendet das LLVM-Backend, um Code auf C/C++-Ebene zu kompilieren, sodass Sie die Leistung erreichen können, die von C++ möglich ist. Es ist äußerst effizient, insbesondere für Schleifen, mathematische Berechnungen und Datenkonvertierungsvorgänge. Jedes SystemBase in Ihrem System (zum Beispiel MovementSystem) läuft tatsächlich als Job und kann von Burst optimiert und parallel auf verschiedenen CPU-Kernen ausgeführt werden. Dies verhindert das Ändern von Daten auf einem einzigen Thread, beseitigt Data Races und gewährleistet die Sicherheit der Parallelisierung.
In Unreal Engine 5 verfolgt das Mass Entity Framework ähnliche Prinzipien, die die Verwendung von Multithreading erleichtern. Mass erleichtert die Nutzung von Multithreading, indem es eine bestimmte Aufgabe (zum Beispiel das Ausführen der Wegfindungslogik von Hunderten von KIs) datenorientiert organisiert und sie parallel auf mehreren Threads ausführt. Mass ist zudem so konzipiert, dass es sich nahtlos mit anderen Unreal-Thread-Modellen wie dem Render-Graph integrieren lässt. Dies erhöht die globale Leistung, indem sichergestellt wird, dass verschiedene Motorbereiche auf unterschiedlichen Threads parallel arbeiten. Seit der Version Unreal Engine 5.0 hat die Engine selbst Verbesserungen vorgenommen, um die Nutzung von Multithreading zu erhöhen; beispielsweise haben Stabilitäts- und Leistungsupdates im Vulkan RHI eine bessere Multithreading-Nutzung sowohl auf Desktop- als auch auf Mobilplattformen ermöglicht.
Konkretes Codebeispiel (Unity DOTS):
public class CharacterController_OOP : MonoBehaviour
{
public float moveSpeed = 5f;
void Update()
{
foreach(var character in allCharacters)
{
character.Move();
}
}
}
using UnityEngine;
using Unity.Entities;
using Unity.Transforms;
using Unity.Mathematics;
public class MovementSystem_DOD : SystemBase
{
protected override void OnUpdate()
{
float deltaTime = Time.DeltaTime;
Entities.ForEach((ref Translation translation, in Rotation rotation, in MoveSpeed speed) =>
{
translation.Value += speed.value * deltaTime * math.rotate(rotation.Value, new float3(0, 0, 1)).normalize();
}).Schedule();
}
}
In diesem Beispiel läuft der OOP-Ansatz synchron auf dem Haupt-Thread, während im DOD-Ansatz die Entities.ForEach-Schleife innerhalb von OnUpdate als ein Job geplant wird, der vom Job System parallel verarbeitet werden kann. Dieser Job kann von Burst optimiert und gleichzeitig auf verschiedenen CPU-Kernen ausgeführt werden. Dies verhindert das Ändern von Daten auf einem einzigen Thread, beseitigt Data Races und gewährleistet die Sicherheit der Parallelisierung.
Zusammenfassend lässt sich sagen, dass DOD die Synchronisationsschwierigkeiten und unerwarteten Ruckler, die OOP mit sich bringt, eliminiert und die Nutzung von Multithreading von Natur aus erleichtert. Unitys DOTS und das Mass-Framework von Unreal Engine 5 sind darauf ausgelegt, die Leistung zu steigern, indem beide Engines verteilte Speicherzugriffsmuster vermeiden und CPU-Caches effizient nutzen. Diese architektonische Änderung ist von entscheidender Bedeutung, um das gewünschte flüssige Erlebnis zu gewährleisten, insbesondere in Spielen wie Kena: Bridge of Spirits, die eine reichhaltige und lebendige Welt bieten. Für mobile Plattformen bieten diese Optimierungen zudem Energieeinsparungen, indem sie die Möglichkeit bieten, mit weniger Stromverbrauch mehr Arbeit zu erledigen.
Data-Oriented Technology Stack (DOTS) innerhalb des Unity-Ökosystems
Unity behält zwar die OOP-basierte GameObject-Architektur bei, bietet aber gleichzeitig einen völlig neuen Technologiestack namens Data-Oriented Technology Stack (DOTS) für Anwendungen an, die eine hohe Leistung erfordern. DOTS basiert auf den Prinzipien des datenorientierten Designs, optimiert das Speicherlayout, erhöht die Effizienz des CPU-Caches und bietet native Multithreading-Unterstützung. Dieser Abschnitt untersucht die Kernkomponenten von DOTS, konkrete Codebeispiele und den Integrationsprozess.
Den Grundstein von DOTS bildet das Entities-Paket. Dieses Paket stellt ECS-Elemente (Entity Component System) wie Entities, Component Data und Systems auf fundamentale Weise bereit. Die zugrundeliegende Philosophie hierbei ist es, Daten aus der Funktionalität herauszulösen und sie effizienter im Speicher zu speichern. 1. Entities: Entities sind leere Container ohne eigene Daten und mit eindeutigen IDs. Eine Entity ist kein Objekt; sie ist lediglich eine EntityId. Das macht sie im Speicher sehr leichtgewichtige Elemente und ermöglicht ein schnelles Erstellen und Zerstören. 2. Component Data: Dies sind datenhaltige Structs. Sie müssen ein Struct sein und dürfen keine Vererbung verwenden. Es werden einfache datenhaltige Strukturen wie Translation { public float3 Value; } oder Health { public int Value; } definiert. Diese Structs implementieren das IComponentData-Interface. 3. Systems: Dies ist die Logik, die diese Daten verarbeitet. Klassen, die von der SystemBase-Klasse abgeleitet sind, verwenden Abfragen (Queries), um bestimmte Datentypen (Komponenten) auszuwählen, und führen Operationen auf diesen Daten aus. Die OnUpdate-Methode wird als Job geplant und enthält typischerweise eine Entities.ForEach-Schleife.
Konkretes Codebeispiel (Unity DOTS): Der folgende Code vergleicht, wie die Bewegung eines Charakters mit OOP und DOTS unterschiedlich gehandhabt wird:
public class PlayerController_OOP : MonoBehaviour
{
public float moveSpeed = 5f;
void Update()
{
float moveInput = Input.GetAxis("Horizontal");
transform.Translate(Vector3.right * moveInput * moveSpeed * Time.deltaTime);
}
}
public struct Translation : IComponentData
{
public float3 Value;
}
public struct Rotation : IComponentData
{
public quaternion Value;
}
public struct MoveSpeed : IComponentData
{
public float value;
}
// 2. System zur Darstellung der Spiellogik
public class MovementSystem : SystemBase
{
protected override void OnUpdate()
{
float deltaTime = Time.DeltaTime;
Entities
.WithName("MoveEntities")
.ForEach((ref Translation translation, in Rotation rotation, in MoveSpeed speed) =>
{
translation.Value += speed.value * deltaTime * math.normalize(math.mul(rotation.Value, new float3(0, 0, 1)));
}).Schedule();
Dependency.Complete();
}
}
In diesem Beispiel zeigt der DOD-Ansatz, wie Daten im Speicher gruppiert und verarbeitet werden. Die Schleife innerhalb von Entities.ForEach wird als einzelner Job kompiliert, der von Burst optimiert und parallel auf verschiedenen CPU-Kernen ausgeführt werden kann. Dies verhindert das Ändern von Daten auf einem einzigen Thread, beseitigt Data Races und gewährleistet die Sicherheit der Parallelisierung.
Integrationsschritte (Unity DOTS): Die Integration von DOTS in ein Unity-Projekt beginnt mit der Erstellung eines Standard-Unity-Projekts und erfordert anschließend das Hinzufügen der erforderlichen Pakete über den Package Manager:
Paket-Manager: Gehen Sie zum Menü Edit > Project Settings > Packages oder zum Menü Window > Package Manager innerhalb der IDE.
Erforderliche Pakete hinzufügen: Die folgenden grundlegenden DOTS-Pakete können für das Projekt hinzugefügt werden:
com.unity.entities: Das Paket, das die grundlegende ECS-Architektur bereitstellt.com.unity.jobs: Das Paket, das zum Ausführen des Job-Systems erforderlich ist.com.unity.burst: Das Paket, das C#-Code in nativen C++-Code übersetzt und optimiert.com.unity.mathematics: Bietet grundlegende mathematische Typen wie Vektor- und Matrizenoperationen für DOTS.com.unity.netcode.entities: Erforderlich für netzwerkbasierte DOTS-Anwendungen.
Definition der Datenstruktur: Structs werden erstellt, die das IComponentData-Interface implementieren. Diese Structs tragen Daten, können jedoch keine Funktionen enthalten.
Erstellung von Systemen: Klassen werden erstellt, die von der SystemBase-Klasse abgeleitet sind. Diese Klassen überschreiben Lebenszyklusmethoden wie OnUpdate, OnFixedUpdate oder OnCreate.
Renderer-Integration: Um mit DOTS erstellte Entities auf dem Bildschirm anzuzeigen, ist ein Renderer erforderlich. Anfangs ist es praktisch, den Hybrid Renderer zu verwenden, um DOTS-Daten auf vorhandene GameObjects zu übertragen. Dadurch können Sie die datenorientierte Architektur von DOTS nutzen und gleichzeitig Ihre bestehende Rendering-Pipeline beibehalten. Später können Entities Graphics-Pakete verwendet werden, die sich in URP oder HDRP integrieren lassen.
Strategische Auswirkungen für AAA-Open-World- und Mobil-Optimierung: Spiele wie Kena: Bridge of Spirits erfordern sowohl eine reichhaltige, detaillierte Umgebung (AA-Open-World) als auch eine flüssige, reaktive Charaktersteuerung. Mobile Plattformen hingegen fügen eine zusätzliche Herausforderungsebene in Bezug auf begrenzte CPU-/GPU-Leistung und Akkulaufzeit hinzu.
Leistung und Flüssigkeit: DOD ist eines der mächtigsten Werkzeuge zur Reduzierung plötzlicher Ruckler und Framerate-Einbrüche, insbesondere in OOP-basierten Projekten. Die Stotterprobleme im Spiel Kena verdeutlichen den Unterschied, den ein DOD-Ansatz bewirken kann. DOD bietet eine höhere Datenverarbeitungskapazität durch die Nutzung der vollen CPU-Leistung, was ein stabileres Ziel von 60 FPS ermöglicht.
Optimierung für mobile Plattformen:
CPU-Leistung: Mobile CPUs (wie Arm Cortex-X4) werden immer leistungsstärker, aber Energieeffizienz bleibt ein kritischer Faktor. DOD kann die Leerlaufzeit der CPU minimieren und es ihr ermöglichen, mit weniger Stromverbrauch mehr Arbeit zu erledigen. Verbesserungen wie die Reduzierung der Bandbreite um 33 % in der Cortex-X4-Architektur von Arm bedeuten, dass Anwendungen, die mit DOD arbeiten, davon noch mehr profitieren können.
Speicherverwaltung: Die Speichernutzung muss auf mobilen Plattformen sorgfältig verwaltet werden. DOTS kann den Gesamtbedarf an Speicher reduzieren, indem es mit kompakteren und zugewiesenen Daten im Speicher arbeitet. Technologien wie Unitys
AssetBundle-Kompprimierungsformate und SVT (Virtual Texturing) können in Kombination mit der Datenorganisation von DOD eine äußerst effiziente Struktur für mobile Plattformen bilden.ProGuard Minification: Tools wie die ProGuard-Minifizierung für Android können, wenn sie zusammen mit dem durch DOD erstellten optimierten Code verwendet werden, die Installationsgröße und die Leistung weiter verbessern.
Zusammenfassend lässt sich sagen, dass der DOTS-Stack von Unity ein leistungsstarkes Toolset ist, das entwickelt wurde, um die Skalierbarkeitsgrenzen von OOP zu überwinden. Entwickler können in Bereichen, in denen die Leistung eines Projekts kritisch ist (Physik, KI, Partikelsysteme), DOTS verwenden und einen hybriden Ansatz verfolgen, ohne die bestehende OOP-basierte Struktur zu zerstören.
Leistungsbezogene Architekturansätze in Unreal Engine 5: Mass und Chaos

Unreal Engine 5 ist in ihrer Kernarchitektur mit ihrer UObject-Vererbung tiefgehend objektorientiert (OOP). Dennoch zwingen die Anforderungen an hohe Leistung und Skalierbarkeit, die für Spiele in AAA-Qualität unerlässlich sind, die Engine selbst dazu, sich weiterzuentwickeln und datenorientierte Ansätze anzunehmen. Um diesen Bedarf zu decken, bietet Unreal Engine 5 zwei leistungsorientierte Architekturansätze: das Mass Entity Framework und Chaos Physics. Diese beiden Systeme gehen über die OOP-basierte Struktur von Unreal hinaus und verfolgen datenorientierte Designprinzipien, die besonders für groß angelegte Simulationen und physikalische Simulationen eine entscheidende Leistungssteigerung bewirken.
Mass Entity Framework: Datenorientiertes Gameplay Mass ist ein in Unreal Engine 5 für datenorientierte Berechnungen entwickeltes Framework, das speziell für Szenarien entwickelt wurde, in denen Hunderte oder Tausende von Spieleinheiten gleichzeitig verwaltet werden. Anstatt das Unreal-Gameplay zu ersetzen, ist Mass als eine datenorientierte und für die Parallelverarbeitung geeignete Schicht konzipiert, die auf der bestehenden Actor-/Component-Architektur aufbaut. Seine Kernphilosophie besteht darin, die Leistung zu steigern, indem große Mengen ähnlicher Datensätze im Speicher effizienter gruppiert und über mehrere Threads hinweg parallel verarbeitet werden.
Die Hauptkomponenten der Mass-Architektur sind:
Entität: In Mass ist eine Entität ein leerer Container ohne eigene Daten und mit einer eindeutigen Identität. Dies macht sie extrem leichtgewichtig, ähnlich wie
Entitys in Unity.Komponente: Dies ist die Datenstruktur, die die Daten enthält. Sie kann ein
float-Wert, ein Vektor oder eine komplexe Struktur sein. Komponenten ermöglichen die Gruppierung von Daten im Speicher.System: Die Logik, die Entitäten mit bestimmten Komponenten auswählt und verarbeitet. Diese Systeme können bei der Verarbeitung der Daten parallelisiert werden.
Archetyp: Dies ist die wichtigste und einzigartigste Komponente der Mass-Architektur. Ein
Archetypdefiniert einen bestimmten Satz von Komponenten. Beispielsweise kann einArchetypmit den Komponenten „Position“, „Velocity“ (Geschwindigkeit) und „AIController“ erstellt werden. Alle Entitäten mit genau diesen Komponenten (z. B. 1000 feindliche Einheiten) werden daraufhin automatisch in den Speicherblöcken diesesArchetyps gespeichert. Dies ermöglicht eine effizientere Ausführung von Abfragen und reduziert die Verschwendung des CPU-Caches.
Konkretes Codebeispiel (Unreal Engine 5 – Mass): Mass wird typischerweise mit C++ oder über spezielle Nodes innerhalb von Blueprint verwendet. Unten befindet sich ein Pseudocode-Beispiel, das einen allgemeinen Eindruck von der Grundstruktur eines Mass-Systems vermittelt:
USTRUCT(BlueprintType)
struct FPositionComponent
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components")
FVector Location;
};
USTRUCT(BlueprintType)
struct FVelocityComponent
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components")
FVector Velocity;
};
class FMovementSystem : public FGlobalComponentSystem
{
public:
virtual void Tick(float DeltaTime) override
{
Query.ForEach(
[&](FEntityHandle Entity, FMutableRef<FPositionComponent> PositionComp, FMutableRef<FVelocityComponent> VelocityComp)
{
PositionComp->Location += VelocityComp->Velocity * DeltaTime;
});
}
};
// 3. Das System wird registriert und in die Engine integriert
IMPLEMENT_MODULE(MyModule, MyModuleName);
In diesem Beispiel bildet der Aufruf von Query.ForEach das Fundament der datenorientierten Struktur von Mass. Das System wählt alle Entitäten mit den angegebenen Komponenten aus und verarbeitet deren Daten in einer einzigen Schleife. Diese Schleife kann von den internen Parallelverarbeitungsmechanismen von Unreal auf verschiedenen Threads ausgeführt werden. In neueren Versionen wie UE 5.7 werden Low-Level-Optimierungen für
Mass kontinuierlich fortgesetzt, was ein klarer Beweis für die leistungsorientierte Ausrichtung des Frameworks ist.
Chaos Physics und Caching:
Chaos ist die Standard-Physik-Engine in Unreal Engine 5 und wurde als Teil der OOP-Architektur konzipiert. Dennoch hat auch Chaos datenorientierte Prinzipien übernommen und ist darauf ausgelegt, die Leistung insbesondere bei CPU-intensiven Simulationen zu steigern. Chaos unterstützt Funktionen wie brechende Gelenke (breakable joints) und Kollisionsrestitution.
Das wichtigste Merkmal der leistungsorientierten Seite von Chaos ist die Caching-Funktion für Simulationen. Wenn eine komplexe physikalische Simulation (zum Beispiel der Einsturz eines großen Gebäudes) in jedem Frame neu berechnet würde, wäre dies extrem rechenintensiv. Der Chaos Cache Manager wurde entwickelt, um dieses Problem zu lösen. Der Entwickler zeichnet eine Simulation auf, und die Engine speichert eine Kopie dieser Simulation im Speicher oder auf der Festplatte. Wenn die Simulation dann erneut abgespielt wird, verwendet die Engine die aufgezeichneten Daten, anstatt Neuberechnungen durchzuführen, was eine erhebliche Einsparung an CPU-Zeit bedeutet. Dies ist besonders effektiv für wiederholte Effekte oder dynamische Objekte. Damit dieses System jedoch ordnungsgemäß funktioniert, muss es sorgfältig konfiguriert werden; bei falscher Konfiguration sind die Cache-Daten nicht synchronisiert und Objekte können an ihre ursprünglichen Positionen zurückspringen.

Integrationsschritte (Unreal Engine 5):
Die Integration von Systemen wie Mass und Chaos in ein Unreal-Projekt ist in der Regel unkompliziert, da sie bereits in der Standardkonfiguration der Engine enthalten sind.
Plugin-Aktivierung: Sie können das Mass-Plugin in den Projekteinstellungen (Settings > Plugins > Gameplay > Mass) aktivieren.
Entwicklung mit Blueprint oder C++: Mass kann über die Mass-Entity-Palette im Blueprint-Editor oder direkt durch das Schreiben von C++-Code verwendet werden. Die Blueprint-Unterstützung ist ideal für schnelles Prototyping.
Erstellung eines Systems: Sie können beginnen, indem Sie vorgefertigte Controller wie den
MassEntityPlayerControllerverwenden oder Ihr eigenes System überFMassExecutionContextin C++ erstellen.Chaos-Einstellungen: Die Chaos-Physikeinstellungen befinden sich unter Project Settings > Chaos Physics. In diesen Einstellungen können Funktionen wie die Kollisionsrestitution aktiviert werden. Für das Chaos-Caching muss die Option
bEnableCacheinnerhalb der Chaos Solver Settings aktiviert werden.
Strategische Auswirkungen:
Die datenorientierten Ansätze der Unreal Engine 5 sind besonders für AAA-Open-World- und Mobilplattformen von strategischer Bedeutung. In Spielen im Stil von Kena gibt es eine riesige Welt, in der sich vor dem Spieler ständig lebendige Aktivitäten abspielen. Wenn das sofortige Verhalten eines NPCs oder Objekts in dieser Welt im OOP-Stil verwaltet wird, wird in jedem Frame auf Hunderte verschiedener Speicheradressen zugegriffen, was zu Rucklern führt. Der DOD-Ansatz ist von entscheidender Bedeutung, um in solchen Spielen das gewünschte flüssige Erlebnis zu gewährleisten. Für mobile Plattformen ist die Effizienz des CPU-Caches sogar noch kritischer; mit weniger Stromverbrauch mehr Berechnungen durchzuführen, ist ein wesentlicher Vorteil für Mobilgeräte. Wenn das Niagara-Partikelsystem der Unreal Engine 5 zusammen mit Technologien wie SVT (Virtual Texture) eingesetzt wird, kann es durch das Caching von Simulationen erhebliche Leistungs- und Speicherverbesserungen ermöglichen.
Zusammenfassend lässt sich sagen, dass Unreal Engine 5 ihre OOP-basierte Struktur beibehält, aber Mass und Chaos entwickelt hat – leistungsstarke, datenorientierte Ebenen, um leistungsorientierte Anforderungen zu erfüllen. Diese Systeme bieten Entwicklern die nötige Leistung für groß angelegte, datenintensive Simulationen, während sie nahtlos integriert arbeiten, ohne die Kernarchitektur der Engine zu verändern.
Strategische Auswirkungen und Produktivitätskosten: Eine Bewertung für AAA-Open-World und Mobilplattformen
Die Wahl zwischen datenorientiertem Design (DOD) und objektorientierter Programmierung (OOP) ist längst nicht mehr nur eine technische Präferenz, sondern eine strategische Entscheidung für den Erfolg eines Spiels. Besonders für reichhaltige, flüssige und weitläufige AAA-Spiele wie Kena: Bridge of Spirits sowie für Mobilplattformen mit begrenzten Ressourcen hat diese Entscheidung tiefgreifende Auswirkungen auf Leistung, Entwicklungsgeschwindigkeit und Spielerlebnis. DOD ist ein mächtiges Paradigma, das speziell dafür entwickelt wurde, die Skalierbarkeitsgrenzen von OOP zu überwinden, doch diese Vorteile müssen gegen Kosten wie die Lernkurve und den Integrationsaufwand abgewogen werden.
Strategische Auswirkungen bei AAA-Open-World und Ruckelproblemen:
Kena: Bridge of Spirits zeichnet sich als ein Spiel aus, das eine reichhaltige mythologische Welt, eine flüssige Charaktersteuerung und detaillierte Umgebungselemente bietet. In Diskussionen in Steam-Community-Foren wurden Leistungsprobleme des Spiels („Stutter“ und „FPS-Drops“) angesprochen . Die zugrunde liegenden technischen Ursachen für solche Probleme sind höchstwahrscheinlich die Skalierbarkeitsgrenzen einer OOP-basierten Architektur. In OOP besitzt jedes Entitätselement in der Szene (NPC, Objekt, Partikelsystem) ein eigenes GameObject und damit verbundene Komponenten. Da diese GameObjects im Speicher verstreut gespeichert sind, erfordert das Aktualisieren aller dieser Entitäten in jedem Frame den CPU-Befehl, auf Hunderte verschiedener Speicheradressen zuzugreifen. Dies führt zu einer hohen Anzahl von CPU-Cache-Misses und zwingt den Prozessor, Daten aus dem langsamen RAM abzurufen, was zu sichtbaren Einbrüchen (momentanen Verlangsamungen) führt. DOD bietet eine direkte Lösung für dieses Problem. Frameworks wie DOTS in Unity oder Mass in Unreal Engine 5 speichern ähnliche Datentypen (z. B. die Positionsdaten aller NPCs) sequenziell im Speicher. Das bedeutet, dass ein Thread alle diese Daten auf einmal aus dem Speicher abrufen und verarbeiten kann, was die CPU-Cache-Trefferquote und die Gesamtleistung dramatisch erhöht. Diese Architektur ist von vitaler Bedeutung, um das in Spielen wie Kena angestrebte flüssige Erlebnis zu gewährleisten. DOD nutzt die volle Leistung der CPU, um eine größere Datenverarbeitungskapazität zu ermöglichen, wodurch ein stabileres 60-FPS-Ziel erreicht werden kann.
Strategische Auswirkungen für die Optimierung von Mobilplattformen:
Mobilplattformen verfügen im Vergleich zu Desktop- oder Spielkonsolen über eingeschränktere Ressourcen: weniger CPU-Leistung, weniger RAM und als kritischer Faktor eine begrenzte Akkulaufzeit. Daher werden Energieeffizienz und Speicherverwaltung für mobile Spieleentwickler zu entscheidenden Erfolgsfaktoren des Spiels.
Energieeffizienz: Mobile Prozessoren (z. B. Arm Cortex-X4) werden immer leistungsstärker, aber die Energieeffizienz bleibt ein kritischer Faktor . DOD minimiert die Leerlaufzeit der CPU, sodass sie mit weniger Stromverbrauch mehr Arbeit erledigen kann. Verbesserungen wie die Reduzierung der Bandbreite um 33 % in der Cortex-X4-Architektur von Arm bedeuten, dass Anwendungen, die mit DOD arbeiten, davon noch mehr profitieren können . Geringere CPU-Nutzung trägt auch dazu bei, dass sich das Gerät weniger erhitzt und der Akku langsamer entlädt.
Speicherverwaltung: Auf Mobilplattformen muss die Speichernutzung sorgfältig verwaltet werden. DOD kann die allgemeine Speichernutzung reduzieren, indem es mit dichteren und zugewiesenen Daten im Speicher arbeitet. Technologien wie die
AssetBundle-Kompprimierungsformate von Unity () und SVT (Virtual Texturing) () können in Kombination mit der Datenorganisation von DOD eine äußerst effiziente Struktur für Mobilplattformen bilden. Darüber hinaus unterstützen neue Technologien wie die DirectStorage-Unterstützung von Unity () und Shader-Streaming ebenfalls die Vision hinter der datenverwaltungsbasierten Architektur von DOD .Produktivität und Entwicklungszeit: Mobilplattformspezifische Optimierungen (z. B. ProGuard-Minifizierung) () und die Verwendung plattformspezifischer APIs () in Verbindung mit DOD ermöglichen eine effizientere Codebasis, wodurch diese Optimierungen noch wirksamer werden.
Produktivitätskosten und Entwicklererfahrung:
Die Leistungsvorteile von DOD müssen gegen eine spürbare Lernkurve und die Kosten eines anfänglichen Produktivitätsrückgangs abgewogen werden.
Transformationsherausforderung: Ein bestehendes, großes OOP-basiertes Projekt kann nicht vollständig in eine DOD-Architektur überführt werden. Meistens wird ein hybrider Ansatz verfolgt: Während einige kritische Bereiche (Physik, KI, Partikelsysteme) auf DOD migriert werden, verbleiben andere Bereiche (UI, bestimmte spezielle Gameplay-Mechaniken) unter der bestehenden OOP-Struktur. Obwohl der Hybrid Renderer von Unity () solche Übergänge erleichtert, birgt er Probleme bei einer vollständigen Integration. Die Probleme im Spiel Kena hängen höchstwahrscheinlich mit der Skalierbarkeit der bestehenden OOP-basierten Struktur zusammen und legen nahe, dass sie durch einen Archkturwechsel wie DOD gelöst werden könnten.
Erfahrungsstufe: Bei DOD kann die Lernkurve besonders steil sein, insbesondere für Entwickler mit OOP-Erfahrung. Der Übergang von der Logik „Ich habe ein Objekt, das ich besitze“ zur Logik „Was mache ich mit diesem Datensatz?“ fällt schwer. Dies kann die Entwicklungsgeschwindigkeit zu Beginn verringern.
Werkzeugökosystem: OOP-basierte Unity und Unreal verfügen über ein im Laufe der Jahre entwickeltes und ausgereiftes Werkzeugökosystem. DOD-Frameworks wie DOTS und Mass entwickeln sich ebenfalls weiter, weisen jedoch möglicherweise noch Lücken auf und die Dokumentation ist oft neuer. Beispielsweise können einige Fehler im Zusammenhang mit DOTS (z. B. Fehler beim Laden der Burst-Assembly) ( ) oder die Integration von Systemen wie dem Chaos Cache Manager in Unreal () Entwickler immer noch vor Herausforderungen stellen.
Vergleichende Bewertung:
KriteriumObjektorientierte Programmierung (OOP)Datenorientiertes Design (DOD)LernkurveGering, ist ein gängiges und beliebtes ParadigmaHoch, erfordert eine neue PhilosophieProduktivität (Anfang)Hoch, geeignet für schnelles PrototypingGering, kann zu Beginn langsam seinLeistung (Skalierbarkeit)Begrenzt, verlangsamt sich bei großen DatensätzenHoch, skaliert gut bei Millionen von DatenCPU-Cache-EffizienzGering (verstreuter Zugriff)Hoch (sequenzieller Zugriff)Einfachheit der ParallelverarbeitungMittel (erfordert Synchronisation)Hoch (von Natur aus parallel)Eignung für MobilplattformenAkzeptabel, aber geringere EnergieeffizienzHoch, nutzt die CPU effizienterIntegration (Bestehende Projekte)Einfach, direkt kompatibel mit bestehenden ProjektenSchwierig, erfordert einen hybriden Ansatz
Fazit und strategische Empfehlung:
Die Wahl zwischen OOP und DOD hängt von Faktoren wie dem Maßstab des Spiels, der Zielplattform und dem Fachwissen des Teams ab. Für kleine bis mittlere Projekte oder schnelles Prototyping kann OOP hinsichtlich Entwicklungsgeschwindigkeit und Flexibilität von Vorteil sein. Für AAA-Spiele wie Kena: Bridge of Spirits, die flüssig, reichhaltig und in einer offenen Welt angesiedelt sind, wird DOD jedoch zu einer unverzichtbaren Option in Bezug auf Leistung und Skalierbarkeit. Für Mobilplattformen bietet DOD zusätzliche Vorteile wie Energieeffizienz und geringeren Speicherverbrauch, was DOD noch attraktiver macht. Entwickler sollten die Projektanforderungen sorgfältig analysieren und die Annahme einer hybriden Strategie in Betracht ziehen, die die Flexibilität von OOP und die Leistung von DOD kombiniert. Dies ermöglicht es, in verschiedenen Teilen des Projekts die jeweils richtige Architektur anzuwenden.
*Hinweis: Die Bilder wurden von Google Gemini generiert.
