Hallo Leute,
brauche mal einen Denkanstoß in Sachen Entity Component System und Performance.
Geschichte
Ich habe angefangen für ein Schulprojekt ein kleines runden basierendes RPG zu entwickeln. Entwickelt wird mit JavaScript in Visual Code und PIXIJS als Render Library.
Im Prinzip ist man in einem kleinen Dungeon (Tile Map) welcher X Gegner enthält. Pro Runde kann sich entweder der Gegner oder der Spieler bewegen. Sind Spieler/Gegner in Reichweite, greift das Kampf-System in welchem man wie der Name schon sagt kämpft. Nun habe ich schon viele gute Sachen über das Entity Component System gehört und angefangen das Spiel mit diesem Pattern zu entwickeln. In meiner Implementierung gibt es vier Akteure: Das Entity, den EntityManager, die Komponenten und die Systeme.
Entity
Meine Entities bestehen aus einer Sammlung von Komponente und einer GUID um diese "eindeutig" zu identifizieren.
Bspw. besteht das PlayerEntity aus einer Transform-/Render-/Collision-/Player - Komponente.
Dabei hat jedes Entiy eine eigene Liste mit seinen Komponenten.
EntityManager
Kümmert sich um das erstellen und löschen der Entitys. Führt außerdem eine Liste aller verfügbaren Entities.
Desweiteren habe ich hier eine Funktion implementiert, mit welcher ich Entities anhand Ihrer Komponenten filtern kann.
Komponenten
Reine Datenklassen, welche wenig bis keine Funktionalität bieten.
System
Die Systeme sind momentan so angeordnet:
Input System -> MovementSystem -> AnimationSystem -> RenderSystem
Input System: Kümmert sich um den Input. Im Prinzip habe ich einfach nur von meinem CANAS das click Event subscribed, wodurch ich eben die aktuelle Mausposition auf dem CANVAS bekomme.
MovementSystem: Kümmert sich darum das die Entities vom Start zum Ziel kommen.
AnimationSystem: Hier wird geprüft welcher State das Entity hat und welches Frame vom jeweiligen Spritesheet gezeichnet werden soll.
RenderSystem: Hier übernimmt PIXIJS das meiste, aber wie man sich schon denken kann werden hier letztendlich die Sprites gerendert.
Jedes System weiß schon zur compile time welche Komponenten ein Entity haben muss, um bearbeitet zu werden.
Hier wird dann praktisch jeden "Update Zyklus" nach den jeweiligen Entities gefiltert.
Das hat natürlich den extremen Nachteil das jedes System jedes mal alle Entities durchläuft.
An sich bin ich wirklich zufrieden mit den Ansätzen die ich jetzt schon habe nur ergibt sich ein riesen Problem
Problem
Sobald ich mehrere Sprites auf einmal rendere bspw. 21x14 Tile Map und einen Spieler, merkt man wie die Performance ziemlich weit runter geht.
So wie es momentan aufgebaut ist, werde ich wohl ab einer gewissen Anzahl von Systemen/Entities extreme Performance Probleme bekommen.
Das wird auch an dem oben genannten Problem mit den ganzen iterationen über alle Objekte in jedem System liegen.
Frage
Auf Google finde ich meistens nur Aritkel welche die absoluten Basics behandeln oder in welchen dann hardwarenahe Sprachen benutzt werden (Obj. C, C++ ...) und wo es dann um Speicheradressierung und den ganzen kram geht.
Wie bekomme ich das ganze System flotter bzw. wie würdet Ihr an die Sache rangehen?
Momentan würde mir ehrlich gesagt nur cachen in den Sinn kommen. Bspw. werden beim Spielstart alle Entities durchlaufen und in einem Cache abgelegt. Wenn ich nun neue Entities hinzufüge oder lösche, wird der Cache wieder aktualisiert. Somit müssen die Systeme zumindest nur noch "Ihren Teil" abarbeiten und nicht immer und immer wieder alles Entities filtern.
Vielen Dank für eure Zeit!