Wie gehe ich mit mehreren Story-Threads in einem RPG-Spiel um?

26

Ich habe ein RPG-Spiel mit mehreren Story-Threads entworfen. Je nach Wahl des Benutzers können einige Dinge passieren oder auch nicht. Sie können dasselbe auf verschiedene Weise erreichen. Das Ende kann unterschiedlich sein und so weiter.

Ich habe eine einfache Entscheidungs-Engine implementiert, die funktioniert, aber einen großen Fehler aufweist. Sobald Sie eine Entscheidung treffen, wird die Geschichte sofort von Ihrer Entscheidung beeinflusst. Das bedeutet, dass Sie keine Entscheidung treffen können, die Sie in ferner Zukunft betrifft . Dies liegt daran, dass sich die Story wie ein Zweig in einer Baumstruktur entfaltet und immer wissen muss, welcher Knoten der nächste ist. Unter der Haube werden die Entscheidungen mithilfe einer Warteschlange implementiert: Jeder Knoten kennt den vorherigen und den nächsten Knoten (oder wenn es sich um einen Entscheidungsknoten handelt, wartet er auf Benutzereingaben, um den nächsten Knoten festzulegen).

Ich habe viele Spiele mit komplexen Entscheidungsprozessen gesehen und ich frage mich, wie sie gemacht werden. Gibt es ein spezielles Design, das die Dinge wirklich einfach macht? Hat jemand etwas Ähnliches gemacht und kann mir einen Hinweis geben, wie ich das angehen kann?

UPDATE 1:

Ein wichtiger Aspekt ist es, den Story-Code irgendwie unabhängig zu halten, damit er aus einer externen Datei heraus bearbeitet werden kann. Ich plane, dies als Engine zu verwenden, sodass selbst die möglichen Auswahlen aus einer externen Datei stammen müssen. Der Code muss absolut abstrakt sein.

Außerdem interessiere ich mich für eine Designlösung, eine gute Möglichkeit, dies zu tun, wie andere es tun oder getan haben.

Valentin Radu
quelle
1
Wenn wichtige Entscheidungen getroffen wurden, behalten Sie diese einfach in einer global zugänglichen Variablen im Auge (ein Array dieser Variablen ist einfacher zu verwalten). Diese Variablen können dann von späteren Teilen Ihres Spielprogramms referenziert werden, um entsprechend zu handeln oder Dinge anzuzeigen. Zum Beispiel beschließt der Spieler, einen kleinen Baum zu pflanzen, und später erscheint dieser Baum sehr groß. Wenn er den Baum nicht gepflanzt hätte, wäre dieser Baum zu diesem späteren Zeitpunkt im Spiel überhaupt nicht mehr vorhanden.
Randolf Richardson
Ja, das ist es, was ich anfangs dachte, aber ich brauche dies, um Code unabhängig zu sein. Das bedeutet, dass die Story vollständig aus einer externen Datei heraus bearbeitet werden kann. Also muss ich einen Weg finden, um das, was Sie gerade gesagt haben, zu verallgemeinern und so zu tun, dass ich nicht die Kontrolle über das Projekt verliere (es gibt einige Entscheidungen). Aktualisiert die Frage. Vielen Dank!
Valentin Radu
Genauer gesagt, ich kann if (isTree)eine isTreeglobale Variable nicht prüfen oder beibehalten, da die Story diese Wahlmöglichkeit haben kann oder nicht. Weißt Du, was ich meine? Es ist eher eine auserlesene Engine, die mehrere Geschichten abdeckt.
Valentin Radu
Auch dies hat ein anderes Problem, sagen wir, wenn der Benutzer sich entscheidet, einen von uns gesetzten Baum zu pflanzen isTree=true, tut er später noch etwas anderes, wie einen Schulkameraden zu bekämpfen, der im Gegenzug seinen Baum abhackt, während der Baum noch jung ist weil er seinen Arsch getreten hat. Jetzt haben wir 2 Variablen, die die Existenz des Baumes isTree==true' and didFightBrat == false` beeinflussen. Weißt Du, was ich meine? Und die Kette kann für immer weitergehen, die Existenz des Baumes kann durch eine unbekannte Anzahl von Faktoren beeinflusst werden. Weißt Du, was ich meine?
Valentin Radu
Speichern Sie diese Daten dann in einer Datei auf der Festplatte. Sie müssen zwei Unterroutinen erstellen, um die Informationen zu laden und zu speichern, und diese Routinen dann für jeden Teil des Codes nach Bedarf verwenden.
Randolf Richardson

