Escolha sua própria aventura - pilha de escolhas

8

Atualmente, estou construindo um jogo de aventura para você escolher. Agora é fácil o suficiente ter um resultado para cada escolha e criar um fluxo linear, mas existe um bom algoritmo para que todas as seleções anteriores afetem o próximo resultado? Obviamente, eu poderia armazenar todas as seleções anteriores e ter grandes declarações 'SE' para decidir, mas me perguntei se havia uma maneira melhor.

Parte de mim se pergunta se cada opção deve ter uma 'pontuação' e então eu a uso (talvez com um limite) para determinar qual deve ser a próxima ação e cada ação será adicionada à pontuação.

Primeiramente, estou fazendo isso no swift / SpriteKit, mas acho que é mais sobre o conceito do que o código neste momento.

Em resposta ao comentário de Josh abaixo:

Suponho que ainda estou na fase conceitual no momento, mas cada 'página' seria um objeto personalizado ou um arquivo json. Eu estava pensando em sua resposta (agora removida) e talvez tendo cada opção ENUM um pouco. Então cada página pode ter uma 'pontuação'. Em seguida, usando as opções anteriores selecionadas, determine quais bits estão definidos e que determina qual página. Acho que me perguntei se havia uma solução existente para esse problema antes de começar a quase ajudar a decidir como eu deveria formatar a 'história'.

Palpite aproximado no 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 
  }

obrigado

TommyBs
fonte
Como você representa atualmente cada "página" da sua aventura? Todas elas são apenas funções codificadas no Swift? Você está lendo o texto / imagens e opções disponíveis para cada página de um arquivo de dados? Se sim, como é o arquivo?
@JoshPetrie atualizado com mais informações #
TommyBs
O problema subjacente é que simplesmente não há uma maneira elegante de representar uma narrativa não linear com um meio linear como código fonte. O método ideal seria ter um editor visual semelhante a UML, onde os pontos da história são representados como caixas e a narrativa possível flui como setas. Mas para a maioria dos projetos menores, provavelmente seria mais trabalhoso implementar um editor desse tipo do que escrever à mão uma bagunça de código espaguete, cheia de if's else', switch's case' e 's, esperando que você termine antes de perder a sanidade.
Philipp
@ Philipp Não é um diagrama UML exatamente o que é um gráfico de objetos? Você provavelmente poderia examinar as abordagens de serialização de gráfico de objetos para encontrar boas maneiras de representar um gráfico de objetos de maneira linearizada.
211116 uliwitness
@uliwitness Existem diferentes tipos de diagramas UML. O mais próximo de uma árvore de diálogo é um diagrama de atividades . Eu experimentei várias ferramentas para gerar código a partir de diagramas UML uma vez e fiquei bastante decepcionado. Você geralmente obtém um código bastante confuso, que ainda nem é funcional e precisa de algum preenchimento manual dos métodos de stub.
Philipp

Respostas:

12

Muitos jogos de aventura / RPG lidam com isso de duas maneiras (pode haver mais que eu não esteja ciente).

Uso de bandeiras

O primeiro é definir um sinalizador se algo acontecer (geralmente alguma máscara de bit). Isso é bom se você não tem muitas coisas para rastrear. Na sala / encontro, pode haver um cheque contra uma bandeira que altera alguma coisa. No seu exemplo, você pode adicionar uma regra:

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

Onde a 2ª opção aparece apenas se flags & 64estiver definida. Você também pode implementar a setflagopção se a cena aparecer, ou uma escolha específica foi feita.

Uso de itens

A segunda opção é adicionar itens ao inventário do jogador. Estes são os "itens necessários para completar uma missão" que você vê frequentemente nos jogos. Estes funcionam basicamente como 'sinalizadores' portáteis. Isso pode ser implementado de duas maneiras (ou uma combinação):

  • O item é a 'bandeira': Faça com que a cena ou a caixa de diálogo verifique se o jogador tem um objeto específico em seu inventário. Isso é muito parecido com o mecânico 'check for a flag', como descrito acima. A vantagem é que pode ser muito mais fácil projetar encontros enquanto você checa contra objetos nomeados familiares.

  • Os itens têm propriedades que funcionam como um sinalizador. Por exemplo, em The Witcher 3, o jogador obtém um objeto que pode dissipar paredes ilusórias. Esse item em si pode ser um 'sinalizador', mas também pode ser que o objeto tenha uma propriedade can_dispel_illusions. A vantagem aqui é que você pode implementar vários objetos que podem ser usados ​​no mesmo cenário. Assim, uma cena / caixa de diálogo / porta pode verificar se o jogador tem 'algo' em seu inventário que possui a propriedade can_dispel_illusions.

