Ich mache ein Java Shoot Em Up-Spiel für Android-Handys. Ich habe 20 seltsame Gegner im Spiel, die jeweils ein paar einzigartige Verhaltensweisen haben, aber bestimmte Verhaltensweisen werden von den meisten von ihnen wiederverwendet. Ich muss Kugeln, Explosionen, Asteroiden usw. und andere Dinge modellieren, die alle ein bisschen wie Feinde wirken. Mein derzeitiges Design favorisiert die Komposition über die Vererbung und stellt Spielobjekte so dar:
%Vor%Um nur das zu zeichnen, was als Entitätsbild gespeichert ist, können Sie einen einfachen Renderer, z. B.
, anhängen %Vor%Um die Entity um jeden Frame herumzufliegen, fügen Sie einfach ein Verhalten wie dieses an:
%Vor%Oder fügen Sie ein komplexeres Verhalten hinzu, z. B. warten Sie, bis sich der Player in der Nähe befindet, bevor Sie sich einmelden:
%Vor%Ich bin sehr glücklich mit diesem Design bisher. Es ist schön und flexibel, dass Sie z.B. Modularisieren Sie die letztere Klasse so, dass Sie das "Schlaf" - und das "Wach" -Verhalten bereitstellen können, damit Sie etwas wie "WaitUntilCloseBehaviour" sagen können (player, 50 / pixels /, new MoverRandomlyBehaviour (), new HomingBehaviour ( )). Dies macht es wirklich einfach, neue Feinde zu machen.
Der einzige Teil, der mich beschäftigt, ist, wie die Verhaltensweisen und die Renderer kommunizieren. Momentan enthält Entität ein Image-Objekt, das von einem Verhalten geändert werden könnte, wenn dies der Fall ist. Zum Beispiel könnte ein Verhalten das Objekt zwischen einem Schlaf- und einem Wach-Bild ändern und der Renderer würde das Bild einfach zeichnen. Ich bin mir nicht sicher, wie dies skalieren wird, z. B.:
Was ist mit einem Turm ähnlichen Feind, der in eine bestimmte Richtung weist? Ich denke, ich könnte der Entität ein Rotationsfeld hinzufügen, das Verhalten und Renderer beide modifizieren / lesen können.
Was ist mit einem Tank, wo der Tankkörper und die Kanone des Tanks unterschiedliche Richtungen haben? Jetzt benötigt der Renderer Zugriff auf zwei Rotationen von irgendwo und den zwei zu verwendenden Bildern. Sie möchten die Entity-Klasse nicht wirklich aufblähen, wenn nur ein Tank vorhanden ist.
Was ist mit einem Feind, der glüht, wenn seine Waffe aufgeladen wird? Sie möchten die Ladezeit wirklich im Behavior-Objekt speichern, aber die Renderer-Klasse kann sie nicht sehen.
Ich habe Probleme, über Möglichkeiten nachzudenken, die oben genannten zu modellieren, damit die Renderer und die Verhaltensweisen etwas getrennt bleiben können. Der beste Ansatz, den ich mir vorstellen kann, ist, dass die Verhaltensobjekte das zusätzliche Status und des Rendererobjekts enthalten, dann rufen die Verhaltensobjekte die Renderer-Draw-Methode auf und geben den zusätzlichen Status (z. B. Rotation) weiter zu.
Sie könnten dann z.B. habe ein tankartiges Behaviour-Objekt, das einen tankartigen Renderer haben möchte, wobei letzterer nach den zwei Bildern und zwei Drehungen fragt, um damit zu zeichnen. Wenn Sie möchten, dass Ihr Tank nur ein einfaches Bild ist, würden Sie einfach einen Unterklassen-Renderer schreiben, der die Rotationen ignoriert.
Kann jemand an Alternativen denken? Ich will wirklich Einfachheit. Da es ein Spiel ist, kann Effizienz auch ein Problem sein, wenn z.B. ein einzelnes 5x5-Feindbild zu zeichnen, wenn ich 50 Feinde mit 60fps herumfliegen lasse, beinhaltet viele Schichten von Funktionsaufrufen.
Der Kompositionsentwurf ist ein gültiger Entwurf, da er es ermöglicht, die Verhaltensweisen und das Rendering zu mischen und anzupassen.
In dem Spiel, mit dem wir spielen, haben wir einen "databag" hinzugefügt, der grundlegende Informationen enthält (in Ihrem Fall die Position und den Status dead / alive) und Variablen, die durch das Verhalten und / gesetzt werden Kollisions-Subsytem. Der Renderer kann diese Daten dann verwenden (oder nicht, wenn sie nicht benötigt werden). Dies funktioniert gut und ermöglicht einen ordentlichen Effekt, z. B. das Setzen eines "Ziels" für einen gegebenen grafischen Effekt.
Ein paar Probleme:
Momentan verwenden wir eine HashMap für den Databag, aber dies ist auf einem PC, nicht auf einem IPhone. Ich weiß nicht, ob die Leistung ausreicht, in welchem Fall eine andere Struktur besser sein könnte.
Auch in unserem Fall haben wir uns für einen speziellen Renderer entschieden. Wenn die Entität beispielsweise nicht-leere Shield-Daten besitzt, zeigt der ShieldRenderer die Repräsentation an ... In Ihrem Fall könnte der Tank zwei Renderer haben, die mit zwei (initialisierungsdefinierten) Daten verknüpft sind:
%Vor%mit "TankRotation" und "TurretRotation", festgelegt durch das Verhalten. und der Renderer dreht einfach das Bild, bevor es an der Position angezeigt wird.
%Vor%Hoffen Sie diese Hilfe
Grüße
Guillaume
Das Design, mit dem du gehst, sieht gut aus. Dieses Kapitel zu Komponenten kann Ihnen dabei helfen.