Elegancki sposób na symulację dużej liczby bytów w świecie gry

33

Załóżmy, że masz grę, w której istnieje wiele (wiele) bytów pełniących niektóre funkcje, z których nie wszystkie są stale potrzebne lub należy je rozpatrywać w każdej ramce. Konkretnym problemem, nad którym pracuję, w którym występuje ten problem, jest szczegółowa symulacja ciała, w tym jego organów.

W grze każde stworzenie ma własne ciało, które jest podzielone na mniejsze części (tułów, nogi itp.), A czasami te części zawierają narządy, które pełnią określoną funkcję w ciele. To, czy organ obecnie służy celowi, czy jest aktywny, nigdy nie jest jasne. W końcu zwierzę może mieć pusty żołądek, który w związku z tym nie musi niczego trawić. Sprawdzanie lub symulacja każdego obiektu w każdej klatce byłoby bardzo śmieszne i bardzo kosztowne, gdy tylko pojawi się wiele stworzeń na świecie. Zastanawiałem się więc nad sposobem inteligentnego rozróżnienia między obiektami, które wymagają aktualizacji, a tymi, które tego nie robią.

To, co wymyśliłem, wydaje się co najmniej dobrym rozwiązaniem. Tworzy prostą kolejkę / stos (istotne jest to, że każdy element jest usuwany natychmiast po jego odczytaniu; kolejność nie ma znaczenia) nazywana „stosem uwagi”, w którym znajdują się obiekty, które należy symulować. Przedmioty wymagające uwagi po prostu ułożyłyby się na stosie lub zostałyby tam umieszczone przez inne obiekty. Obiekty te prawdopodobnie zaimplementują prosty interfejs z funkcją simulate ().

W przypadku mojego poprzedniego przykładu trawienia oznaczałoby to:

Gracz wybiera z ekwipunku coś do jedzenia (zakładając, że to chleb) i wkłada go do ust swojej postaci, a usta umieszcza na stosie uwagi. W następnej klatce usta są pobierane ze stosu i wywoływana jest jego funkcja symulacji (). Ponieważ jest to usta, rozsądnie byłoby symulować tutaj żucie. Może to trwać kilka ramek, w których usta ustawiają się na stosie, dopóki nie zdecydują, że jedzenie jest gotowe do połknięcia. W tym przypadku usta wkładają przeżuty chleb do żołądka (wiem, że nie trafia tam bezpośrednio, ale przełyk jest pominięty dla uproszczenia), który jest następnie umieszczany na stosie uwagi. W następnej ramce rozpoczyna się symulacja procesu trawienia. I tak dalej dla pozostałych niezbędnych narządów.

Przewidywalnym problemem z tym są obiekty na biegu jałowym. Śpiące zwierzę jest tego dobrym przykładem. Można to zrobić zgodnie z wcześniejszym opisem, utrzymując śpiące zwierzę na stosie i za każdym razem sprawdzając, czy trzeba się obudzić, ale wydaje się to marnotrawstwem, ponieważ jest to jedyna rzecz, jaką się robi. Aby uczynić obiekty na biegu jałowym bardziej wydajnym, planowałem dodać rodzaj harmonogramu, który przechowuje zadania do wykonania w określonym czasie. Jeśli zwierzę pójdzie spać, wykona pracę według tego harmonogramu, który będzie zaplanowany na pewien czas po tym, jak zwierzę pójdzie spać. Zadanie to polegałoby na ponownym umieszczeniu śpiącego zwierzęcia na stosie uwagi. Teraz możesz powiedzieć, że śpiące zwierzę, które nie znajduje się na stosie uwagi, może przegapić atak czegoś, ponieważ jego sztuczna inteligencja nie jest symulowana,

Teraz, szczerze mówiąc, nie wiem, czy jest to blisko eleganckiego rozwiązania tego problemu z powodu braku doświadczenia. Czy jestem blisko czegoś użytecznego? Jak to zwykle się robi lub czy ktoś ma jakieś sugestie lub lepsze rozwiązania?

Marc Müller
źródło

Odpowiedzi:

10

Właśnie w ten sposób rozwiązaliśmy ten problem w Stendhal . W naszym przypadku jest wiele rzeczy, które dzieją się okresowo, ale nie co turę: Czary leczące, rośliny rosnące nieco dalej, zwyrodnienia zwłok, przedmioty na ziemi wygasają.

Mamy numer tury, który jest zwiększany w każdej turze. Utrzymujemy mapę przyszłych numerów zakrętów wskazującą na zestaw obiektów, które należy powiadomić w tym zakręcie.

Hendrik Brummermann
źródło
co jeśli w międzyczasie coś innego wchodzi w interakcję z obiektem? Na przykład śpiące zwierzę może obudzić uderzający kamień. Czy w takim przypadku należy usunąć harmonogram zwierzęcia?
Emiliano
To zależy od sytuacji: jeśli wykonane działanie jest nieszkodliwe (jak budzenie się, gdy już nie śpisz), po prostu pozwalamy, aby to się stało. Ale jeśli akcja zużyje jakiś zasób, przeszukujemy oczekującą kolejkę i usuwamy ją.
Hendrik Brummermann
14

Brzmi jak problem z wejściami: masz ponad 100 klawiszy na klawiaturze, ale nie chcesz sprawdzać każdego klawisza w każdej ramce, więc co robisz?

Dwie odpowiedzi: ankiety lub komunikaty systemowe.

Sondowanie = w dowolnym momencie, gdy miałoby to znaczenie w grze, sprawdź stan klawiszy klawiatury (lub obiektów, w twoim przypadku). Resztę czasu ignoruj.

