Entity Component System

Category: 

Ein Entity Component System (ECS) ist ein Design Pattern, welches vor allem in der Spiele Industrie verwendet wird. Anstatt die verschiedenen Entitäten eines Spiels durch große, komplexe Vererbungshierarchien zu modellieren, verwendet man Entitäten, deren Attribute durch sogenannte Komponenten hinzugefügt werden.

Motivation

Erst einmal muss man verstehen, warum Vererbung nicht immer die beste Wahl ist. Betrachten wir dazu ein einfaches 2D Spiel. Angenommen dieses Spiel soll ein kleines top-down RPG werden, in dem sich der Spieler durch die Welt kämpft.
Alles was wir in der Welt sehen können, ist eine Entity. Diese unterteilen wir in Umgebung und Lebewesen. Bäume, Pflanzen, Stein, etc. sind dabei natürlich statische Elemente und erben dementsprechend von Environment. Die Gegner und der Spieler sind natürlich Lebewesen und erben daher auch von Livings.

Doch was machen wir, wenn wir uns entscheiden einen bösen Monsterbaum einzubauen? Da es ein Baum ist, sollte er natürlich von Tree erben. Andererseits ist es auch ein Monster und sollte von Monster erben. Diese Mehrfachvererbung ist einerseits unschön und zum anderen in vielen Sprachen gar nicht möglich.
Ein weiteres Problem ist, dass die Update Methoden sehr groß und unübersichtlich werden können. Die Update Methode eines Gegners, muss sich z.B. um das Render, die Collision, den Kampf, etc. des Monsters kümmern.

Die Komponenten

Um die eben genannten Probleme zu lösen, kann man die einzelnen Objekte in Komponenten aufteilen. Jede Komponente enthält dabei keinerlei Logik, sondern nur Attribute. Jede Entity speichert dann für sich eine Liste an Komponenten, aus denen sie besteht.

Wir unterscheiden nun nicht mehr explizit zwischen den einzelnen Entitäten, sondern fällen die Unterscheidung nach den Komponenten.
Ein Spieler ist nun nichts weiter als eine Entity mit den Komponenten: Position, Drawable, Stats und Input. Ein Baum ist nun nur noch eine Entity mit Position und Drawable, während unser MonsterBaum zusätzlich noch Stats enthält.
Der vorteil liegt auf der Hand. Einerseits haben wir nun das Vererbungsproblem gelöst, andererseits sind wir nun sogar in der Lage Objekte zur Laufzeit komplett zu verändern. Wir können Beispielsweise einen normalen Baum während des Spiels spontan in einen MonsterBaum verwandeln. Ebenso sind wir nun in der Lage die Objekte aus Konfigurationsdateien zu lesen.
Typische Komponenten sind die folgenden:

  • Position (x, y)
  • Velocity (vx, vy)
  • Size (width, height)
  • Stats (hp, att, def, ...)
  • Drawable (texture)
  • Input
  • AI

Logic der Komponenten

Das klingt ja bisher sehr gut, aber wo ist unsere Logik? Wo wird auf Kollision und Eingabe geprüft? Für diesen Job werden Systeme genutzt. Diese verarbeiten Entities, welche die notwendigen Komponenten besitzen. Das KampfSystem betrachtet z.B. nur die Entities, welche die Stats-Komponente besitzen. Das RenderSystem hingegen kümmert sich nur um Objekte mit Position- und Drawable-Komponente.
Dadurch definieren die Komponenten indirekt das Verhalten einer Entity.

Das Rendersystem zeichnet nun die Textur an die entsprechende Position. Teilweise macht es aber auch Sinn, eine Komponente ohne Attribute zu erzeugen. Diese dienen dann nur dazu, von einem bestimmten System erkannt zu werden. Die Input-Komponente hat z.B. keine Attribute, da die Eingabe erst vom Benutzer eingelesen werden muss. Das InputSystem benötigt nun sowohl Positions-, als auch Input-Komponente. Die Eingabe wird dann eingelesen und die Position wird angepasst.

Abschluss

Vererbung ist gut und schön, kann aber insbesondere bei Spielen häufig durch einen Komponenten basierten Ansatz getauscht werden.
Einige Spielengines, wie z.B. Unity3D oder das XNA Framework, nutzen teilweise ebenfalls ein Entity Component System.

Für Java ist Ashley ein schönes ECS, zu welchem ihr hier ein Tutorial findet: Ashley