Jaki jest najlepszy sposób na wdrożenie systemu drzew dialogowych w mojej grze? Chcę, aby NPC dał graczowi różne zestawy odpowiedzi, niektóre z nich mogą pojawić się tylko wtedy, gdy gracz ma przedmiot lub miało miejsce poprzednie zdarzenie.
Jaki jest najlepszy sposób na wdrożenie systemu drzew dialogowych w mojej grze? Chcę, aby NPC dał graczowi różne zestawy odpowiedzi, niektóre z nich mogą pojawić się tylko wtedy, gdy gracz ma przedmiot lub miało miejsce poprzednie zdarzenie.
Odpowiedzi:
Drzewa dialogowe należy wykonywać przy użyciu XML. Warunki odpowiedzi i odpowiedzi są przechowywane w zagnieżdżonych drzewach z odniesieniem do pliku skryptu, jeśli trzeba zrobić coś bardziej złożonego.
Powinieneś oddzielić skrypty i dialogi osobno, szczególnie jeśli tworzysz RPG o tonie konwersacji. Następnie możesz użyć biblioteki takiej jak simpleXML, aby odczytać plik XML.
Podobne pytanie dotyczy SO z przykładem: https://stackoverflow.com/questions/372915/game-logic-in-xml-files
Chciałbym osadzić w tym język skryptowy, taki jak lua lub ruby, i interakcje w dialogu kodowania.
Tak więc skrypt okna dialogowego może wyglądać następująco:
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!"
Działa to również dobrze do kodowania AI i innych prostych rzeczy, które są przydatne do poprawiania w czasie wykonywania. Możesz nawet dodać edytor wbudowany w aplikację, który można wywoływać podczas uruchamiania w trybie debugowania (lub jako Pisanka).
W grze Stendhal używamy skończonej maszyny stanów do implementacji postaci niezależnych.
Poniższy diagram pokazuje mały przykład z pisania samouczka z zadaniami .
Na początku NPC jest w stanie BIEGU bezczynnego i może chodzić. Gracz może rozpocząć rozmowę mówiąc „cześć”, a NPC przejdzie do stanu UCZESTNICTWO. W tym stanie odpowiada na pytania dotyczące jego „pracy” i oferuje „pomoc” do gry. Gracz może poprosić o misję, a NPC przejdzie do stanu QUEST_OFFERED, czekając, aż gracz zaakceptuje („tak”) lub odrzuci („nie”).
Zdefiniowaliśmy zestaw warunków, które można dołączyć do przejść. Na przykład ukończenie zadania może być możliwe tylko wtedy, gdy zostanie spełniony parametr PlayerHasItemWithHimCondition .
Po wykonaniu przejścia NPC może powiedzieć tekst i / lub wykonać akcję. Podobnie do warunków, które zdefiniowaliśmy, zestaw działań wielokrotnego użytku, takich jak EquipItemAction, który służy do przyznania nagrody za zadanie graczowi.
Wiele warunków można łączyć za pomocą AndCondition , OrCondition i NotCondition . Zwykle po zakończeniu zadania należy wykonać szereg akcji, więc istnieje również klasa MultipleActions .
Chociaż rzeczywista implementacja w Stendhal cierpi z powodu braku możliwości łatwego tłumaczenia na inne (ludzkie) języki, myślę, że ogólna koncepcja jest dobra.
Myślę, że do dodawania tłumaczeń nadal można użyć XML do logiki, jak podano powyżej . Kiedy wchodzisz w tego rodzaju złożoność, powinieneś napisać własne narzędzie dialogu. Twój tekst dialogowy zostanie zapisany jako klucz do bazy danych, którą możesz wymienić w zależności od języka, który chcesz wyświetlić.
Na przykład możesz mieć:
<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>
Wówczas renderer tekstu zadania zastąpiłby „Localize.FixMyCar” odpowiednio przetłumaczonym tekstem.
Twoje narzędzie wyświetlałoby to, co odtwarzacz zobaczyłby w wybranym języku obok edytowalnego surowego XML.
Podobnie możesz użyć czegoś takiego z podanego przykładu :
npc.add(ConversationStates.ATTENDING,
ConversationPhrases.QUEST_MESSAGES,
null,
ConversationStates.QUEST_OFFERED,
Localization[ "BringMeABeer" ],
null);
Jeśli twoje klucze są wystarczająco opisowe, brak pełnego tekstu nie powinien być problemem.
Przydałoby się coś takiego:
Localization[ "<Location>.<NPC_name>.<Dialogue_text_key>" ];
Dane napędzają twoje postacie za pomocą skryptów LUA, a nawet plików XML. Kiedy wchodzisz w interakcję z NPC, weź dołączony do niego plik, przeczytaj go, dostosuj wszystkie zmienne gry, które mogły zostać wyzwolone, i uzyskaj prawidłową odpowiedź.
Największą korzyścią z robienia tego w ten sposób jest to, że możesz łatwo wejść do okna dialogowego i manipulować nim, dodawać nowe znaki itp. Unikasz również zepsucia bazy kodu dzięki specjalnej logice obsługi każdego przypadku.
Jeśli masz dość głęboki zestaw drzew dialogowych, użyj ChatMapper . Posiadają w pełni funkcjonalną bezpłatną wersję, a narzędzie pozwala na eksport drzew dialogowych do formatu XML. Korzystam z niego i jest to doskonały sposób na wizualizację i organizację złożonych drzew dialogowych.
Jeśli Twoje okna dialogowe są dowolnej złożoności, najważniejszą rzeczą, której potrzebujesz do implementacji okien dialogowych, jest sposób na zrozumienie złożoności interakcji. Polecam jakiegoś edytora węzłów, aby to zwizualizować, chociaż nie mam dobrych dobrych systemów otwartych do polecania.
Myślę, że używasz własnego języka skryptowego do kierowania tego typu grą (jeśli nie, powinieneś). Następnie rozwiń skrypt do obsługi okien dialogowych.
Możesz pracować z innymi zmiennymi gry podczas tworzenia logiki dialogów. Silniki gier są jak Lego. Zaprogramowałeś tylko cegły, a skrypt ich używa. Nie ma znaczenia, czy wykonasz interpreter skryptów lub kompilator. Ale skrypt jest zawsze przydatny.
Prosty automat może wykonać:
(dialogueline_id, condition) -> (next_id, response)
Może to wyglądać mniej więcej tak:
(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!!!")
W grze znajdziesz identyfikator i spróbuj dopasować identyfikator i warunek.
Musisz wymodelować warunki i działania. Według obiektów, wskaźników funkcji, XML ...
Przyda się również dobry edytor dialogów.