Wählen Sie Ihr eigenes Abenteuer - Auswahlstapel

8

Ich baue gerade ein eigenes Abenteuerspiel. Jetzt ist es einfach genug, für jede Auswahl ein Ergebnis zu haben und einen linearen Fluss zu erstellen. Gibt es jedoch einen guten Algorithmus, mit dem alle vorherigen Auswahlen das nächste Ergebnis beeinflussen? Ich könnte natürlich jede vorherige Auswahl speichern und große IF-Anweisungen zur Entscheidung haben, aber ich habe mich gefragt, ob es einen besseren Weg gibt.

Ein Teil von mir fragt sich, ob jede Auswahl eine "Punktzahl" haben sollte, und dann benutze ich diese (möglicherweise mit einem Schwellenwert), um zu bestimmen, wie die nächste Aktion aussehen soll, und jede Aktion wird zur Punktzahl hinzugefügt.

Ich mache das hauptsächlich in Swift / SpriteKit, aber ich denke, es geht an dieser Stelle mehr um das Konzept als um den Code.

Als Antwort auf Joshs Kommentar unten:

Ich nehme an, ich bin im Moment noch in der Konzeptionsphase, aber jede 'Seite' wäre entweder ein benutzerdefiniertes Objekt oder eine JSON-Datei. Ich habe über Ihre Antwort nachgedacht (jetzt entfernt) und vielleicht jede ENUM-Option ein bisschen. Dann könnte jede Seite eine "Punktzahl" haben. Verwenden Sie dann die zuvor ausgewählten Optionen, um herauszufinden, welche Bits gesetzt sind und welche Seite bestimmt wird. Ich habe mich wohl nur gefragt, ob es eine Lösung für dieses Problem gibt, bevor ich fast bei der Entscheidung half, wie ich die "Geschichte" formatieren soll.

Grobe Vermutung des Formats:

  { "text":"You arrive in the dungeon and there are 2 doors",
   "options":[
    1: "Go left",
    2: "Go Right"
    ],
   "score" : 0 // first page
  }
  {"text" "You went left and meet a dragon",
  "options":[
    0: "Game over, you were eaten" // something to handle game over
    ],
   "score" : 1 
  }
  {"text" "You meet a mushroom who tells you the princess is in another castle",
  "options":[
    4: "Give up, game over", // something to handle game over
    8: "Jump down the pipe"
    ],
   "score" : 2 
  }

Vielen Dank

TommyBs
quelle
Wie repräsentieren Sie derzeit jede "Seite" Ihres Abenteuers? Sind sie alle nur fest codierte Funktionen in Swift? Lesen Sie die für jede Seite verfügbaren Texte / Bilder und Auswahlmöglichkeiten aus einer Datendatei? Wenn ja, wie sieht die Datei aus?
@ JoshPetrie aktualisiert mit einigen weiteren Informationen
TommyBs
Das zugrunde liegende Problem ist, dass es einfach keine elegante Möglichkeit gibt, nichtlineare Erzählungen mit einem linearen Medium wie dem Quellcode darzustellen. Die ideale Methode wäre IMO, einen UML-ähnlichen visuellen Editor zu haben, in dem Story-Points als Kästchen dargestellt werden und die möglichen Erzählströme als Pfeile. Aber für die meisten kleineren Projekte wäre es wahrscheinlich mehr Arbeit, einen solchen Editor zu implementieren, als nur ein Durcheinander von Spaghetti-Code von if's, else' s, switch's und case' s von Hand zu schreiben, in der Hoffnung, dass Sie fertig sind, bevor Sie Ihren Verstand verlieren.
Philipp
@Philipp Ist ein UML-Diagramm nicht genau das, was ein Objektdiagramm ist? Sie könnten sich wahrscheinlich mit Ansätzen zur Serialisierung von Objektgraphen befassen, um gute Möglichkeiten zu finden, einen Graphen von Objekten linear darzustellen.
uliwitness
@uliwitness Es gibt verschiedene Arten von UML-Diagrammen. Am nächsten an einem Dialogbaum befindet sich ein Aktivitätsdiagramm . Ich habe einmal mit verschiedenen Tools experimentiert, um Code aus UML-Diagrammen zu generieren, und war ziemlich enttäuscht. Normalerweise erhalten Sie einen ziemlich unordentlichen Code, der noch nicht einmal funktionsfähig ist und das manuelle Ausfüllen von Stub-Methoden erfordert.
Philipp

Antworten:

12

Viele Adventure / RPG-Spiele behandeln dies auf zwei Arten (es gibt möglicherweise mehr, die mir nicht bekannt sind).

Verwendung von Flaggen