Antworten:

18

Sie können die Warteschlange auch in einen gerichteten azyklischen Graphen (DAG) verallgemeinern. Sie können darüber auf Wikipedia lesen. Grundsätzlich kann jeder Knoten einen oder mehrere übergeordnete Knoten haben, von denen er "abhängt". Zyklen sind nicht zulässig, dh wenn A von B abhängt, kann B nicht von A abhängen (direkt oder über eine indirekte Kette anderer Knoten).

Jeder Knoten befindet sich in einem "aktiven" oder "inaktiven" Zustand und darf nur dann aktiv werden, wenn alle übergeordneten Knoten bereits aktiv sind. Die Struktur des Graphen (welche Knoten sind vorhanden und wie sind sie verbunden) ist Teil der Spieldaten, aber der Aktiv / Inaktiv-Status ist Teil der Sicherungsdaten des Spielers.

Auf diese Weise können Sie Dinge modellieren wie: Wenn Sie einen Baum pflanzen, markieren Sie eine Aufgabe "plantedTree" als aktiv; Dann, später im Spiel, nennt eine andere Aufgabe "treeGrown" sowohl "plantedTree" als auch einen anderen Knoten (Teil der Geschichte) als seine Eltern. Dann wird "treeGrown" nur dann aktiv, wenn der Spieler zu diesem Punkt in der Geschichte gelangt und auch "plantedTree" aktiv ist.

Sie können andere Funktionen einschließen, z. B. Knoten, die aktiviert werden, wenn einer ihrer Elternteile aktiviert wird, oder Knoten, die von einem Elternteil aktiviert und von einem anderen deaktiviert werden, usw. Es ist ein ziemlich allgemeiner Rahmen zum Erstellen von Geschichten mit mehreren, voneinander abhängigen Threads.

Nathan Reed
quelle
Eine sehr gute Antwort, danke. Es löst tatsächlich andere Probleme, die ich auch habe, wie das Speichern des Benutzerfortschritts. Das ist das, was ich benötige.
Valentin Radu
@ NathanReed Warum konnte das nicht zyklisch sein? Azyklisch zu sein ist normalerweise kein Merkmal, sondern ein Nebenprodukt des Graphendesigns. Ich würde es nicht mit dieser Absicht schaffen. Stellen Sie sich zum Beispiel vor, Sie möchten, dass Ihr Baum Jahreszeiten erkennt. Sie sind von Natur aus zyklisch, und Ihr Handlungsstrang kann je nach den verfügbaren Optionen während einer Saison identisch sein.
Es muss azyklisch sein, denn wenn es einen Zyklus gibt, geraten Sie in eine Endlosschleife, wenn Sie herausfinden möchten, ob ein Knoten im Zyklus aktiv sein kann, da Sie rekursiv alle seine Vorfahren überprüfen, einschließlich des Knotens selbst. Wenn Sie so etwas wie die Jahreszeiten modellieren wollten, würde ich das im Zusammenhang mit dieser Grafik nicht tun.
Nathan Reed
@ NathanReed Ah, sorry, ich habe den rekursiven Teil verpasst.
3

Nach meinem Verständnis ist das, was Sie wollen, nicht nur eine Entscheidungsmaschine, sondern auch eine Regelmaschine. Für jede Entscheidung führen Sie eine Untergruppe von Regeln aus, die durch diese Entscheidung definiert wurden. Die Ausführung dieser Regeln hängt häufig vom Status bestimmter Entitäten ab, z. B. Ihres Baumbeispiels.

Wenn Ihr Player eine Entscheidung trifft, suchen Sie nach dieser Entscheidung, führen Sie die Regeln aus und stellen Sie dann die nächsten verfügbaren Entscheidungen wie gewohnt bereit. Ihre Regeln sind jedoch dahingehend dynamisch, dass einige von ihnen nur basierend auf anderen Regeln ausgeführt werden, die bereits ausgeführt wurden.

Einige mehr auf Wikipedia .

