Moje pytanie brzmi:
Jak poradzić sobie ze stanami gry w moim systemie encji bez uciekania się do utrzymywania stosu obiektów stanu gry w pobliżu?
Tak więc projekt mojego systemu encji oznacza, że gdy encja musi się zarejestrować na przykład dla zdarzeń wejściowych, komponent wejściowy wywołuje system wejściowy i mówi „zarejestruj tę encję dla tego wejściowego”. Wszystko jest w porządku i dobrze, jednak jeśli dodasz do tego pojęcie stanów gry (powiedzmy ekran pauzy), trudno będzie ustalić, czy jednostka jest w obecnym stanie i powinna otrzymać dane wejściowe.
Mógłbym ulepszyć komponent wejściowy / system tak, aby powiedział: „zarejestruj ten byt dla tego wejścia w tych stanach gry”, ale wymaga to, aby każdy byt wiedział, w których stanach będzie używany, i może to nie być oczywiste. Również utrzymywanie listy stanów gry wokół zarejestrowanych danych wejściowych (i innych systemów korzystających z wywołań zwrotnych) nie wydaje się zbyt wydajne.
Innym pomysłem, jaki miałem, było istnienie bytu reprezentującego stan gry, oznaczenie tego jako wyłączone, a następnie podczas generowania zdarzenia wejściowego sprawdź, czy byt nie jest potomkiem wyłączonego bytu stanu gry. Kosztowne jest ustalenie rodzica dla każdego oddzwaniania.
Innym pomysłem jest, aby wszystkie systemy zapisywały swoje dane w kluczach względem bieżącego stanu, w ten sposób podczas generowania danych wejściowych jednostka docelowa nawet nie będzie kandydatem. Jednak to naprawdę szkodzi możliwości umożliwienia komunikacji między bytami w różnych stanach (nie jest to tak bardzo problemem dla ekranów pauzy, ale pomyśl wybieranie zamka w Oblivion / Skyrim).
Jedynym innym pomysłem, jaki miałem, było to, aby wszystkie komponenty obsługiwały zdarzenia związane ze zmianą stanu i komunikowały się z odpowiednim systemem, aby wyłączyć wszystko, co zarejestrowały, i włączyć je ponownie po przełączeniu do tego stanu.
Drugi (oznacz obiekt jako wyłączony) i czwarty (każą każdemu komponentowi radzić sobie ze zmianami stanu) wydają się najlepszymi z moich pomysłów, ale żaden z nich nie wyskakuje na mnie jako wyjątkowo dobry.
Czy ktoś jeszcze ma jakieś pomysły, jak to zrobić?
edytuj Mówiąc o danych wejściowych w tym pytaniu, może to oznaczać dowolny system zdolny do wysyłania wiadomości / zdarzeń do podmiotów, takich jak kolizje, zdarzenia czasowe itp.
źródło
Odpowiedzi:
Często używany jest półprodukt,
Intent System
który wyodrębnia dane wejściowe i śledzi kontekst i odpowiednie gry.System Intent przestanie na przykład przekazywać sygnały wejściowe, gdy symulacja zostanie na przykład wstrzymana. Obsługuje również mapowanie między zdarzeniami kontrolera a zamiarami (poruszanie się w kierunku, bieganie, strzelanie, przeładowanie ...).
W ten sposób twoje inne elementy nie są zależne od konkretnych gamepadów / wejść (BUTTON_A, BUTTON_B vs BUTTON_X, BUTTON_O ...), ale wszystkie reagują na te same zamiary (IntentRun, IntentReload ...).
Kolejną zaletą jest to, że system intencji może być świadomy dodawania / usuwania dostępnych kontrolerów, ponieważ może wysyłać intencje do dowolnego subskrybenta, nawet poza symulacją, z którą można sobie poradzić
AddPlayer(controllerID)
.Ile informacji o stanie gry przekazujesz systemowi poprzez zdarzenia / wiadomość lub bezpośrednio od Ciebie. Ale czas zainwestowany w system Intent jest zwykle tego wart.
Możesz zarządzać kontekstami intencji, które generują intencje, gdy są one dołączone do systemu.
Kontekst może mieć priorytet, tj .:
W ten sposób możesz dodawać i usuwać konteksty, które są obecnie istotne.
Jedną rzeczą dotyczącą całego systemu intencji jest to, że powinien on działać, gdy symulacja jest wstrzymana.
Jednym ze sposobów, który jest często używany do grania / wstrzymywania symulacji gry bez przerywania aktualizacji niezwiązanych z symulacją, jest użycie innego zestawu czasów. tj
GenericSystem::onTime(Long time, Long deltaTime, Long simTime, Long simDeltaTime)
.Dzięki takiemu podejściu silnik może po prostu blokować przyrosty czasu simTime gier, co z kolei blokuje aktualizacje odpowiednich silników animacji i fizyki, które używają,
simTime and simDeltaTime
jednocześnie umożliwiając ciągłe aktualizacje efektu sprężyny kamery, jeśli musi się poruszać nawet podczas pauzy, animacja efekt ładowania na wirtualnym billboardzie w grze podczas pobierania danych ...źródło
Co powiesz na utworzenie globalnego systemu zdarzeń, a następnie posiadania komponentu detektora zdarzeń dla każdej jednostki? Po wydarzeniu „Zmiana stanu gry” można było bawić się komponentami indywidualnie dla każdego konkretnego podmiotu.
Powiedzmy, że masz komponent wejściowy. Po tym, jak komponent nasłuchiwania zdarzeń otrzyma zdarzenie zmiany stanu gry, zmienia bardzo specyficzne wartości dla tego konkretnego komponentu wejściowego, aby nie odbierał żadnych wywołań wejściowych ani nie wykonywał żadnych ruchów ani odpowiedzi do systemu lub jego właściciela.
Działa to dla mnie, ponieważ większość moich komponentów jest skryptowana (przez Lua). Tzn. Mam komponent wejściowy, który jest uruchamiany raz po naciśnięciu klawisza i uruchamia ruch + kierunek, a następnie jest wyzwalany, gdy klawisz jest zwolniony i uruchamia się w kierunku stop +. Istnieje również komponent nasłuchiwania zdarzeń, który kontaktuje się z komponentem wejściowym (jeśli gra jest wstrzymana), aby przestać uruchamiać jakąkolwiek funkcję i zatrzymać, jeśli to konieczne. Mógłbym wtedy łatwo dodać inny byt z inną reakcją na te same zdarzenia i naciśnięcia klawiszy, używając innego skryptu. W ten sposób można zapisać interakcję między różnymi podmiotami w różnych stanach, a nawet uczynić ją bardziej dostosowywalną. Co więcej, niektóre podmioty mogą nawet nie zawierać w sobie komponentu detektora zdarzeń.
To, co właśnie wyjaśniłem, jest w zasadzie praktycznym przykładem czwartego rozwiązania.
źródło