Intersystemkommunikation in einem ECS-Spiel


8

Entschuldigung, wenn diese Frage schon einmal beantwortet wurde, aber nach unermüdlicher Suche konnte ich nichts finden.

Wie viele habe ich kürzlich auf den ECS-Zug gesprungen, und ich töte derzeit einige Zeit, indem ich ein bescheidenes ECS-Spiel mache. Das Spiel ist ein etwas einfaches 2D-Plattformspiel. Es ist in einfachem JS programmiert.

Das Layout des Spiels ist im Wesentlichen wie folgt:

Der Kern des Spiels ist die Engine. Die Engine führt die Spielschleife aus und enthält einen EventManager, der für das Auslösen von Ereignissen verantwortlich ist, und einen EntityManager, der für die Aufnahme aller Komponenten aller Entitäten verantwortlich ist.

Die gesamte Logik wird von Systemen ausgeführt. Das System registriert Event-Handler (dh Member-Funktionen) beim EventHandler für bestimmte EventTypes, die aufgerufen werden, wenn ein Ereignis dieses Typs ausgelöst wird.

Zum Beispiel:

this.eventManager.registerHandler(EventType.EVENT_RENDER, this.render, null, this);

Ich habe kürzlich vom expliziten Aufrufen aller systemrelevanten Funktionen in der Engine zu diesem Muster gewechselt.


Aber rüber zu meinem Problem und meiner Frage.

Zum Rendern habe ich ein RenderSystem. Dieses System enthält Verweise auf verschiedene Arten von zeichnbaren / animierbaren Komponenten, die es, wie Sie vermutet haben, rendert.

Bis vor kurzem enthielt dieses System auch einen Verweis auf ein anderes System , MapSystem, das alle Entitäten räumlich indiziert. Der Grund für diese Referenz war, eine Funktion nach dem Vorbild von aufrufen zu können

mapSystem.search(frame_bound);

Alle Entitäten, die nicht gerendert werden müssen, werden effektiv entfernt.

Ich habe also ein paar Fragen dazu:

  1. Ist es eine sehr schlechte Praxis für Systeme, direkt zu kommunizieren? Etwas daran riecht für mich einfach nicht richtig.

    Ich sehe, wie es Ihren Code ernsthaft komplizieren kann, wenn Sie sagen, 100 Systeme, und jedes System enthält Verweise auf viele der anderen Systeme. Hallo O (n ^ 2).

  2. Wie führe ich eine Kommunikation wie oben beschrieben durch, wenn ich keine systemübergreifenden Referenzen haben soll?


Meine ersten Gedanken waren, eine Entität zu erstellen, deren Hauptzweck darin bestand, die erforderlichen Informationen zu speichern (dh alle Entitäten, die sich derzeit im Rahmen befinden). Lassen Sie dann MapSystem in diese Entität schreiben und RenderSystem daraus lesen.

Das scheint mir aber auch ziemlich unrein zu sein. Insbesondere, da die MapSystems-Suchfunktion nützlich sein kann, um in vielen verschiedenen Kontexten aufzurufen. Das Erstellen einer Entität pro aufrufendem Kontext scheint auch kein guter Weg zu sein.


TL; DR: Ist es schlecht für Systeme in einem ECS-Spiel, direkt zu kommunizieren und Verweise aufeinander zu halten?



Obwohl sie mir keine direkte Antwort gaben, wiesen sie mich definitiv irgendwo in die richtige Richtung. Vielen Dank! Ich denke, was ich jetzt versuchen werde, ist ein Nachrichtenübermittlungssystem zwischen Systemen zu implementieren, das es mir ermöglicht, synchron nach Dingen wie allen Entitäten in einer bestimmten Grenze usw.
abzufragen

Antworten:


3

Grundsätzlich sollten Ihre Systeme nicht miteinander kommunizieren müssen. Es kann Fälle geben, in denen Systeme implizit interagieren, diese Interaktion sollte jedoch nicht explizit sein. Wenn Systeme miteinander interagieren müssen , haben Sie die Systeme wahrscheinlich nicht richtig definiert.

Bevor ich mich mit einigen Beispielen befasse, um den Punkt zu veranschaulichen, möchte ich definieren, um welche Art von Entitätskomponenten-System es sich handelt. Sie haben Entitäten, die nichts tun, und Komponenten, die ihr Verhalten definieren. Das tatsächliche Verhalten ist in Systemen implementiert. denn das ist die effizienteste Sache. Entitäten haben Eigenschaften und Ereignisse, die von mehreren Komponenten gelesen, geschrieben oder ausgelöst werden können.


