Elige tu propia aventura: la pila de opciones

8

Actualmente estoy construyendo un juego de elegir tu propia aventura. Ahora es bastante fácil tener un resultado para cada elección y crear un flujo lineal, pero ¿existe un buen algoritmo para que todas las selecciones anteriores afecten al siguiente resultado? Obviamente, podría almacenar cada selección anterior y tener grandes declaraciones 'IF' para decidir, pero me preguntaba si había una mejor manera.

Parte de mí se pregunta si cada opción debería tener un 'puntaje' y luego lo uso (tal vez con un umbral) para determinar cuál debería ser la siguiente acción y cada acción se agrega al puntaje.

Principalmente estoy haciendo esto en swift / SpriteKit, pero creo que se trata más del concepto que del código en este momento.

En respuesta al comentario de Josh a continuación:

Supongo que todavía estoy en la fase conceptual en este momento, pero cada 'página' sería un objeto personalizado o un archivo json. Estaba pensando en su respuesta (ahora eliminada) y tal vez tener cada opción ENUM como un poco. Entonces cada página podría tener un 'puntaje'. Luego, utilizando las opciones anteriores seleccionadas, determine qué bits se configuran y eso determina qué página. Supongo que me preguntaba si había una solución existente para este problema antes de comenzar a ayudar a decidir cómo debería formatear la 'historia'

Aproximación aproximada al formato:

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

Gracias

TommyBs
fuente
¿Cómo representa actualmente cada "página" de su aventura? ¿Son solo funciones codificadas en Swift? ¿Está leyendo el texto / imágenes y las opciones disponibles para cada página de un archivo de datos? Si es así, ¿cómo se ve el archivo?
@JoshPetrie actualizado con más información
TommyBs
El problema subyacente es que simplemente no hay una forma elegante de representar una narración no lineal con un medio lineal como el código fuente. El método ideal sería en mi opinión tener un editor visual similar a UML donde los puntos de la historia se representan como cuadros y los posibles flujos narrativos como flechas. Pero para la mayoría de los proyectos más pequeños, probablemente sería más trabajo implementar un editor de este tipo que simplemente escribir a mano un lío de código de espagueti lleno de if's else', switch's case' y 'con la esperanza de que termines antes de perder la cordura.
Philipp
@Philipp ¿No es un diagrama UML exactamente lo que es un gráfico de objeto? Probablemente podría buscar en los enfoques de serialización de gráficos de objetos para encontrar buenas maneras de representar un gráfico de objetos de forma linealizada.
uliwitness
@uliwitness Hay diferentes tipos de diagramas UML. Lo más cercano a un árbol de diálogo es un diagrama de actividad . Experimenté con varias herramientas para generar código a partir de diagramas UML una vez y me decepcionó bastante. Por lo general, obtienes un código bastante desordenado que ni siquiera es funcional todavía y necesita un poco de llenado manual de los métodos de código auxiliar.
Philipp

Respuestas:

12

Muchos juegos de Aventura / RPG manejan esto de dos maneras (puede haber más de los que no estoy al tanto).

Uso de banderas

El primero es establecer una bandera si algo sucedió (generalmente alguna máscara de bits). Esto está bien si no tienes muchas cosas que rastrear. En la sala / encuentro puede haber una verificación contra una bandera que altera algo. En su ejemplo, podría agregar una regla:

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

Donde la segunda opción solo aparece si flags & 64está configurada. También podría implementar la setflagopción si aparece la escena, o si se hizo una elección particular.

Uso de artículos

La segunda opción es agregar elementos al inventario del jugador. Estos son "este elemento es necesario para completar una misión" que ves a menudo en los juegos. Básicamente funcionan como 'banderas' portátiles. Esto se puede implementar de dos maneras (o una combinación):

  • El elemento es la 'bandera': haga que la escena o el diálogo comprueben si el jugador tiene un objeto específico en su inventario. Esto es muy parecido a la mecánica de 'comprobar una bandera' como se describió anteriormente. Lo bueno es que puede ser mucho más fácil para ti diseñar encuentros a medida que verificas contra objetos conocidos con nombre.

  • Los elementos tienen propiedades que funcionan como una bandera. Por ejemplo, en The Witcher 3, el jugador obtiene un objeto que puede disipar paredes ilusorias. Ese elemento en sí podría ser una 'bandera' pero también podría ser que el objeto tiene una propiedad can_dispel_illusions. La ventaja aquí es que podría implementar varios objetos que se pueden usar en el mismo escenario. Por lo tanto, una escena / diálogo / puerta podría verificar si el jugador tiene 'algo' en su inventario que tiene la propiedad can_dispel_illusions.

