Zaprojektowałem grę RPG, która ma wiele wątków fabularnych, co oznacza, że w zależności od wyboru użytkownika mogą się zdarzyć pewne rzeczy, możesz osiągnąć to samo na kilka sposobów, zakończenie może być inne i tak dalej.
Wdrożyłem prosty silnik decyzyjny, który działa dobrze, ale ma jedną wielką wadę. W momencie podjęcia decyzji na twoją decyzję ma wpływ natychmiastowa historia, co oznacza, że nie możesz podjąć decyzji, która wpłynie na ciebie w dalekiej przyszłości . Dzieje się tak, ponieważ historia rozwija się jak gałąź w strukturze drzewa i zawsze musi wiedzieć, który węzeł jest następny. Pod maską decyzje są wdrażane za pomocą kolejki: każdy węzeł wie o poprzednim węźle i następnym węźle (lub jeśli jest to węzeł decyzyjny, czeka na dane wejściowe użytkownika, aby ustawić następny węzeł)
Widziałem wiele gier ze złożonymi silnikami decyzyjnymi i zastanawiam się, jak są one tworzone? Czy istnieje specjalny projekt, który sprawia, że wszystko jest naprawdę łatwe? Czy ktoś zrobił coś podobnego i może dać mi wskazówkę, jak sobie z tym poradzić?
AKTUALIZACJA 1:
Ważnym aspektem jest zachowanie niezależności kodu opowieści, aby można było nim manipulować z zewnętrznego pliku. Planuję używać tego jako silnika, więc nawet możliwe wybory muszą pochodzić z zewnętrznego pliku. Kod musi być całkowicie abstrakcyjny.
Ponadto interesuje mnie rozwiązanie projektowe, dobry sposób na zrobienie tego, jak inni to zrobili lub zrobili.
źródło
if (isTree)
ani zachowaćisTree
globalnego var, ponieważ historia może mieć wybór. Wiesz co mam na myśli? To bardziej jak silnik wyboru, który będzie obsługiwał wiele historii.isTree=true
, to później robi coś innego, na przykład walcząc ze szkolnym kolegą, który w zamian idzie i ściąga swoje drzewo, gdy drzewo jest jeszcze młode bo skopał mu tyłek. Teraz mamy 2 zmienne, które wpływają na istnienie drzewaisTree==true' and
didFightBrat == false`. Wiesz co mam na myśli? I łańcuch może trwać wiecznie, na istnienie drzewa może mieć wpływ nieznana liczba czynników. Wiesz co mam na myśli?Odpowiedzi:
Możesz także uogólnić kolejkę na ukierunkowany wykres acykliczny (DAG). Możesz przeczytać o nich na Wikipedii. Zasadniczo każdy węzeł może mieć jeden lub więcej węzłów nadrzędnych, od których „zależy”. Cykle nie są dozwolone, tzn. Jeśli A zależy od B, B nie może zależeć od A (bezpośrednio lub poprzez dowolny pośredni łańcuch innych węzłów).
Każdy węzeł znajduje się w stanie „aktywnym” lub „nieaktywnym” i można go aktywować tylko wtedy, gdy wszyscy jego rodzice są już aktywni. Struktura wykresu (jakie są węzły i jak są one połączone) jest częścią danych gry, ale stan aktywny / nieaktywny jest częścią zapisywanych danych gracza.
W ten sposób możesz modelować takie rzeczy: kiedy sadzisz drzewo, oznaczasz zadanie „plantedTree” jako aktywne; potem, w dalszej części gry, kolejne zadanie „treeGrown” określa zarówno „plantedTree”, jak i inny węzeł (część historii) jako jego rodziców. Następnie „TreeGrown” uaktywnia się dopiero, gdy gracz dojdzie do tego momentu w historii, a także „plantedTree” jest aktywne.
Możesz dołączyć inne funkcje, takie jak węzły aktywowane, jeśli którykolwiek z ich rodziców aktywuje się, lub węzły, które są aktywowane przez jednego rodzica i dezaktywowane przez drugiego itd. Jest to dość ogólna struktura do tworzenia opowieści z wieloma współzależnymi wątkami.
źródło
Z tego, co rozumiem, to, czego chcesz, to nie tylko silnik decyzyjny, ale także silnik reguł. Dla każdej decyzji wykonujesz podzbiór reguł określonych przez tę decyzję. Wykonanie tych reguł jest często zależne od stanu niektórych podmiotów, takich jak przykład drzewa.
Zasadniczo, kiedy gracz podejmuje decyzję, szukasz tej decyzji, przestrzegasz zasad, a następnie podajesz następny zestaw dostępnych decyzji, jak zwykle. Jednak reguły są dynamiczne, ponieważ niektóre z nich będą działać tylko na podstawie innych reguł, które już zostały wykonane.
Więcej na Wikipedii .
Z podtytułu Kiedy stosować silniki reguł (nacisk należy do mnie):
Należy zauważyć, że czasami silnik reguł najlepiej wdrażać za pomocą uproszczonego „języka” specyficznego dla domeny lub czegoś takiego jak YAML. Nie sugerowałbym XML.
źródło
Musisz wziąć pod uwagę, że zdarzenie nie jest oparte wyłącznie na decyzji użytkownika. Jak zauważyłeś, jakieś zdarzenie musi się dołączyć, jeśli po podjęciu zestawu sekwencji decyzji, a następnie dołączone zostanie coś innego (np. Dwa dni później).
Myślę, że potrzebujesz sposobu modelowania zdarzeń i sposobu, aby je uruchomić. Podczas gdy pierwszy jest bardziej ograniczony do konkretnego przypadku, ten drugi może być modelowany za pomocą hierarchicznej maszyny stanów (HSM), która bezpośrednio lub pośrednio wyzwala zdarzenia.
Należy pamiętać, że maszyna stanu cierpi na Klątwę wymiarowości, która jest łagodzona jedynie przez strukturę hierarchiczną. Wkrótce zrozumiesz, że musisz modelować złożone znaczenie statusu za pomocą HMS, ale także zapewnić sposób na jego zapytanie.
W tym scenariuszu masz podstawowe zdarzenia (decyzje użytkownika, czas, zmiana pogody itp.), Które są przetwarzane zarówno przez HSM, jak i przez podstawowe wywołania zwrotne zdarzeń. HSM zapewnia model „pamięci”, a wywołania zwrotne umożliwiają opisanie, w jaki sposób pamięć ta musi zostać wykorzystana do obliczenia konsekwencji sekwencji decyzji / zdarzeń zewnętrznych.
Możesz także skończyć na użyciu słownika (lub innej struktury kolekcji) HMS, po jednym dla każdego „aspektu” statusu, który musisz obliczyć. Przykładem może być użycie zdarzenia HMS i jednego dla decyzji podejmowanych przez wywołania zwrotne w celu wyzwolenia zdarzeń.
Cała ta infrastruktura służy temu, by naśladować zachowanie ludzkiego Mistrza Lochów: generalnie zapisuje w pamięci bieżącą sytuację (HMS [„zewnętrzny”]) z powodu decyzji gracza i warunków środowiskowych; gdy coś się dołącza, może podejmować decyzje na podstawie swojego zapisu mentalnego i zapisywać również status wewnętrznej strategii (HSM [„wewnętrzny”]), aby uniknąć reakcji w podobny sposób, jeśli na przykład sytuacja się pojawi.
źródło