Choisissez votre propre aventure - pile de choix

8

Je suis en train de construire un jeu d'aventure à choisir. Maintenant, il est assez facile d'avoir un résultat pour chaque choix et de créer un flux linéaire, mais existe-t-il un bon algorithme pour que toutes les sélections précédentes affectent le résultat suivant? Je pourrais évidemment stocker chaque sélection précédente et avoir de grandes déclarations «IF» à décider, mais je me demandais s'il y avait une meilleure façon?

Une partie de moi se demande si chaque choix devrait avoir un «score», puis je l'utilise (peut-être avec un seuil) pour déterminer quelle devrait être la prochaine action et chaque action est ajoutée au score.

Je fais principalement cela dans swift / SpriteKit mais je pense que c'est plus sur le concept que sur le code à ce stade.

En réponse au commentaire de Josh ci-dessous:

Je suppose que je suis encore dans la phase conceptuelle pour le moment, mais chaque «page» serait soit un objet personnalisé soit un fichier json. Je pensais à votre réponse (maintenant supprimée) et peut-être avoir un peu chaque option ENUM. Ensuite, chaque page pourrait avoir un «score». Ensuite, en utilisant les options précédentes sélectionnées, déterminez quels bits sont définis et cela détermine quelle page. Je suppose que je me demandais simplement s'il existait une solution à ce problème avant de commencer à presque aider à décider comment je devrais mettre en forme 'l'histoire'.

Devinez approximativement le format:

  { "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 
  }

Merci

TommyBs
la source
Comment représentez-vous actuellement chaque "page" de votre aventure? S'agit-il uniquement de fonctions codées en dur dans Swift? Lisez-vous le texte / les images et les choix disponibles pour chaque page d'un fichier de données? Si oui, à quoi ressemble le fichier?
@JoshPetrie mis à jour avec plus d'informations
TommyBs
Le problème sous-jacent est qu'il n'existe tout simplement aucun moyen élégant de représenter une narration non linéaire avec un support linéaire comme le code source. La méthode idéale serait que l'OMI soit d'avoir un éditeur visuel de type UML où les récits sont représentés sous forme de boîtes et les flux narratifs possibles sous forme de flèches. Mais pour la plupart des petits projets, il serait probablement plus difficile d'implémenter un tel éditeur que de simplement écrire à la main un désordre de code de spaghetti plein de if', else', switch'et casede en espérant que vous aurez terminé avant de perdre votre raison.
Philipp
@Philipp Un diagramme UML n'est-il pas exactement ce qu'est un graphe d'objet? Vous pourriez probablement étudier les approches de sérialisation des graphes d'objets pour trouver de bons moyens de représenter un graphe d'objets de manière linéarisée.
uliwitness
@uliwitness Il existe différents types de diagrammes UML. Le plus proche d'une arborescence de dialogue est un diagramme d'activité . J'ai expérimenté différents outils pour générer du code à partir de diagrammes UML une fois et j'ai été assez déçu. Vous obtenez généralement du code assez désordonné qui n'est même pas encore fonctionnel et nécessite un remplissage manuel des méthodes de stub.
Philipp

Réponses:

12

Beaucoup de jeux d'aventure / RPG gèrent cela de deux manières (il y en a peut-être d'autres que je ne connais pas).

Utilisation de drapeaux

La première consiste à définir un indicateur si quelque chose s'est produit (généralement un masque de bits). C'est très bien si vous n'avez pas beaucoup de choses à suivre. Dans la salle / rencontre, il peut y avoir une vérification contre un drapeau qui modifie quelque chose. Dans votre exemple, vous pouvez ajouter une règle:

{"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
}

Où la 2e option n'apparaît que si flags & 64est définie. Vous pouvez également implémenter l' setflagoption si la scène apparaît ou si un choix particulier a été fait.

Utilisation d'articles

La deuxième option consiste à ajouter des objets à l'inventaire du joueur. Ce sont les "cet objet est nécessaire pour terminer une quête" que vous voyez souvent dans les jeux. Ceux-ci fonctionnent essentiellement comme des «drapeaux» portables. Cela peut être mis en œuvre de deux manières (ou une combinaison):

  • L'élément est le «drapeau»: faites vérifier la scène ou la boîte de dialogue si le joueur a un objet spécifique dans son inventaire. Cela ressemble beaucoup au mécanicien «vérifier un drapeau» tel que décrit ci-dessus. L'avantage est qu'il peut être beaucoup plus facile pour vous de concevoir des rencontres lorsque vous comparez des objets nommés familiers.

  • Les éléments ont des propriétés qui fonctionnent comme un indicateur. Par exemple, dans The Witcher 3, le joueur obtient un objet qui peut dissiper les murs illusoires. Cet élément lui-même pourrait être un «indicateur», mais il se pourrait également que l'objet ait une propriété can_dispel_illusions. L'avantage ici est que vous pouvez implémenter plusieurs objets pouvant être utilisés dans le même scénario. Ainsi, une scène / boîte de dialogue / porte pourrait vérifier si le joueur a «quelque chose» dans son inventaire qui a la propriété can_dispel_illusions.