Die erste besteht darin, ein Flag zu setzen, wenn etwas passiert ist (normalerweise eine Bitmaske). Dies ist in Ordnung, wenn Sie nicht viele Dinge zu verfolgen haben. Im Raum / in der Begegnung kann es eine Überprüfung gegen eine Flagge geben, die etwas verändert. In Ihrem Beispiel könnte eine Regel hinzugefügt werden:

{"text" "You meet a mushroom who tells you the princess is in another castle",
"options":[
  4: "Give up, game over", // something to handle game over
  8: [64:"Jump down the pipe", "Exit stage left"]
  ],
 "score" : 2
 "setflag" : 32
}

Wobei die 2. Option nur angezeigt wird, wenn flags & 64eingestellt ist. Sie können die setflagOption auch implementieren, wenn die Szene angezeigt wird oder eine bestimmte Auswahl getroffen wurde.

Verwendung von Gegenständen

Die zweite Möglichkeit besteht darin, Gegenstände zum Inventar des Spielers hinzuzufügen. Dies sind die "Dieser Gegenstand wird benötigt, um eine Quest abzuschließen", die Sie häufig in Spielen sehen. Diese fungieren grundsätzlich als tragbare "Flags". Dies kann auf zwei Arten (oder in einer Kombination) implementiert werden:

  • Der Gegenstand ist die 'Flagge': Lassen Sie die Szene oder den Dialog prüfen, ob der Spieler ein bestimmtes Objekt in seinem Inventar hat. Dies ähnelt der oben beschriebenen Mechanik "Auf Flagge prüfen". Der Vorteil ist, dass es für Sie möglicherweise viel einfacher ist, Begegnungen zu entwerfen, wenn Sie mit bekannten benannten Objekten vergleichen.

  • Elemente haben Eigenschaften, die als Flag fungieren. Zum Beispiel erhält der Spieler in The Witcher 3 ein Objekt, das illusionäre Wände zerstreuen kann. Dieses Element selbst könnte eine 'Flagge' sein, aber es könnte auch sein, dass das Objekt eine Eigenschaft hat can_dispel_illusions. Der Vorteil hierbei ist, dass Sie mehrere Objekte implementieren können, die im selben Szenario verwendet werden können. Somit könnte eine Szene / ein Dialog / eine Tür prüfen, ob der Spieler "etwas" in seinem Inventar hat, das die Eigenschaft besitzt can_dispel_illusions.

Dies gibt Ihnen die Möglichkeit, dem Spieler die Illusion der Wahl zu geben; Wenn der Spieler der Hexe in Szene 1 nicht begegnet ist und somit den Zauberstab der Zerstreuung fehlt, kann er später von einem zwielichtigen Händler einen Ring der Zerstreuung erhalten, wodurch ein nicht gewinnbarer Zustand des Spiels verhindert wird.

Wenn Sie nicht vorhaben, dem Spieler ein "echtes" Inventar zu geben, können die Questgegenstände in eine Liste verschoben werden, die vor dem Spieler verborgen ist.

Beispiel:

{"items":[
  "Wand of Dispel": { "properties": ["can_dispel_illusions","illumination"]}
]}

und:

{"text" "The corridor ends in a dead end. The wall feels cold when you touch it.",
"options":[
  4: "Turn back", 
  8: {"can_dispel_illusions": "Check if the wall is real."} 
  ],
 "score" : 2 
}

{"text" "The witch hands you an object. She observes what you're going to do next.",
"options":[
  14: "Leave the witch's house", 
  22: "Look at the object."} 
  ],
 "giveitem" : "Wand of Dispel" 
}
Felsir
quelle
2

Eine Lösung, die ich gesehen habe und die Ihren Ansatz näher erläutert, besteht darin, verschiedene Attribute mit zugehörigen Bewertungen zu haben. Einige Auswahlmöglichkeiten führen dazu, dass eine oder mehrere dieser Bewertungen geändert werden. Die Punktzahlen können wiederum die Auswahlmöglichkeiten ändern, die dem Spieler zur Verfügung stehen.

Zum Beispiel kann es zu Beginn der Geschichte einige optionale Kampfbegegnungen geben. Wenn der Spieler in einen Kampf verwickelt ist, würde sich das Tapferkeitsattribut erhöhen, während das Fliehen dazu führen würde, dass es abnimmt. Später ist ein bestimmter Story-Zweig möglicherweise nur verfügbar, wenn die Tapferkeitsbewertung über oder unter einem bestimmten Schwellenwert liegt. Um mehr Tiefe zu erreichen, sollten einige Entscheidungen mehr als eine Punktzahl betreffen. Zum Beispiel kann das Pflücken von Taschen einen Stealth-Score erhöhen und einen Ehrlichkeits-Score verringern.

