Ich versuche ein kurzes "Spiel" zu schreiben, in dem ein Spieler herumläuft und Monster bekämpft, aber ich habe keine Ahnung, wie ich mit dem Kampf umgehen soll.
Angenommen, ich habe einen "Krieger" und einen "Troll". Wie kämpfen die beiden gegeneinander? Ich weiß, dass ich so etwas tun kann
Conan = Warrior.new();
CaveTroll = Troll.new();
Conan.attack(CaveTroll);
CaveTroll.attack(Conan);
Aber welcher Teil des Spiels kontrolliert das Monster? Halte ich die obige Sequenz einfach in eine Schleife, bis einer von ihnen stirbt? Oder muss die "Engine" des Spiels einen Teil haben, der sich speziell mit Kämpfen befasst? Oder ist dies ein Aspekt der künstlichen Intelligenz des Trolls, der sich um seine Handlungen kümmern muss?
Und wer / was bestimmt die Aktionen, die das Monster ausführt? Vielleicht kann ein Troll zuschlagen, treten, beißen, Zauber wirken, Tränke trinken, einen magischen Gegenstand benutzen. Bestimmt die Spiel-Engine, welche Aktion der Troll ausführt, oder ist das etwas, was die Troll-Klasse verwaltet?
Entschuldigung, ich kann nicht genauer sein, aber ich brauche eine Anleitung, in welche Richtung ich gehen soll.
Antworten:
Ich stelle mir eine Kampfsequenz als Minispiel in Ihrem Spiel vor. Aktualisierungs-Ticks (oder Turn-Ticks) werden an eine Komponente gerichtet, die diese Ereignisse behandelt. Dieser Ansatz kapselt die Schlachtsequenzlogik in einer separaten Klasse und lässt Ihrer Hauptspielschleife den Übergang zwischen den Spielstatus frei.
Die Battle Sequence-Klasse würde folgendermaßen aussehen:
Ihr Troll und Ihr Krieger erben beide von einer gemeinsamen Superklasse namens Entity. Innerhalb von HandleTurn darf sich das angreifende Objekt bewegen. Dies entspricht einer AI-Denkroutine.
Die Kampfmethode entscheidet, was die Entität tun wird. Beachten Sie, dass dies nicht die gegnerische Entität betreffen muss, wie das Trinken eines Tranks oder das Weglaufen.
Update: Um mehrere Monster und eine Spieler-Gruppe zu unterstützen, führen Sie eine Gruppenklasse ein:
Die Gruppenklasse ersetzt alle Vorkommen von Entitäten in der Klasse BattleSequence. Das Auswählen und Angreifen wird von der Entity-Klasse selbst durchgeführt, sodass die KI die gesamte Gruppe bei der Auswahl der besten Vorgehensweise berücksichtigen kann.
quelle
Ich hätte ein dediziertes Kampfobjekt, das den Kampf verwaltet. Es würde den vollständigen Kampfzustand einschließen, einschließlich der Liste der Spielercharaktere, der Liste der Feinde, der aktuellen Runde, des Kampfgeländes und so weiter. Combat kann dann eine Aktualisierungsmethode haben, die die Kampflogik verwaltet. Es ist keine gute Idee, den Kampfcode einfach in eine einfache Schleife zu setzen, da er sehr schnell enden würde. Normalerweise hat man ein wenig Zeit und verschiedene Kampfphasen.
Für die durchgeführten Aktionen kann man es sicherlich nur zufällig machen, aber für ein Monster mit vollen HP wäre es wenig sinnvoll, einen Heilzauber zu wirken. Es lohnt sich, eine grundlegende Logik zu haben, um zu bestimmen, welche Aktion durchgeführt werden soll. Einige Aktionen haben möglicherweise eine höhere Priorität als andere (z. B. Troll-Kicks 30% der Zeit) und andere Bedingungen, um Schlachten interessanter zu gestalten (z. B. wenn die Troll-HP weniger als 10% der vollen HP beträgt, gibt es 20%. Chance, einen Heilzauber zu wirken, sonst beträgt die Chance 1%). Dies kann so komplex sein, wie Sie möchten.
Ich denke, die Monsterklasse sollte die Auswahl der auszuführenden Aktion übernehmen. Das Kampfobjekt fordert das Monster auf, eine Aktion auszuführen, und das Monster trifft eine Auswahl und wendet diese dann an. Eine Idee ist, ein Strategieobjekt zu haben, das Sie in Monster einbinden und das aus der Liste der möglichen Monsteraktionen basierend auf den Prioritäten, Kategorien und Bedingungen, die jeder Kampfaktion zugewiesen sind, auswählt. Dann können Sie zum Beispiel eine OffensiveStrategy-Klasse haben, die Angriffe gegenüber defensiven Fähigkeiten priorisiert, und eine andere CautiousStrategy, die mit größerer Wahrscheinlichkeit heilt. Ein Boss ist möglicherweise in der Lage, die Strategie basierend auf seinem aktuellen Zustand dynamisch zu ändern.
Eine letzte Sache. Möglicherweise möchten Sie entweder, dass sowohl Spielercharaktere als auch Monster von derselben Klasse geerbt werden, Instanzen derselben Klasse (z. B. Schauspieler oder Kombattant) sind oder ein gemeinsames Objekt gemeinsam nutzen, in dem die gemeinsamen Funktionen zusammengefasst sind. Dies reduziert die Codeduplizierung und ermöglicht es Ihnen, KI-gesteuerte NPCs an Ihrer Seite zu haben, die die gleichen Strategien implementieren können, die Sie bereits für Monster codiert haben.
quelle
Ja, Sie müssen ein spezielles Teil in Ihrem Motor haben, das für den Kampf zuständig ist.
Ich weiß nicht genau, wie du deinen Kampf ausführst, aber ich gehe davon aus, dass die Spieler durch die Spielwelt streifen, sich mit Monstern treffen und der Kampf in Echtzeit stattfindet. Wenn ja, muss der Troll die Umgebung in einem bestimmten Bereich kennen, vielleicht definieren, wie weit der Troll etwas davor sehen kann (Troll handhabt dies).
Was die KI anbelangt, muss die Engine selbst damit fertig werden. Nehmen wir also an, Sie haben mehr als eine Art von Feind, der dasselbe tun kann (Biss). Sie können die KI einfach einem anderen Monster zuweisen und los geht's!
quelle
Dein Spieler und dein Troll sind nichts als Datensätze, was wir das Datenmodell nennen, das deine Welt beschreibt. Leben, Inventar, Angriffsmöglichkeiten, sogar ihr Wissen über die Welt - alles besteht im Datenmodell.
Behalten Sie ein einzelnes Hauptmodellobjekt bei, das alle Daten enthält, die Ihre Welt beschreiben. Es wird allgemeine Weltinformationen wie Schwierigkeitsgrad, physikalische Parameter usw. enthalten. Es wird auch eine Liste / ein Array von Daten bestimmter Entitäten enthalten , wie ich oben beschrieben habe. Dieses Hauptmodell kann aus vielen Unterobjekten bestehen, um Ihre Welt zu beschreiben. Nirgendwo in Ihrem Modell sollten Sie Funktionen haben, die die Spiel- oder Anzeigelogik steuern. Getter sind die einzige Ausnahme und werden nur verwendet, um Ihnen den einfacheren Abruf von Daten aus dem Modell zu ermöglichen (wenn öffentliche Mitglieder dies nicht bereits tun).
Als nächstes erstellen Sie Funktionen in einer oder mehreren "Controller" -Klassen. Sie können sie alle als Hilfsfunktionen in Ihre Hauptklasse schreiben, obwohl dies nach einer Weile ein bisschen groß werden kann. Diese werden als jedes Update bezeichnet, um auf die Daten der Entitäten für verschiedene Zwecke (Bewegung, Angriff usw.) zu reagieren. Das Aufbewahren dieser Funktionen außerhalb einer Entitätsklasse ist ressourceneffizienter. Wenn Sie wissen, was Ihre Entität beschreibt, wissen Sie automatisch, welche Funktionen darauf reagieren müssen.
Ein letzter Hinweis ist, dass es auch nützlich ist, die Anzeigelogik von der Spielelogik zu trennen. Die Anzeigelogik würde lauten: "Wo und in welcher Farbe zeichne ich das auf dem Bildschirm?" Spiellogik ist das, was ich oben im Pseudocode umrissen habe.
(Anmerkung von Dev: Während der Verwendung von Klassen folgt dies locker einem funktionalen Programmieransatz, der alle Methoden als ideal zustandslos ansieht, was ein sauberes Datenmodell und einen Verarbeitungsansatz ermöglicht, der Fehler minimiert, die durch den beibehaltenen Zustand verursacht werden. FP ist die ultimative MVC, da sie MVCs erreicht Ziel der Trennung von Anliegen explizit. Siehe diese Frage .)
quelle