Cela vous donne la possibilité de donner au joueur l'illusion de son choix; si le joueur n'a pas rencontré la sorcière dans la scène un, manquant ainsi la `` baguette de dissipation '', le joueur pourrait obtenir un `` anneau de dissipation '' plus tard de la part d'un marchand ombragé, empêchant un état du jeu impossible à gagner.

Si vous ne prévoyez pas de donner au joueur un "vrai" inventaire, les objets de quête pourraient aller dans une liste cachée au joueur.

exemple:

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

et:

{"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
la source
2

Une solution que j'ai vue qui développe votre approche consiste à avoir différents attributs avec des scores associés. Certains choix entraînent la modification d'un ou plusieurs de ces scores. Les scores peuvent à leur tour modifier les choix disponibles pour le joueur.

Par exemple, au début de l'histoire, il peut y avoir des rencontres de combat en option. Si le joueur s'engage dans un combat, l'attribut de bravoure augmenterait, tandis que fuir le ferait diminuer. Plus tard, une branche d'histoire particulière pourrait être disponible uniquement si le score de bravoure était supérieur ou inférieur à un seuil donné. Pour ajouter plus de profondeur, certaines décisions devraient affecter plus d'un score. Par exemple, cueillir des poches pourrait augmenter un score de furtivité et diminuer un score d'honnêteté.

Généralement, j'ai vu cette approche utilisée dans la fiction interactive de type simulation. Vous pouvez entendre Dan Fabulich de Choice Of Games discuter de cette solution dans cet épisode de la table ronde sur la conception de jeux.

Les avantages de cette approche sont:

  • chaque décision n'a pas besoin de fournir une fin unique, ce qui réduit le nombre total de fins nécessaires
  • il peut y avoir plus d'une façon d'atteindre une fin donnée, permettant une plus grande variété de styles de jeu gratifiants

Certains inconvénients sont:

  • si les décisions reposent sur des attributs uniques, elles peuvent être superficielles et formulées
  • à l'inverse, si les décisions sont trop complexes, équilibrer le jeu / l'histoire devient plus difficile
Pikalek
la source
1

C'est le gros problème des jeux basés sur l'histoire: l'explosion combinatoire. En tant que tel, si vous regardez par exemple les jeux Bioware ou Telltale, vous constaterez que l'approche la plus courante semble toujours être d'essayer de restreindre l'histoire à être plus linéaire et de limiter les conséquences des actions à leurs chapitres.

L'approche que Bioware semble utiliser divise chaque histoire en fils ou sous-arcs séparés. Les arcs sont à peu près indépendants les uns des autres, mais se produisent simultanément et peuvent tous contribuer à la fin. De cette façon, vous n'avez pas à modéliser chaque combinaison d'arcs, vous alternez simplement les chapitres entre les arcs, et les conséquences sont limitées au sous-arc particulier que vous traitez en ce moment, ou à la façon de terminer un arc. (ou comment mettre fin à l'arc d'un personnage. Si vous n'avez plus besoin de ce PNJ, vous avez souvent le choix de les tuer, de les arrêter ou de les libérer, par exemple, en vous donnant le choix, mais en limitant les conséquences au reste de l'histoire)

La fin de l'histoire entière n'a alors besoin que de savoir comment chaque arc s'est terminé et de lier l'ensemble du récit en un petit arc soigné.

Comment modéliseriez-vous cela dans un programme?

Cela pousse simplement le problème d'un niveau (car chaque sous-arc doit suivre les différences comme le ferait une histoire simple), mais en gros, vous auriez un tableau de drapeaux (par exemple, un champ de bits ou une liste d'éléments avec des drapeaux représentant le capacité à effectuer certains résultats) pour chaque sous-arc.

De plus, lorsque vous dites votre fin, vous adoptez généralement la même approche d'alternance lorsque vous informez le joueur des conséquences: le résultat de chaque sous-arc obtient son propre paragraphe / nœud de conversation, simplifiant considérablement vos conditions.

uliwitness
la source
0

Cela peut prendre un peu de temps, mais le développement de votre propre arborescence (comme une arborescence de comportement ou une arborescence de dialogue, mais pour les pages) peut être bénéfique. Et vous pourriez en utiliser un comme modèle. Quelque chose comme ça:

Comment fonctionnent les arborescences de dialogue?

Cela vous permettrait de l'adapter à vos besoins spécifiques, mais aussi de laisser le code gérer la plupart du travail.

Jesse Williams
la source
0

Et si vous utilisiez une approche de type moteur de règles? Lorsqu'un joueur interagit avec un PNJ, le jeu exécutait un moteur de règles dépouillé qui commencerait avec des drapeaux qui avaient été créés par des choix / comportements passés et le vérifierait par rapport à un ensemble de règles définies par vous à l'avance. Quelque chose comme Drools est probablement trop gros et ambitieux, sans parler de lenteur, mais un moteur de règles à portée limitée pourrait théoriquement vous donner de meilleures performances et beaucoup de flexibilité.

JBiggs
la source