Im Allgemeinen habe ich diesen Ansatz in interaktiven Fiktionen vom Simulationstyp gesehen. Sie können hören, wie Dan Fabulich von Choice Of Games diese Lösung in dieser Episode des Game Design Round Table bespricht .

Die Vorteile dieses Ansatzes sind:

  • Jede Entscheidung muss kein eindeutiges Ende enthalten, wodurch sich die Gesamtzahl der erforderlichen Endungen verringert
  • Es kann mehr als einen Weg geben, um ein bestimmtes Ende zu erreichen, was mehr Abwechslung bei der Belohnung von Spielstilen ermöglicht

Einige Nachteile sind:

  • Wenn Entscheidungen von einzelnen Attributen abhängen, können sie flach und formelhaft sein
  • Umgekehrt wird es schwieriger, das Spiel / die Geschichte in Einklang zu bringen, wenn Entscheidungen zu komplex sind
Pikalek
quelle
1

Dies ist das große Problem, mit dem geschichtengetriebene Spiele konfrontiert sind: die kombinatorische Explosion. Wenn Sie sich beispielsweise Bioware- oder Telltale-Spiele ansehen, werden Sie feststellen, dass der häufigste Ansatz immer noch darin zu bestehen scheint, die Geschichte auf eine linearere Darstellung zu beschränken und die Konsequenzen von Aktionen auf ihre Kapitel zu beschränken.

Der Ansatz von Bioware scheint darin zu bestehen, jede Geschichte in separate Threads oder Teilbögen aufzuteilen. Die Bögen sind ziemlich unabhängig voneinander, treten jedoch gleichzeitig auf und können alle zum Ende beitragen. Auf diese Weise müssen Sie nicht jede Kombination von Bögen modellieren, sondern nur Kapitel zwischen Bögen wechseln, und die Konsequenzen sind auf den bestimmten Teilbogen beschränkt, mit dem Sie sich gerade befassen, oder wie Sie einen Bogen beenden. (oder wie man den Bogen eines Charakters beendet. Wenn du diesen NPC nicht mehr brauchst, hast du oft die Wahl, sie zu töten, zu verhaften oder freizulassen, um dir beispielsweise die Wahl zu geben, aber die Konsequenzen auf den Rest zu beschränken von der Geschichte)

Das Ende der gesamten Geschichte muss dann nur noch wissen, wie jeder Bogen endete, und die gesamte Erzählung in einem ordentlichen kleinen Bogen zusammenbinden.

Wie würden Sie das in einem Programm modellieren?

Dies drückt das Problem einfach um eine Ebene nach unten (da jeder Teilbogen Unterschiede verfolgen muss, wie es eine einfache Geschichte tun würde), aber im Grunde hätten Sie eine Reihe von Flags (z. B. ein Bitfeld oder eine Liste von Elementen mit Flags, die das darstellen Fähigkeit, bestimmte Ergebnisse zu erzielen) für jeden Teilbogen.

Wenn Sie Ihr Ende mitteilen, gehen Sie normalerweise genauso vor, wenn Sie dem Spieler die Konsequenzen mitteilen: Das Ergebnis jedes Teilbogens erhält einen eigenen Absatz- / Konversationsknoten, wodurch Ihre Bedingungen erheblich vereinfacht werden.

uliwitness
quelle
0

Es kann einige Zeit dauern, aber die Entwicklung eines eigenen Baums (wie eines Verhaltensbaums oder eines Dialogbaums, jedoch für Seiten) kann von Vorteil sein. Und Sie könnten eines davon als Modell verwenden. Etwas wie das:

Wie funktionieren Dialogbäume?

Auf diese Weise können Sie es an Ihre spezifischen Anforderungen anpassen, aber auch den Code den größten Teil der Arbeit erledigen lassen.

Jesse Williams
quelle
0

Was ist, wenn Sie einen Regelengine-Ansatz verwendet haben? Wenn ein Spieler mit einem NPC interagiert, führt das Spiel eine abgespeckte Regel-Engine aus, die mit Flags beginnt, die durch frühere Entscheidungen / Verhaltensweisen erstellt wurden, und diese anhand einer Reihe von Regeln überprüft, die Sie im Voraus definiert haben. So etwas wie Drools ist wahrscheinlich zu groß und ehrgeizig, ganz zu schweigen von langsam, aber eine Regelengine mit begrenztem Umfang könnte Ihnen theoretisch eine bessere Leistung und viel Flexibilität bieten.

JBiggs
quelle