Isso lhe dá a possibilidade de dar ao jogador a ilusão de escolha; se o jogador não encontrar a bruxa na cena um, perdendo a 'varinha de dissipar', o jogador poderá obter um 'anel de dissipação' mais tarde de algum comerciante obscuro - evitando um estado invencível do jogo.

Se você não planeja fornecer ao jogador um inventário "real", os itens da missão podem ir para uma lista - escondida do jogador.

exemplo:

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

e:

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

Uma solução que eu vi que elabora sua abordagem é ter vários atributos com pontuações associadas. Algumas opções resultam na modificação de uma ou mais dessas pontuações. As pontuações, por sua vez, podem modificar as opções disponíveis para o jogador.

Por exemplo, no início da história, pode haver alguns encontros de combate opcionais. Se o jogador se envolver em combate, o atributo de bravura aumentaria, enquanto fugir faria com que diminuísse. Posteriormente, um ramo específico da história poderá estar disponível apenas se a pontuação de bravura estiver acima ou abaixo de um determinado limite. Para adicionar mais profundidade, algumas decisões devem afetar mais de uma pontuação. Por exemplo, escolher bolsos pode aumentar a pontuação furtiva e diminuir a pontuação da honestidade.

Geralmente, eu vi essa abordagem usada na ficção interativa do tipo simulação. Você pode ouvir Dan Fabulich, da Choice Of Games, discutir esta solução neste episódio da Mesa Redonda de Design de Jogos.

Os benefícios dessa abordagem são:

  • cada decisão não precisa fornecer um final único, reduzindo o número total de finais necessários
  • pode haver mais de uma maneira de chegar a um determinado final, permitindo mais variedade de estilos de jogo recompensadores

Algumas desvantagens são:

  • se as decisões dependem de atributos únicos, pode ser superficial e formulado
  • por outro lado, se as decisões são muito complexas, equilibrar o jogo / história se torna mais difícil
Pikalek
fonte
1

Este é o grande problema enfrentado pelos jogos baseados em histórias: explosão combinatória. Assim, se você observar, por exemplo, os jogos da Bioware ou da Telltale, descobrirá que a abordagem mais comum parece ainda tentar restringir a história a ser mais linear e manter as conseqüências de ações limitadas aos seus capítulos.

A abordagem que a Bioware parece estar usando divide cada história em segmentos ou sub-arcos separados. Os arcos são praticamente independentes um do outro, mas acontecem simultaneamente e podem contribuir para o final. Dessa forma, você não precisa modelar cada combinação de arcos, apenas alterna capítulos entre arcos, e as consequências são limitadas ao sub-arco específico com o qual você está lidando agora ou como encerrar um arco. (ou como terminar o arco de um personagem. Se você não precisar mais desse NPC, muitas vezes terá a opção de matá-lo, prendê-lo ou libertá-lo, por exemplo, dando-lhe uma escolha, mas limitando as consequências para o resto da história)

O final de toda a história precisa apenas saber como cada arco terminou e amarrar toda a narrativa em um pequeno arco.

Como você modelaria isso em um programa?

Isso simplesmente empurra o problema para um nível abaixo (porque cada sub-arco precisa rastrear diferenças como faria uma história simples), mas basicamente você teria uma matriz de sinalizadores (por exemplo, um campo de bits ou uma lista de itens com sinalizadores que representam o capacidade de efetuar determinados resultados) para cada sub-arco.

Além disso, quando você está dizendo o seu final, geralmente usa a mesma abordagem de alternar quando conta ao jogador sobre as conseqüências: O resultado de cada sub-arco obtém seu próprio nó de parágrafo / conversa, simplificando muito suas condicionais.

uliwitness
fonte
0

Pode demorar um pouco, mas desenvolver sua própria árvore (como uma árvore de comportamento ou de diálogo, mas para páginas) pode ser benéfico. E você pode usar um desses como modelo. Algo assim:

Como as árvores de diálogo funcionam?

Isso permitiria adaptá-lo às suas necessidades específicas, mas também deixaria o código lidar com a maior parte do trabalho.

Jesse Williams
fonte
0

E se você usasse uma abordagem do tipo mecanismo de regras? Quando um jogador interage com um NPC, o jogo executa um mecanismo de regras despojado, que começa com bandeiras criadas por escolhas / comportamentos passados ​​e o compara com um conjunto de regras definidas por você com antecedência. Algo como o Drools provavelmente é muito grande e ambicioso, para não mencionar lento, mas um mecanismo de regras de escopo limitado poderia teoricamente oferecer a você um melhor desempenho e muita flexibilidade.

JBiggs
fonte