Petridish

Evolution Simulation in Unity ECS

Von am 24.05.2023

Unity ECS Einführung

Unity ECS ist ein Aspekt des sogenannten DOTS (Data oriented technology stack) den Unity seit einigen Jahren verfolgt. DOTS ist ein Set von Technologien die zusammen das Erstellen von performance-intensiveren Spielen als mit den traditionellen objektorientierten Technologien erlauben. Konkret fokussiert sich DOTS, wie der Name beschreibt, auf datenorientiertes Programmieren, mit einem weiteren Fokus auf Parallelisierung und low-level Optimierungen, wie beispielsweise SIMD.

ECS, oder „Entity-component-system“, ist eine datenorientierte Software-architektur, die oft in Spielen zu Einsatz kommt. Nicht nur gibt es ECS schon einige Jahre, es gab sogar schon für Unity verschiedenste third-party ECS-Frameworks. Sein 2018 arbeitet Unity aber auch an ihrem eigenen inhouse Framework, welches Anfang 2023 endlich in 1.0.0 ging. Eine kurze Beschreibung über wie die ECS-Architektur funktioniert, folgt später.

ECS bietet an Vorteilen zunächst Performance-verbesserungen (Mehrere tausende simulierte Entities auch auf schwächerer Hardware mit guten FPS möglich), wobei das nicht der Hauptgrund ist warum ich es lernen wollte. Primär geht mit ECS eine komplett neue Art über Spiele und den Code nachzudenken einher die ich gerne kennenlernen wollte. Nachdem ich mich nun einige Monate damit beschäftigt habe, kann ich sagen, dass ich den ECS-Workflow sehr schätze und mir teilweise sogar schwer tue wieder zu normalem OO MonoBehaviour Code zurückzukommen.

Das Petridish Projekt

Ich habe überlegt, was ein gutes Projekt wäre, um mich mit ECS auseinander zu setzen und habe nach einigen Tests eine Idee von vor einigen Jahren wiederbelebt. Damals habe ich mich mit simulierten Bakterien und deren Evolution gespielt und dachte mir, dass das ein guter Kandidat für ECS mit der verbesserten Performance wäre.

In Petridish gibt es Blobs, das sind die runden Tierchen, die herumflitzen. Blobs müssen Energie zu sich nehmen, um zu überleben. Sie können dazu Nutrients essen, also die sechseckigen Stückchen, die verteilt sind. Fast alles, dass die Blobs tun, kostet sie auch Energie, beispielsweise bewegen oder sehen.

In dieser Simulation waren wohl sehr kleine und schnelle Blobs die fittesten

Verschiedene Blobs haben verschiedene Gene, die beispielsweise kontrollieren, wieviel Energie sie pro Sekunde nutzen, wieviel sie von dieser Energie für Bewegen benutzen oder wie groß sie sind. Alle diese Eigenschaften haben vor und Nachteile und es ist Ziel der Simulation eine optimale Spezies zu finden. Wenn Blobs genug Energie aufgenommen haben klonen sie sich, wobei der Nachwuchs immer eine kleine Mutation hat. Somit sind die Voraussetzungen für Evolution gegeben.

Ein grober Überblick über ECS

Die ECS-Architektur ist in drei Teile aufgeteilt. Entities, Components und Systems.

Entities sind alle „Dinge“, die im Spiel vorkommen. Entities selber haben keine Eigenschaften, sie sind nur dazu da Components zu beinhalten. Der einfachste Vergleich ist zu Unitys GameObjects, aber im Unterschied zu ihnen muss ein Entity nicht zwingend etwas sein, das „im Raum ist“. Abstrakte Daten die „nirgendwo“ sind können auch auf Entities untergebracht sein. In Petridish gibt es einige Arten von Entities, beispielsweise Blobs, Nutrients und verschiedene Daten-entities.

Components sind mit Entities assoziiert und beinhalten die Daten, die das Entity zu der Sache machen, die es sein soll. Beispielsweise haben Entities die Blobs sein sollen Components die ihre Position im Raum, ihre verbleibende Energie, ihre Gene und andere Daten beinhalten. Im Gegensatz zu OO Unity Components, haben ECS Components keine Methoden; können also nichts „tun“. Das ist die Aufgabe von Systems.

Systems beinhalten die tatsächliche Spiel-logik. Üblicherweise ist ein System durch eine Update Funktion definiert, die jedes Frame läuft und die Daten auf relevanten Entities updatet. Dazu definieren Systems an welchen Components sie interessiert sind und das ECS-Framework liefert diese für die Update Funktion. In Petridish gibt es beispielsweise ein „MoveTowardsTargetSystem“, dass jedes Frame alle Entities findet die eine Position im Raum haben und eine Ziel-position hinterlegt haben und bewegt dann diese Entities näher an ihr Ziel, indem sie ihre Positionen updatet.

Das ist nur ein extrem verkürzter Überblick über die Architektur, aber es gibt sehr gute Ressourcen zu dem Thema online, falls man mehr lernen will.

Learnings und Hürden

Ich bin sehr froh mich mit ECS beschäftigt zu haben. Der datenorientierte Workflow gefällt mir sehr gut und ich freue mich darauf mehr damit zu arbeiten. Besonders im Bereich Performance-optimierungen habe ich sehr viel gelernt. In ECS ist es viel üblicher sich mit den lower-level Features von C# auseinanderzusetzen, mit denen ich bis jetzt noch nichts zu tun hatte.

Bei sehr vielen Blobs leidet die Performance

Mit Petridish bin ich auch recht zufrieden, wobei ich sagen muss, dass es nicht so performant ist wie es vermutlich sein könnte. Das Hauptproblem ist die Logik, die berechnet was ein Blob sehen kann, da ich noch nicht sehr erfahren damit bin welche Datenstrukturen für ein effizientes spatial lookup am besten sind. Aber ich bin gespannt darauf, ob ich darüber in zukünftigen Projekten noch etwas lernen kann.

The comments are closed.