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:
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).
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?
quelle
Antworten:
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.
quelle