Wiadomości = każe klawisz klawiaturowy (obiekt) umieszcza coś w kolejce wiadomości po naciśnięciu lub zwolnieniu (gdy wymaga uwagi). Podczas każdej iteracji pętli gry przegląda kolejkę i rozwiązuje wszystkie wiadomości przed kontynuowaniem.

Ian Schreiber
źródło
10

Cofnę się więc od wdrożenia i przejrzę pytanie z perspektywy projektowania. Czy masz solidny plan wyświetlania wszystkich szczegółów, które chcesz uwzględnić w tej symulacji?

Na przykład:

  • Czy gracz może odróżnić zwierzę z pustym żołądkiem od zwierzęcia z pełnym żołądkiem?
  • Czy te informacje mają dla nich jakiekolwiek znaczenie, gdy dokonują wyborów interakcji w grze?
  • Czy gracz obserwujący zwierzę może konsekwentnie przewidywać wynik symulowanych wydarzeń, czy może wystarczyłaby liczba losowa?

Zasadniczo ogólną zasadą jest, aby twoja symulacja nie była bardziej skomplikowana niż jej wyniki. Na koniec dnia, jeśli jedynymi animacjami dla owiec są pasanie się, spanie, ucieczka. Zatem tak naprawdę nie ma znaczenia, ile czynników decyduje o tym, który stan wybrać. Wszyscy gracze zobaczą owce śpiące w nocy, uciekające przed niebezpieczeństwem i jedzące w ciągu dnia.

Symulacja zachowania to mnóstwo zabawy, ale zawsze pamiętaj o wrażeniach użytkowników końcowych.

wkerslake
źródło
Tak, gracz będzie w stanie rozpoznać różnicę i ma to kilka efektów na rozgrywkę, ale w tej chwili jest to raczej „chwyt” dla zabawy. Coś w rodzaju systemu ran w Twierdzy Krasnoludów, który jest również bardzo szczegółowy, ale nieistotny. Ale jak już wspomniałeś, praca nad tym jest świetną zabawą i to jest teraz mój główny cel.
Marc Müller,
9

Miałem podobny problem z grą, nad którą pracowałem kilka lat temu - symulacja obiektów była złożona i nie można jej było szczegółowo wykonać na każdym obiekcie na świecie.

Rozwiązaniem było użycie koncepcji LOD do symulacji. Obiekty znajdujące się w polu widzenia gracza uruchomiłyby pełną symulację. Obiekty odległe od gracza okresowo przeprowadzały bardzo uproszczoną symulację. Gdy obiekty pojawiły się w polu widzenia gracza, przechodziły z kursu, okresowej aktualizacji symulacji do szczegółowych, regularnych aktualizacji.

Skizz
źródło
2

Rozwiązanie z harmonogramem jest dobre. Należy pamiętać, że każdy podmiot powinien mieć listę wskaźników do swoich przyszłych działań, co daje możliwość unieważnienia przyszłych działań w razie potrzeby. To znaczy. śpiące zwierzę budzi się natychmiast po zaatakowaniu, więc musisz anulować jego budzenie w przyszłości.

użytkownik2047
źródło
1

Jest na to wzór projektowy. Myślę, że to się nazywa obiekty bazy danych?

Zasadniczo trzymasz jedną „szablonową” owcę, która może reprezentować wszystkie nie-specjalne owce w świecie gry, narysuj je w ten sam sposób, zachowując unikalne dane w obiekcie szablonu, powiedzmy jako tabelę lokalizacji owiec i / lub czasu - od ścinania. Następnie, gdy trzeba uczynić owcę wyjątkową, można utworzyć konkretną instancję do śledzenia tej unikalnej owcy.

To samo dotyczy animacji. Jeśli jest to bezczynna animacja lub zdarzenie wspólne dla każdej instancji, może ona znajdować się w instancji szablonu, gdzie bardziej szczegółowe animacje można zaplanować osobno.

Dawno temu napisałem grę dla konkursu programistycznego, której główna pętla właśnie nazywała się animate () na całej scenie. Wykorzystał wskaźniki funkcji do zastąpienia bezczynnych animacji innymi, stosownie do potrzeb, i zastosował tę technikę do obsługi odziedziczonej animacji (np. Obracając postać stojącą na obracającym się dysku).

Ma to podobny charakter do używania delegata do animacji.

davenpcj
źródło
3
Masz na myśli wzór Flyweight?
topright
0

Czy maszyna stanu działałaby? Zwierzę jest w stanie np. Spania, jedzenia, biegu itd. Do każdego stanu przypisuje się listę aktywnych narządów. Tak więc każdą klatkę, którą odwiedzasz, przełączaj stan, przeglądaj listę organów dla tego stanu i wykonuj aktualizację na każdym z narządów.

Erik Engheim
źródło
Myślę, że skomplikowałoby to wszystko, ponieważ w zwierzęciu musi istnieć wiele rzeczy. Na przykład fakt, że żołądek coś trawi, nie oznacza, że ​​serce przestaje bić lub zwierzę przestaje chodzić. Jasne, możesz zdefiniować zestaw stanów, z których każdy bierze pod uwagę pewne funkcje, ale liczba stanów byłaby niesamowicie duża.
Marc Müller,
W jednym stanie może się zdarzyć wiele rzeczy, ponieważ przechowujesz wszystkie aktywne narządy w jednym stanie i wykonujesz każdy z nich w każdej ramce. Wiele z tego, co dzieje się w twojej symulacji, wydaje się jednak pasować do przejść między stanami. Np. Żucie -> Trawienie. Ale myślę, że masz rację, że zwierzę nie może mieć tylko jednego stanu. Zdarzają się przemiany stanu, powiedzmy, z kończynami niezwiązanymi z przemianami stanu zachodzącymi w układzie trawiennym. Ale może jest to bardziej skomplikowane niż to, co masz. Pomyślałem, że to może być coś do rozważenia.
Erik Engheim,