Struktur der RTS-Spieleinheiten

18

Ich möchte eine Möglichkeit haben, viele verschiedene Einheiten zu erstellen, ohne Dinge wie MoveTo- und Attack-Aktionen mehr als einmal programmieren zu müssen

So wie ich es sehe, gibt es zwei Möglichkeiten, wie ich das tun kann.

  1. Eine einzelne generische Unit-Klasse mit Flags, die angeben, was sie kann / nicht kann (dann Instanzen in einem statischen Array erstellen und bei Bedarf abrufen).
  2. Abstrakte Einheitenklasse mit abstrakten Methoden für einheitenspezifische Aktionen wie (Attack, Harvest, Patrol), die dann alle in den Unterklassen implementiert werden müssen , auch wenn die Einheit eigentlich nichts ernten kann.

Der erste Weg, dies zu tun, scheint der einfachste zu sein, aber ich würde viel Code haben, der für die Mehrheit der Einheiten nicht verwendet wird.

der zweite weg könnte auch funktionieren. Aber wenn ich mich für zwei verschiedene Einheiten entscheide, die Ressourcen ernten können, werde ich genau den gleichen Code in zwei verschiedenen Klassen haben, was nicht der richtige Weg zu sein scheint.

Ist das überhaupt der richtige Ansatz für dieses Problem?
In einem Spiel wie AoE hat jede Einheit, was ich annehme, eine Art Liste von Aktionen / Befehlen. Ich würde wirklich gerne wissen, wie man etwas Ähnliches erreicht, bei dem ich jede Aktion / Befehl nur einmal codieren kann und Geben Sie es dann allen Einheiten, die diese Aktion benötigen.

Wenn ich unklar bin (sehr plausibel) oder Sie weitere Informationen benötigen, was genau ich suche, fragen Sie mich einfach in einem Kommentar.

Daniel Holst
quelle

Antworten:

25

Ein gängiger Ansatz ist ein komponentenbasierter Ansatz, bei dem die Basisklasse "Einheit" nur die grundlegendsten Aspekte implementiert, die alle Einheiten gemeinsam haben, während jede Einheit dann eine Liste mit mehreren Komponentenobjekten hat, die angeben, was sie kann und kann wie es das macht.

Zum Beispiel könnte ein Tank die Komponenten hat Mobile, Destructible, Attacker, ein unbeweglichen Revolver nur Destructible, Attackerund ein Mähdrescher Mobile, Destructible, Harvester. Diese Klassen würden dann den gesamten Code enthalten, der zum Implementieren dieser Verhaltensweisen erforderlich ist. Interaktionen zwischen Komponenten (und Attackerkönnen nur das beschädigen, was ist Destructible) können implementiert werden, indem die Komponente überprüft wird, ob die andere Einheit die erforderliche Komponente hat, und dann direkt mit dieser Komponente interagiert wird.

Der Vorteil gegenüber einer klassischen Klassenvererbung ist, dass Sie Fähigkeiten einfach kombinieren können. Wenn Sie beispielsweise einen Mähdrescher haben möchten, der auch Infanterie angreifen, transportieren und fliegen kann, müssen Sie nur die erforderlichen Komponenten hinzufügen. Sie können auch problemlos neue Features in Form neuer Komponenten hinzufügen und entfernen, ohne die Basis-Einheitenklasse aufblähen zu müssen.

Unity unterstützt Sie in einer solchen Architektur, da die gesamte Engine bereits komponentenbasiert ist. So können solche spiellogischen Komponenten in Form von Skripten hinzugefügt werden.

Philipp
quelle
Würde ich dann in Unity die Komponenten nach Bedarf deaktivieren und aktivieren?
Daniel Holst
@DanielHolst Nein, Sie würden sie nach Bedarf hinzufügen und entfernen. Sie können dies im Unity-Editor oder mit Scripten mit gameObject.AddComponentund tun gameObject.RemoveComponent.
Philipp
ah okay, aber sag für eine "moveTo" Aktion / Bestellung. Wie würde das Gerät wissen, wann die Bestellung abgeschlossen ist und wie würde ich die Bestellungen in die Warteschlange stellen?
Daniel Holst
2
@DanielHolst Ich denke du hast etwas falsch verstanden. Die MovingKomponente bedeutet "diese Einheit ist im Allgemeinen beweglich". Die Komponente ist permanent daran befestigt, unabhängig davon, ob sich das Gerät bewegt oder nicht. Es bedeutet nicht , dass es sich bewegt jetzt . Sie können dies jedoch auch auf diese Weise tun, indem Sie eine MoveOrderKomponente hinzufügen und diese Komponente von der Einheit entfernen, wenn die Bestellung ausgeführt oder storniert wird.
Philipp
1
@DanielHolst Nun driftest du in Richtung der Einheit AI, die eine ganze andere Dose Würmer ist. Ein möglicher Ansatz wäre eine Bibliothek von AIScript-Komponenten, die entweder davon ausgehen, dass bestimmte Komponenten vorhanden sind, oder deren Verhalten in Abhängigkeit davon ändern, über welche Komponenten das Gerät verfügt. Aber das ist wirklich ein viel zu komplexes Thema, um es in einem Kommentar zu behandeln.
Philipp
4

Viele Spiele verwenden ein komponentenbasiertes System für Entitäten , bei dem eine Reihe von Verhaltensweisen und Fähigkeiten zu einem allgemeineren Einheitentyp hinzugefügt werden können, anstatt als Teil der Klasse (oder eines Äquivalents) der Entität codiert zu werden.

Ross Taylor-Turner
quelle
Wäre dies äußerst schwierig umzusetzen?
Daniel Holst
Muster wie dieses werden verwendet, um die Implementierung insgesamt zu vereinfachen. Wenn Sie sich nicht für einen Ansatz entscheiden können, ist es eine gute Idee, so einfach wie möglich zu beginnen und Ihre Auswahl zu erweitern, je mehr Funktionen Sie haben. Sobald Sie ein besseres Gefühl für das Problem haben, können Sie entweder eine Umgestaltung vornehmen oder einen Ansatz wählen, der besser zu Ihrer Situation passt.
Ross Taylor-Turner
1
@DanielHolst Mir ist aufgefallen, dass Ihre Frage die UnityFlagge hat. Unity verfügt bereits über ein integriertes Komponentensystem und bevorzugt die Komposition gegenüber der Vererbung . Eine einfache Methode wäre, eine MonoBehaviourfür jeden Ihrer Aktionstypen zu erstellen und dann an jeden Einheitentyp die Aktionen anzuhängen, die er ausführen kann (Anpassen der Aktionsinstanzen mit typspezifischen Details wie Schadenswerten und Kosten). Auf diese Weise bleibt die Datenerstellung Ihrer Einheit abhängig, sodass Sie auf einfache Weise viele benutzerdefinierte Einheitentypen erstellen können.
DMGregory
@DanielHolst Das hängt von deiner Definition von "extrem schwierig" ab. Meine Antwort geht näher darauf ein, wie dies umgesetzt werden könnte.
Philipp