Aus der Unterüberschrift " Wann werden Regel-Engines verwendet ?" (Schwerpunkt liegt bei mir):

  • Das Problem ist für herkömmlichen Code einfach zu komplex.
  • Das Problem mag nicht komplex sein, aber Sie können keine solide Art und Weise sehen, es aufzubauen.
  • Das Problem ist jenseits jeder offensichtlichen algorithmischen Lösung.
  • Es ist ein komplexes Problem zu lösen. Es gibt keine offensichtlichen herkömmlichen Lösungen oder das Problem ist nicht vollständig verstanden.
  • Die Logik ändert sich oft
  • Die Logik selbst mag einfach sein, aber die Regeln ändern sich ziemlich oft. In vielen Unternehmen sind Softwareversionen selten und Regeln können dazu beitragen, die erforderliche und erwartete "Flexibilität" auf einigermaßen sichere Weise bereitzustellen.
  • Domain-Experten und Business-Analysten stehen zur Verfügung, sind jedoch nicht technisch.
  • Domain-Experten verfügen häufig über umfassende Kenntnisse über Geschäftsregeln und -prozesse. Sie sind normalerweise nicht technisch, können aber sehr logisch sein. Mithilfe von Regeln können sie die Logik in eigenen Begriffen ausdrücken. Natürlich müssen sie immer noch kritisch denken und logisch denken können. Viele Menschen in nichttechnischen Positionen haben keine Ausbildung in formaler Logik, seien Sie also vorsichtig und arbeiten Sie mit ihnen. Durch die Kodifizierung von Geschäftskenntnissen in Regeln werden Sie häufig Lücken in der Art und Weise aufdecken, in der Geschäftsregeln und -prozesse derzeit verstanden werden.

Zu beachten ist, dass eine Regel-Engine gelegentlich am besten mit einer vereinfachten domänenspezifischen "Sprache" oder so ähnlich wie YAML implementiert wird. Ich würde XML nicht vorschlagen.


quelle
1

Sie müssen berücksichtigen, dass ein Ereignis nicht nur auf Benutzerentscheidungen beruht. Wie Sie bemerkt haben, muss ein Ereignis angehängt werden, wenn eine Reihe von Entscheidungssequenzen getroffen werden, und dann wird etwas anderes angehängt (wie zwei Tage danach).

Was Sie meiner Meinung nach brauchen, ist eine Möglichkeit, Ereignisse zu modellieren und auszulösen. Während der erste eher an Ihren speziellen Fall gebunden ist, kann der letztere durch eine hierarchische Zustandsmaschine (HSM) modelliert werden, die Ihre Ereignisse direkt oder indirekt auslöst.

Denken Sie daran, dass eine Zustandsmaschine unter dem Fluch der Dimensionalität leidet, der nur durch eine hierarchische Struktur gemildert wird. Bald werden Sie verstehen, dass Sie die komplexe Bedeutung des Status mithilfe eines HMS modellieren, aber auch eine Möglichkeit zur Abfrage bereitstellen müssen.

In diesem Szenario gibt es grundlegende Ereignisse (Benutzerentscheidungen, Uhrzeit, Wetteränderungen usw.), die sowohl vom HSM als auch von grundlegenden Ereignisrückrufen verarbeitet werden. Das HSM bietet ein Modell für das "Gedächtnis" und die Rückrufe bieten eine Möglichkeit, zu beschreiben, wie dieses Gedächtnis verwendet werden muss, um die Folgen einer Folge von Entscheidungen / externen Ereignissen zu berechnen.

Möglicherweise verwenden Sie auch ein Diktonar (oder eine andere Sammlungsstruktur) von HMS, eines für jeden "Aspekt" des zu berechnenden Status. Ein Beispiel kann die Verwendung eines HMS-Ereignisses und eines Ereignisses für die Entscheidungen sein, die Rückrufe treffen, um Ereignisse auszulösen.

Alle diese Infrastrukturen dienen dem Zweck, das Verhalten eines menschlichen Dungeon-Meisters nachzuahmen: Er zeichnet im Allgemeinen die aktuelle Situation (HMS ["extern"]) aufgrund von Spielerentscheidungen und Umgebungsbedingungen im Kopf auf. Wenn sich etwas anhängt, kann es Entscheidungen anhand seiner mentalen Aufzeichnung treffen und auch einen internen Strategiestatus (HSM ["intern"]) aufzeichnen, um zu vermeiden, dass es in ähnlicher Weise reagiert, wenn sich beispielsweise eine Situation ergibt.

FxIII
quelle