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
fonte
if
'selse
',switch
'scase
' e 's, esperando que você termine antes de perder a sanidade.Respostas:
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:
Onde a 2ª opção aparece apenas se
flags & 64
estiver definida. Você também pode implementar asetflag
opçã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 propriedadecan_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:
e:
fonte
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:
Algumas desvantagens são:
fonte
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.
fonte
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.
fonte
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.
fonte