Ich habe ein Entity-System für einen FPS entworfen. Es funktioniert im Grunde so:
Wir haben ein "Welt" -Objekt namens GameWorld. Dies beinhaltet ein Array von GameObject sowie ein Array von ComponentManager.
GameObject enthält eine Reihe von Komponenten. Es bietet auch einen Ereignismechanismus, der wirklich einfach ist. Komponenten selbst können ein Ereignis an die Entität senden, das an alle Komponenten gesendet wird.
Komponente ist im Grunde etwas, das einem GameObject bestimmte Eigenschaften verleiht, und da GameObject eigentlich nur ein Container von ihnen ist, geschieht in den Komponenten alles, was mit einem Spielobjekt zu tun hat. Beispiele hierfür sind ViewComponent, PhysicsComponent und LogicComponent. Wenn eine Kommunikation zwischen ihnen erforderlich ist, kann dies durch die Verwendung von Ereignissen erfolgen.
ComponentManager ist genau wie Component eine Schnittstelle, und für jede Component-Klasse sollte es im Allgemeinen eine ComponentManager-Klasse geben. Diese Komponentenmanager sind dafür verantwortlich, die Komponenten zu erstellen und sie mit Eigenschaften zu initialisieren, die aus so etwas wie einer XML-Datei gelesen werden.
ComponentManager kümmert sich auch um Massenaktualisierungen von Komponenten, wie die PhysicsComponent, bei der ich eine externe Bibliothek verwenden werde (die alles auf der Welt auf einmal erledigt).
Aus Gründen der Konfigurierbarkeit verwende ich eine Factory für die Entitäten, die entweder eine XML-Datei oder ein Skript lesen, die in der Datei angegebenen Komponenten erstellen (die für Massenaktualisierungen auch einen Verweis darauf im rechten Komponentenmanager hinzufügen) und Füge sie dann in ein GameObject-Objekt ein.
Jetzt kommt mein Problem: Ich werde versuchen, dies für Multiplayer-Spiele zu verwenden. Ich habe keine Ahnung, wie ich das angehen soll.
Erstens: Welche Entitäten sollten die Kunden von Anfang an haben? Ich sollte damit beginnen, zu erklären, wie eine Einzelspieler-Engine bestimmen würde, welche Entitäten erstellt werden sollen.
Im Ebeneneditor können Sie "Pinsel" und "Objekte" erstellen. Pinsel sind für Dinge wie Wände, Böden und Decken im Grunde einfache Formen. Entities sind das GameObject, von dem ich dir erzählt habe. Beim Erstellen von Entitäten im Ebeneneditor können Sie Eigenschaften für jede seiner Komponenten angeben. Diese Eigenschaften werden direkt an einen Konstruktor im Skript der Entität übergeben.
Wenn Sie die Ebene für das Laden der Engine speichern, wird sie in eine Liste von Entitäten und deren zugehörigen Eigenschaften zerlegt. Die Pinsel werden in eine "Worldspawn" -Entität umgewandelt.
Wenn Sie diese Ebene laden, werden nur alle Entitäten instanziiert. Hört sich einfach an, oder?
Für die Vernetzung der Einheiten stoße ich nun auf zahlreiche Probleme. Erstens, welche Entitäten sollten von Anfang an auf dem Client vorhanden sein? Angenommen, sowohl der Server als auch der Client verfügen über die Level-Datei, könnte der Client genauso gut alle Entitäten in dem Level instanziieren, selbst wenn sie nur für die Zwecke der Spielregeln auf dem Server vorhanden sind.
Eine andere Möglichkeit besteht darin, dass der Client eine Entität instanziiert, sobald der Server Informationen darüber sendet. Dies bedeutet, dass der Client nur Entitäten hat, die er benötigt.
Ein weiteres Problem ist das Senden der Informationen. Ich denke, der Server könnte Delta-Komprimierung verwenden, was bedeutet, dass er nur dann neue Informationen sendet, wenn sich etwas ändert, anstatt bei jedem Frame einen Snapshot an den Client zu senden. Dies bedeutet jedoch, dass der Server den Überblick darüber behalten muss, was jeder Client im Moment weiß.
Und schließlich, wie soll das Networking in die Engine eingebunden werden? Ich denke an eine Komponente, NetworkComponent, die in jede Entität injiziert wird, die vernetzt werden soll. Aber woher sollte die Netzwerkkomponente wissen, welche Variablen vernetzt werden sollen und wie auf diese zugegriffen werden soll, und schließlich, wie die entsprechende Netzwerkkomponente auf dem Client die vernetzten Variablen ändern soll?
Ich habe große Probleme damit. Ich würde mich sehr freuen, wenn Sie mir auf dem Weg helfen würden. Ich bin auch offen für Tipps zur Verbesserung des Komponentensystemdesigns, also haben Sie keine Angst davor, dies vorzuschlagen.
quelle
Wollte einen Kommentar schreiben, entschied aber, dass dies genug Information für eine Antwort sein könnte.
Zuerst +1 für eine so schön geschriebene Frage mit Unmengen von Details, anhand derer die Antwort beurteilt werden kann.
Für das Laden der Daten hätte ich den Client die Welt aus der Weltdatei laden lassen. Wenn Ihre Entitäten über IDs verfügen, die aus der Datendatei stammen, würde ich sie auch standardmäßig laden, damit Ihr Netzwerksystem sie nur referenzieren kann, um zu wissen, um welche Objekte es sich handelt. Jeder, der die gleichen Anfangsdaten lädt, sollte bedeuten, dass alle für diese Objekte die gleichen IDs haben.
Zweitens sollten Sie keine NetworkComponent-Komponente erstellen, da dies nichts anderes bewirkt, als Daten in andere vorhandene Komponenten zu replizieren (Physik, Animation und dergleichen sind einige übliche Dinge, die übertragen werden müssen). Um Ihre eigene Benennung zu verwenden, möchten Sie möglicherweise einen NetworkComponentManager erstellen. Dies unterscheidet sich geringfügig von der Beziehung zwischen der anderen Komponente und dem ComponentManager. Dies kann jedoch ausgelöst werden, wenn Sie ein vernetztes Spiel starten und alle Arten von Komponenten, die einen Netzwerkaspekt haben, dem Manager ihre Daten zur Verfügung stellen, damit dieser sie packen kann und losschicken. Hier könnte Ihre Save / Load-Funktionalität zum Einsatz kommen, wenn Sie über einen Serialisierungs- / Deserialisierungsmechanismus verfügen, für den Sie, wie erwähnt, auch Daten packen können.
In Anbetracht Ihrer Frage und des Informationsniveaus glaube ich nicht, dass ich viel mehr ins Detail gehen muss, aber wenn etwas nicht klar ist, senden Sie bitte einen Kommentar und ich werde die Antwort aktualisieren, um dies zu beheben.
Hoffe das hilft.
quelle