Moderne Spieleprogrammierung mit dem Entity Component System und der Engine Bevy

Seite 3: ECS mit Unity DOTS

Inhaltsverzeichnis

Vor ein paar Jahren hat sich der Game-Engine-Hersteller Unity entschlossen, mit seiner Initiative Data-Oriented Tech Stack (DOTS) ebenfalls in den datenorientierten Ansatz einzusteigen. Im März 2022 ist Version 0.5 erschienen. DOTS koexistiert im klassischen Unity mit seinen MonoBehaviour-Klassen in C#.

DOTS besteht aus drei Teilen:

  • Einem Framework, das das Muster ECS in Unity zur Verfügung stellt,
  • einem C#-Job-System, das einfachere Multithreading-Programme ermöglicht und
  • dem Compiler Burst, der schnellere und plattform-optimierte Programme erzeugt.

Unity versucht, den datenorientierten Ansatz in der Objektorientierung von C# unterzubringen. Daher ist die zentrale Anlaufstelle des ECS-Frameworks zum Erzeugen neuer Entitäten die Klasse EntityManager:

using UnityEngine;
using Unity.Entities;

private EntityManager entityManager;

entityManager = 
  World.DefaultGameObjectInjectionWorld.EntityManager;

Entity entity = entityManager.CreateEntity();

Die durch die Methode CreateEntity erzeugte Entität hat keine Komponenten. Letztere lassen sich mit einer Vorlage in Form der Klasse EntityArchetype erstellen.

EntityArchetype archetype = entityManager.CreateArchetype(
  typeof(Translation),
  typeof(Rotation),
  typeof(RenderMesh),
  typeof(RenderBounds),
  typeof(LocalToWorld)
);

Entity entity = entityManager.CreateEntity(archetype);

Danach kann man den erzeugten Komponenten konkrete Daten zuweisen:

entityManager.AddComponentData(entity,new Translation{
  Value = new float3(-3f, 0.5f, 5f)
});

Wer eigene Komponenten definieren möchte, muss ein Struct erstellen, das das Interface IComponentData verwendet.

using Unity.Entities;
public struct SpeedComponent :  IComponentData
{
   public float speed;
}

In DOTS sind Systeme Klassen, die von ComponentSystem abgeleitet sind.

using Unity.Entities;
using Unity.Transforms;
using Unity.Mathematics;

public class MoveSystem : ComponentSystem
{
  protected override void OnUpdate()
  {
    Entities.WithAll<Move>()
      .ForEach((ref Translation trans, 
                ref Rotation rot, 
                ref SpeedComponent speedComponent) =>
    {
      trans.Value += speedComponent.speed 
                  * Time.DeltaTime 
                  * math.forward(rot.Value);
    });
  }
}

Das System MoveSystem holt sich die Komponenten Translation, Rotation und SpeedComponent und berechnet daraus die aktuelle Position, die es in die Komponente Translation zurückschreibt.

Das neue System ist nach dem Speichern der zugehörigen Datei aktiv, und Unity führt es beim nächsten Spielestart aus.

Für ECS gibt es in Unity viele hilfreiche Dialoge und Debugger. Entities kann man automatisch aus vorhandenen Klassen durch Markieren des Felds ConvertToEntity im GameObjects-Dialog erzeugen.

Ein Blick auf die Performance lohnt sich erst zur ersten Hauptversion von DOTS mit allen Bestandteilen.

Der Hersteller der Game-Engine Unreal arbeitet mit dem Entity Fragment Processor ebenfalls an einer Umsetzung des ECS-Musters. Er verwendet zwar teilweise andere Begriffe, arbeitet aber letztlich nach demselben Prinzip.

Im Bereich Data Science, in dem die Daten immer mehr im Mittelpunkt stehen, ist es eine spannende Herangehensweise, die Prinzipien der datenorientierten Programmierung auf Bereiche außerhalb der Spieleentwicklung zu übertragen. Einen Ansatz dazu zeigt Yehonathan Sharvit in seinem Buch Data-Oriented Programming [1].