Verwalten von Listen verschiedener Entitätstypen - gibt es einen besseren Weg?

9

Ich entwickle ein 2D-Weltraumspiel für mobile Geräte, aber es wird sehr komplex und meine Lösung ist sehr verwirrend und erzeugt viele wiederholte Codesegmente.

Ich habe eine Weltklasse, in der ich mehrere Listen verschiedener Objekte habe, wie:

List<Enemy> enemys;
List<Projectile> projectiles;
List<Collectable> collectables;
List<Asteroid> asteroids;
List<Effect> effects;
..

Jede Liste wird von der Weltklasse aktualisiert. Aber das ist noch nicht alles. Jeder Feind hat eine Liste von Motoren und eine Liste von Waffenluntern, die vom Feind aktualisiert werden. Jetzt fügt jeder Motor der Weltliste 'Effekte' einige Feuereffekte hinzu, und jeder Waffenwerfer fügt der Weltliste 'Projektile' Projektile hinzu. Alle diese Klassen haben unterschiedliche Parameter, daher benötige ich für jede Klasse ein zusätzliches Update UND eine zusätzliche Renderfunktion.

Zumindest sind sie alle Kinder von 'GameObject', das ihnen grundlegende Dinge wie Positions-, Geschwindigkeits- und Beschleunigungsvektoren, begrenzende Polygone und Funktionen wie applyForce und eine endliche Zustandsmaschine bietet

Gibt es einen besseren oder allgemeineren Weg, dies zu tun? wie eine Catch-All-Klasse, die alle möglichen Parameter und Methoden für alle verschiedenen Objekte enthält. (Ich denke, dies würde noch verwirrenderen Code erzeugen)

Nuss
quelle
Dies ähnelt meiner Frage: gamedev.stackexchange.com/questions/22559/… Ich schlage vor, die Antworten zu überprüfen , die es gegeben hat.
Derek

Antworten:

5

Gibt es einen besseren oder allgemeineren Weg, dies zu tun? wie eine Catch-All-Klasse, die alle möglichen Parameter und Methoden für alle verschiedenen Objekte enthält.

Ja, es wird eine Architektur genannt. Schauen Sie hier für Details.

Dies würde nur eine Liste von Entitäten in Ihrer Weltklasse zulassen:

List<Entity>

Es ist ein Beispiel für Komposition über Vererbung .

Laurent Couvidou
quelle
3

Innerhalb der Grenzen Ihrer ursprünglichen Frage besteht eine Option darin, die Listen in Aktionen anstatt in Typen wie die, die Sie haben, aufzuteilen. Zum Beispiel hätten Sie das List<HasAI>und eins für List<Collidable>und wenn Sie ein neues Objekt erstellen, fügt es sich selbst zu jeder benötigten Aktionsliste hinzu. Wenn das Objekt zerstört wird, entfernt es sich selbst aus diesen Listen. Ein Objekt kann sich in mehreren Listen befinden.

Schritt zwei dieser Option besteht darin, Ihre Klassen von einer Hierarchie in eine Hierarchie umzugestalten, die Schnittstellen verwendet. Ihr HasAI-Typ ist also eine Klasse, die die IBrains-Schnittstelle als Beispiel implementiert. Übereinstimmend, dass List<HasAI>nur Objekte die IBrains-Schnittstelle benötigen.

Das sollte helfen, einen Teil der Komplexität zu bereinigen.

Patrick Hughes
quelle
2

Ich denke, Sie müssen das Rendering in seine eigenen Klassen abstrahieren. Ich denke, eine für den Spieler und eine für den Feind (oder vielleicht nur eine für den Spieler) und dann eine Instanz für Spieler und Feind erstellen - nicht 100% sicher deines Spieldesigns.)

Sie können ein Besuchermuster verwenden, um den Renderer die verschiedenen Objekte durchlaufen zu lassen und zu entscheiden, was gezeichnet werden soll. Dies ist möglicherweise weniger komplex.

Nycynik
quelle
2

Die Verwendung einer Basisklasse und das Verlassen auf Polymorphismus ist eine sehr gute Idee. Es gibt jedoch einige alternative Ansätze. Es gibt zwei Artikel von Noel Llopis, die es wert sind, gelesen zu werden. Ich habe mich in letzter Zeit mit datenorientiertem Design befasst und denke, dass es einige Vorteile hat.

Die Artikel sind hier und hier . Es kann Ihren Code ein wenig mehr vereinfachen als Polymorphismus. Aber wie bei allem YMMV sollten Sie einen Blick darauf werfen, ob es zu dem passt, was Sie erreichen möchten. Polymorphismus verwendet Vererbung und DOD verwendet Aggregation. Beide haben Vor- und Nachteile. Wählen Sie also Ihr Gift.

Britchie
quelle
1

Sie können OOP und insbesondere Polymorphismus verwenden.

Grundsätzlich müssen Sie eine Basisklasse erstellen, von der alle Spielentitäten erben. Diese Basisklasse ist so abstrakt wie möglich und enthält Dinge wie eine Erstellungs-, Aktualisierungs- und möglicherweise eine Zerstörungsfunktion.

Dann leiten Sie alle Ihre anderen Spielobjekte aus dieser Klasse ab. Sie müssen wahrscheinlich auch eine Art Reflexion in Ihren Code einfügen, wenn Ihre Sprache dies nicht unterstützt, um einige fortgeschrittenere Dinge zu tun, aber es ist vermeidbar, wenn Sie wissen, wie Sie Ihre Vererbung richtig strukturieren.

Marlock
quelle
1
Er hat das bereits getan - alle seine Klassen sind Kinder von GameObject. Er muss nur seine Reihe von Listen in eine einzige Liste von GameObjects verwandeln.
SomeGuy