Qual é a melhor maneira de implementar um sistema de árvore de diálogo no meu jogo? Eu quero que um NPC dê ao jogador diferentes conjuntos de respostas, algumas que só podem aparecer quando o Jogador tiver um item ou um evento anterior.
Qual é a melhor maneira de implementar um sistema de árvore de diálogo no meu jogo? Eu quero que um NPC dê ao jogador diferentes conjuntos de respostas, algumas que só podem aparecer quando o Jogador tiver um item ou um evento anterior.
Respostas:
As árvores de diálogo devem ser feitas usando XML. Você armazena as condições para as respostas e a resposta em árvores aninhadas com uma referência a um arquivo de script se precisar fazer algo mais complexo.
Você deve manter os scripts e o diálogo separados, especialmente se estiver montando um RPG com uma tonelada métrica de conversas. Você pode usar uma biblioteca como simpleXML para ler o arquivo XML.
Há uma pergunta semelhante no SO com um exemplo: https://stackoverflow.com/questions/372915/game-logic-in-xml-files
Eu procuraria incorporar uma linguagem de script como lua ou ruby e interações de diálogo de codificação nisso.
Assim, um script de diálogo pode se parecer com:
switch showDialog "Why don't you just leave me along!", "Okay", "But I found your dog!"
case 1:
showDialog "And stay gone!"
case 2:
if playerHasObject "dog"
showDialog "Thank you!"
else
showDialog "Liar!"
Isso também funciona bem para codificar a IA e outras coisas simples que são úteis para ajustar durante o tempo de execução. Você pode até adicionar um editor incorporado ao seu aplicativo que possa ser chamado durante a execução de depuração (ou como um ovo de Páscoa).
No jogo Stendhal, usamos uma máquina de estados finitos para implementar NPCs.
O diagrama a seguir mostra um pequeno exemplo do tutorial de como escrever missões .
No início, o NPC está em um estado ocioso e pode estar andando por aí. Um jogador pode iniciar uma conversa dizendo "oi" e o NPC passará ao estado ATENDO. Nesse estado, ele responde a perguntas sobre o seu "trabalho" e oferece algum jogo "ajuda". O jogador pode pedir uma missão e o NPC irá declarar QUEST_OFFERED esperando que o jogador aceite ("sim") ou recuse ("não").
Definimos um conjunto de condições que podem ser anexadas às transições. Por exemplo, concluir uma missão pode ser possível apenas se uma condição PlayerHasItemWithHimCondition for atendida.
Após a execução da transição, o NPC pode dizer algum texto e / ou executar uma ação. Semelhante às condições, definimos um conjunto reutilizável de ações como EquipItemAction, que é usado para recompensar a missão de um jogador.
É possível combinar várias condições usando AndCondition , OrCondition e NotCondition . Geralmente, existem várias ações a serem executadas na conclusão da missão, portanto há também uma classe MultipleActions .
Embora a implementação real em Stendhal sofra por não ser traduzível em outras línguas (humanas) facilmente, acho que o conceito geral é bom.
Penso que, para adicionar traduções, você ainda pode usar XML para a lógica, conforme declarado acima . Ao entrar nesse tipo de complexidade, escreva sua própria ferramenta de diálogo. O texto do seu diálogo seria armazenado como uma chave para um banco de dados que você poderia trocar dependendo do idioma que deseja exibir.
Por exemplo, você poderia ter:
<dialogue id="101" condition="!npc.carsFixed">
<message>Localize.FixMyCar</message>
<choices>
<choice condition="hero.carFixingSkill > 5" priority="7" id="Localize.Sure">
<command>hero.carFixingSkills += 1</command>
<command>npc.carFixed = true</command>
<command>hero.playSmokeAnimation()</command>
<command>nextDialogue = 104</command>
</choice>
<choice condition="hero.carFixingSkill <= 5" id="Localize.CantFix">
<command>nextDialogue = 105</command>
</choice>
<choice id="Localize.FixYourself">
<command>npc.likesHero -= 1</command>
</choice>
</choices>
</dialogue>
Em seguida, o representante de texto da missão substitui "Localize.FixMyCar" pelo texto traduzido adequadamente.
Sua ferramenta exibia o que o player veria em um idioma selecionável ao lado do XML bruto editável.
Da mesma forma, você pode usar algo como isso no exemplo que você referenciou :
npc.add(ConversationStates.ATTENDING,
ConversationPhrases.QUEST_MESSAGES,
null,
ConversationStates.QUEST_OFFERED,
Localization[ "BringMeABeer" ],
null);
Se suas chaves forem descritivas o suficiente, não ter o texto completo não deve ser um problema.
Algo assim também pode ser útil:
Localization[ "<Location>.<NPC_name>.<Dialogue_text_key>" ];
Os dados direcionam seus caracteres com scripts LUA ou mesmo arquivos XML. Ao interagir com um NPC, pegue o arquivo que está anexado a ele, leia-o, ajuste-o para quaisquer variáveis do jogo que possam ter sido acionadas e produza a resposta válida.
O maior ganho ao fazê-lo dessa maneira é que você pode facilmente entrar e manipular a caixa de diálogo, adicionar novos caracteres etc. Você também evita estragar sua base de código com uma lógica especial ao lidar com todos os casos.
Se você possui um conjunto bastante profundo de árvores de diálogo, use o ChatMapper . Eles têm uma versão gratuita com todos os recursos e a ferramenta permite exportar suas árvores de diálogo para XML. Eu o uso e é uma excelente maneira de visualizar e organizar árvores de diálogo complexas.
Se suas caixas de diálogo tiverem alguma complexidade, o mais importante para a implementação da caixa de diálogo é uma maneira de entender a complexidade de sua interação. Eu recomendo um editor de nó de algum tipo para visualizar isso, embora eu não tenha bons sistemas abertos para recomendar.
Eu acho que você usa sua própria linguagem de script para direcionar esse tipo de jogo (se não, você deveria). Em seguida, expanda seu script para manipulação de diálogos também.
Você pode trabalhar com outras variáveis do jogo durante a criação da lógica dos diálogos. Motores de jogos são como Lego. Você programou apenas tijolos e o script os utiliza. Não importa se você cria algum interpretador ou compilador de script. Mas o script é sempre útil.
Autômato simples pode fazer:
(dialogueline_id, condition) -> (next_id, response)
Pode ser algo como isto:
(1, troll is hungry?) -> (2, say "troll be hungry")
(2, player has bananas?) -> (3, say "hey, you have bananas!")
(3, ) -> (-1, (say "i like bananas, i take them and eat, you may pass, bye", remove bananas, feed the troll))
(2, player does not have bananas?) -> (-1, say "go away!!!")
No jogo, você encontra o id e tenta combinar o id e a condição.
Você precisa modelar as condições e ações. Por objetos, ponteiros de função, XML ...
Um bom editor de diálogo também será útil.