Nehmen wir an, Sie implementieren eine Rakete. Das Grundverhalten des Flugkörpers wird durch eine Führungskomponente (ein Skript) gesteuert, die tatsächliche Bewegung wird durch eine Komponente der Starrkörperphysik gesteuert, die Detonation wird durch eine Auslösekomponente (ein Skript) gesteuert, die visuelle Darstellung erfolgt über eine visuelle Netzkomponente und Der Ton wird über eine Punktklangkomponente ausgegeben. Die Führungskomponente legt die Kraftvektoreigenschaft fest und die Starrkörperphysik bewegt die Entität und damit somit auch Position und Orientierung (unter anderem). Die Triggerkomponente hört auf das Kollisionsereignis. Wenn also eine Kollision mit einer anderen Entität auftritt, wird sie aktiv und stellt sicher, dass Chaos auftritt.

Bei der Implementierung des Flugkörpers sind Grafik, Sound, Physik und Skriptsystem beteiligt. Die tatsächliche Interaktion findet nur über ihre Komponenten statt.


Nehmen wir an, Sie haben ein fotorealistisches Spiel und das Grafiksystem ist das primäre Mittel zum Rendern der Szene. Sie möchten eine Karte als Überlagerung. Es gibt zwei Möglichkeiten, dies zu implementieren: Entweder Sie erweitern das Grafiksystem, um auch Karten zu zeichnen (schlecht), oder Sie fügen ein Kartensystem hinzu (gut). Um auf das eigentliche Grafikgerät zuzugreifen, ruft das Mapping-System das Grafiksystem nicht auf. Sie extrahieren das Grafikgerät (Hardware-Abstraktion) aus dem Grafiksystem und übergeben dann dem Mapping-System und dem Grafiksystem das Grafikgerät und diese verwenden es nacheinander.


Schließlich finde ich die Vorstellung, dass das Grafiksystem das Mapping-System nach einer ungeraden Liste sichtbarer Elemente fragt. Das Grafiksystem sollte eine Liste sichtbarer Elemente führen, die vorzugsweise in einer speziell optimierten Struktur wie einem Quad-Baum gespeichert sind. Sie können im Kontext eines 2D-Spiels damit durchkommen, aber sobald Sie 3D spielen, geraten Sie in echte Schwierigkeiten.


1
Eine kleine Kopplung zwischen Systemen ist meiner Erfahrung nach keine schlechte Sache und klarer, als sich auf Ereignisse oder ähnliches zu verlassen, um zwischen Systemen zu kommunizieren. Ich neige dazu, einige gekoppelte Systeme zu haben (referenzierte Systeme in den Spalten ganz rechts) - sie fungieren normalerweise als "unterstützende" Systeme, wie das GridSystem.
Junkdog

Danke für die Antwort rioki! Sie sagen also im Wesentlichen, dass ich in allen Systemen, in denen ich Entitäten / Komponenten aus bestimmten Regionen extrahieren muss, Kopien relevanter Entitäten (in einem Quadtree) speichern sollte? Meine Argumentation für die erwähnte Kopplung zwischen den beiden Systemen (und auch dem Bewegungssystem und dem Kartensystem) war, dass ich keinen Quadtree pro relevantem System haben musste, sondern einen im Kartensystem.
trmd

@trmd Sie haben mehrere Möglichkeiten. Sie können einen Quad-Baum in der Szene oder einen pro System haben. Die Sache ist, dass jedes System nur die relevanten Entitäten in seiner Struktur hat und unterschiedliche Organisationsstrukturen verwenden kann.
Rioki

1
@junkdog Du musst jedes Problem immer mit etwas Pragmatismus angehen. Im Idealfall ist eine lose Kupplung das Optimum. Wenn Sie ein System entfernen oder ersetzen können, ohne etwas anderes zu ändern, haben Sie es richtig gemacht. Aber manchmal erhöht die Reduzierung der Kopplung die Komplexität des Systems drastisch. Dann müssen Sie einen Gleichgewichtspunkt finden, an dem der Gewinn an Flexibilität nicht durch die erhöhte Codebasis verloren geht.
Rioki
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.