Esto te da la posibilidad de darle al jugador la ilusión de elegir; Si el jugador no se encontró con la bruja en la escena uno, por lo tanto, al perder la 'varita de disipación', el jugador podría obtener un 'anillo de disipación' más tarde de algún comerciante sombrío, evitando un estado del juego imposible de ganar.

Si no planeas darle al jugador un inventario "real", los artículos de la misión podrían ir a una lista oculta del jugador.

ejemplo:

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

y:

{"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
fuente
2

Una solución que he visto que detalla su enfoque es tener varios atributos con puntajes asociados. Algunas opciones dan como resultado la modificación de uno o más de estos puntajes. Los puntajes a su vez pueden modificar las opciones disponibles para el jugador.

Por ejemplo, al principio de la historia, puede haber algunas opciones de encuentros de combate. Si el jugador entra en combate, el atributo de valentía aumentaría, mientras que huir haría que disminuyera. Más adelante, una rama de la historia en particular solo podría estar disponible si el puntaje de valentía estaba por encima o por debajo de un umbral determinado. Para agregar más profundidad, algunas decisiones deberían afectar a más de un puntaje. Por ejemplo, recoger bolsillos podría aumentar un puntaje de sigilo y disminuir un puntaje de honestidad.

En general, he visto este enfoque utilizado en la ficción interactiva del tipo de simulación. Puedes escuchar a Dan Fabulich de Choice Of Games discutir esta solución en este episodio de la Mesa Redonda de Diseño de Juegos.

Los beneficios de este enfoque son:

  • cada decisión no necesita proporcionar un final único, reduciendo el número total de finales necesarios
  • puede haber más de una forma de llegar a un final determinado, lo que permite una mayor variedad de estilos de juego gratificantes

Algunos inconvenientes son:

  • Si las decisiones dependen de atributos únicos, puede ser superficial y formulado
  • por el contrario, si las decisiones son demasiado complejas, equilibrar el juego / historia se vuelve más difícil
Pikalek
fuente
1

Este es el gran problema que enfrentan los juegos basados ​​en la historia: explosión combinatoria. Como tal, si observa, por ejemplo, los juegos Bioware o Telltale, encontrará que el enfoque más común parece ser tratar de restringir la historia para que sea más lineal y mantener las consecuencias de las acciones limitadas a sus capítulos.

El enfoque que Bioware parece estar usando divide cada historia en subprocesos o subarcos separados. Los arcos son bastante independientes entre sí, pero suceden simultáneamente y pueden contribuir al final. De esa manera, no tiene que modelar cada combinación de arcos, solo alterna capítulos entre arcos, y las consecuencias se limitan al subarco particular con el que está lidiando en este momento, o cómo terminar un arco. (o cómo terminar el arco de un personaje. Si ya no necesitas ese NPC, a menudo tienes la opción de matarlos, arrestarlos o liberarlos, por ejemplo, dándote elección, pero limitando las consecuencias al resto de la historia)

El final de toda la historia solo necesita saber cómo terminó cada arco y vincular toda la narración en una pequeña reverencia ordenada.

¿Cómo modelarías eso en un programa?

Esto simplemente empuja el problema hacia abajo un nivel (porque cada subarco necesita rastrear las diferencias como lo haría una historia simple), pero básicamente tendría una serie de banderas (por ejemplo, un campo de bits o una lista de elementos con banderas que representan capacidad de efectuar ciertos resultados) para cada subarco.

Además, cuando está contando su final, generalmente toma el mismo enfoque de alternar cuando le cuenta al jugador las consecuencias: el resultado de cada subarco obtiene su propio nodo de párrafo / conversación, lo que simplifica enormemente sus condicionales.

uli testigo
fuente
0

Puede tomar un poco de tiempo, pero desarrollar su propio árbol (como un árbol de comportamiento o árbol de diálogo, pero para páginas) puede ser beneficioso. Y podrías usar uno de esos como modelo. Algo como esto:

¿Cómo funcionan los árboles de diálogo?

Esto le permitiría adaptarlo a sus necesidades específicas, pero también permitiría que el código maneje la mayor parte del trabajo.

Jesse Williams
fuente
0

¿Qué sucede si utiliza un enfoque de tipo motor de reglas? Cuando un jugador interactúa con un NPC, el juego ejecutaría un motor de reglas simplificado que comenzaría con banderas que habían sido creadas por elecciones / comportamientos pasados ​​y lo compararía con un conjunto de reglas definidas por usted de antemano. Algo así como Drools es probablemente demasiado grande y ambicioso, por no mencionar lento, pero un motor de reglas de alcance limitado teóricamente podría brindarte un mejor rendimiento y mucha flexibilidad.

JBiggs
fuente