Alternatywa dla Game State System?


30

O ile wiem, większość gier ma jakiś „system stanu gry”, który przełącza się między różnymi stanami gry; mogą to być na przykład „Intro”, „MainMenu”, „CharacterSelect”, „Ładowanie” i „Gra”.

Z jednej strony sensowne jest rozdzielenie ich na system państwowy. W końcu są one rozbieżne i w przeciwnym razie musiałyby znajdować się w dużej instrukcji przełączania, która jest oczywiście niechlujna; i z pewnością są dobrze reprezentowani przez system państwowy. Ale jednocześnie patrzę na stan „Gry” i zastanawiam się, czy coś jest nie tak z tym podejściem do systemu stanów. Ponieważ to jest jak słoń w pokoju; jest OGROMNY i oczywisty, ale nikt nie kwestionuje podejścia systemu stanu gry.

Wydaje mi się głupie, że „Gra” jest ustawiona na tym samym poziomie, co „Menu główne”. Nie ma jednak sposobu na przełamanie stanu „Gry”.

Czy najlepszym rozwiązaniem jest system stanów gry? Czy istnieje jakaś inna, lepsza technika zarządzania, no cóż, „stanem gry”? Czy można wprowadzać stan, który rysuje film i nasłuchuje, a następnie stan ładowania zapętla się w menedżerze zasobów, a następnie stan gry, który robi praktycznie wszystko ? Czy to również nie wydaje ci się niezrównoważone? Czy coś brakuje?

Odpowiedzi:


30

Myślę, że tutaj po prostu dyskutujesz semantyką. Nazywa się Game State, ponieważ zachowuje się jak skończona maszyna stanów , ze skończoną liczbą stanów i przejść między nimi. „Gra” w „Systemie stanu gry” odnosi się do całego systemu, przy czym „Ładowanie”, „Menu główne” itp. To stany gry. Można je łatwo nazwać „scenami”, „ekranami” lub „poziomami”. To tylko semantyka.

Nie jestem pewien, czy obowiązuje już ścisły FSM. W moich implementacjach nazywam stany „ekranami” i pozwalam na ich ustawianie jeden na drugim - tj. ekrany można rysować na innych ekranach, kontrolując, czy ekrany pod nimi są aktualizowane czy rysowane. W ten sposób mogę mieć jednocześnie aktywnych wiele ekranów z niezależną logiką i kodem specyficznym dla tego ekranu, bez martwienia się o inny ekran.

Na przykład ekran pauzy można otworzyć na moim głównym ekranie gry, który nie zezwala na aktualizacje, ale umożliwia rysowanie poniżej siebie. Ekran ekwipunku postaci może umożliwiać zarówno rysowanie, jak i aktualizację - dzięki czemu gra będzie kontynuowana podczas pracy w ekwipunku.


dokładnie tak należy to zrobić. Ekrany powinny zawierać wiele innych ekranów w architekturze drzewiastej. Twój program zawiera ekran gry, który zawiera ekran menu pauzy, który zawiera ekran ustawień audio i ekran ustawień gry. itp.
Iain

1
Chciałbym zobaczyć przykładowy kod źródłowy do tego! (Najlepiej w C ++ / C # / Java)
Zolomon

1
Niestety, w tej chwili mam tylko kod produkcyjny, ale podobna koncepcja występuje w próbce XNA Game State: creators.xna.com/en-GB/samples/gamestatemanagement
DrDeth

7

Pewnie stan Gry byłby ogromny, ale nie ma powodu, aby sam stan Gry nie mógł zawierać automatu stanów do zarządzania swoimi danymi. Hierarchiczne maszyny stanów są przydatne.


4

Zawsze lubię myśleć o każdym „stanie” jak o „scenie”. Film otwierający jest sceną, tylko statyczną. Kredyty są sceną. Menu to scena. Jedyną różnicą między nimi jest poziom interaktywności i logiki gry.


3

Właściwie to też mam z tym problemy.

Powiedzmy, że masz grę.

Zamiast zmieniać grę w stan „Ładowanie”, „Menu główne” itp. - IMO lepiej pozwolić, aby gra miała kilka stanów:

„Ładowanie” - „wyświetlanie menu” - „wstrzymane” itp.

Gra nadal działa, ale gdy wyświetli się menu główne, będzie w trybie „pokaż menu”.

A gdy gra nie jest w żadnym konkretnym stanie, po prostu działa.

Przynajmniej dla mnie ma to sens. :)


Zgadzam się. Nikt nie chce wyjść ze stanu gry tylko po to, aby wejść w stan pauzy . Z drugiej strony: wciąż jest to system państwowy ... właśnie zagnieżdżony :)
bummzack

2

Program online (w tradycyjnym znaczeniu online, tj. Ciągłe uruchamianie i reagowanie na dane wejściowe, a nie połączenie z Internetem) zazwyczaj składa się z 3 rzeczy:

  • zbieranie i obsługa danych wejściowych
  • aktualizacja logiki
  • wydajność

Ogólnie rzecz biorąc, te 3 są powiązane i zmieniają się w tym samym czasie. Na przykład podczas wyświetlania ekranu powitalnego możesz zmapować wszystkie klawisze na polecenie „zamknij ekran”, a aktualizacja może powoli zanikać grafikę, a wynik po prostu pokazuje tę grafikę. Ale podczas gry wszystkie klawisze mogą być przypisane do różnych poleceń, a aktualizacja zmienia właściwości wielu obiektów w grze.

Kiedy patrzysz na to w ten sposób, sensowne jest oddzielenie Intro od tworzenia postaci i właściwej gry: każda z nich ma swój własny zestaw zasad wprowadzania, aktualizacji i wyjścia. Są prawie jak samodzielne programy, które dzielą się danymi i kodem biblioteki. Mając to na uwadze, zwykle ma sens tylko jeden stan Gry, ponieważ rozgrywka jest dość jednorodna.

Oczywiście, jeśli faktycznie masz oddzielne typy rozgrywki (np. Przykład RPG - Mapa świata, Mapa miasta, Cutscene, Walka), z różnymi wejściami, aktualizacjami i wynikami, nie ma powodu, dla którego nie miałbyś wielu stanów też zamiast tylko 1 stanu gry. Ale to zależy od twojej gry.


1

Patrzę na to z innej strony. „Menu”, „Najlepsze wyniki”, „kredyty” lub „co”, można uznać za kolejny poziom, a wtedy stan ten niekoniecznie jest lżejszy niż stan „gry” (stan gry zawiera po prostu więcej podmiotów, i różne, ale ostatecznie to tylko kolejny poziom, na którym byty wykazują bardziej przewidywalne zachowanie, a „mapy” są na ogół mniej skomplikowane).
Zmiana tego sposobu myślenia zdecydowanie wyciąga cię z syndromu „nudnego menu”.


Chciałem powiedzieć to samo ... Wszystkie moje menu, ekrany, cokolwiek, to tylko kolejny poziom.
speeder

1

W mojej grze mam:

Kierownik realizacji , który inicjuje aplikację (grę), ładuje zasoby, zwalnia zasoby przy wyjściu z aplikacji itp. Inicjuje silnik aplikacji, GameViewEngine, GameLogicEngine.

Game State Manager , który znajduje się w GameLogicEngine i jest odpowiedzialny za kontrolowanie rzeczy związanych z główną pętlą gry: wykrywanie kolizji, obliczanie fizyki, czytanie klawiatury, operacje matematyczne itp.

Początkowo miałem zazwyczaj tylko jednego Game State Managera, który był częścią mojej GameLogicEngine. Miałem jednak pewne trudności z kontrolowaniem inicjalizacji głównych podsystemów (GameLogic, ApplicationEngine, ...). Można było to zrobić, ale było bardziej niechlujne, imo.

Teraz wszystko wydaje mi się bardziej przejrzyste i jestem zadowolony z projektu.


0

Zmień nazwę stanu „Gra” na „Gameplay”. Wtedy twoja logika wydaje się lepsza; Zatrzymujesz grę, aby przejść do menu: wychodzisz ze stanu gry, aby przejść do stanu menu głównego.

Ponadto uważam, że rzeczy takie jak pauza, które wymagałyby, aby gra była w tym samym stanie, co po wstrzymaniu gry, nie powinny być osobnymi stanami. Być może państwa dzieci i gniazdowanie? Rozgrywka ma menu pauzy.


0

Myślę, że istnieje dobra metoda zwana stosem stanu gry. Nie widziałem żadnych artykułów ani artykułów na ten temat, ale głos rozprzestrzenia się trochę. Zasadniczo najwyższy stan gry na stosie jest nazywany pierwszy i robi wszystko, co chce, z wejściem / renderowaniem itp. Najwyższy stan gry jest jedynym, który może przesuwać lub popować stany.

W moim silniku stany gry są w rzeczywistości tylko listami podmiotów gry. Następnie mam podmioty, które działają jak menu. Moje stany menu albo wstrzymują grę (nie aktualizując następnego elementu na stosie), ale pozwalają innym stanom przesuwać swoje modele do renderera, dzięki czemu moje menu pauzy (które nie obejmuje całego ekranu) nadal renderowanie gry z tyłu.

Mam nadzieję, że daje to wyobrażenie o nieco innym systemie, który nie jest oparty na maszynie stanów.


0

Czy można wprowadzać stan, który rysuje film i nasłuchuje, a następnie stan ładowania zapętla się w menedżerze zasobów, a następnie stan gry, który robi praktycznie wszystko? Czy to również nie wydaje ci się niezrównoważone? Czy coś brakuje?

To jest w porządku. A przynajmniej jest to poprawa w stosunku do „posiadania dużego brzydkiego przełącznika w zależności od stanu gry”.

Chciałbym zaznaczyć, że w większości gier będziesz już potrzebować pewnego rodzaju maszyny o skończonym stanie, aby poradzić sobie z prostą sztuczną inteligencją jednostek. Typowym przykładem są wrogowie w stanie Bezczynności, Ataku lub Umierania.

Jeśli masz wystarczająco abstrakcyjną maszynę stanów skończonych, możesz jej ponownie użyć zarówno dla obiektu gry, jak i swojej sztucznej inteligencji; nagle nie inwestujesz dużo wysiłku w stan Gry - zamiast tego ponownie używasz kodu, którego użyłeś.

Następuje bezwstydna samo-wtyczka: zaimplementowałem taką maszynę skończoną w mojej bibliotece gier Lua, MiddleClass (konkretnie dodatek o nazwie MindState). Oto, w jaki sposób robisz z tym grę .


0

Innym podejściem do tego jest zastosowanie koncepcji ze świata programowania funkcjonalnego zwanej Unią Dyskryminacyjną . Chociaż zwykle znajdują się one w językach FP, można je emulować za pomocą klas .

Zasadniczo Unia dyskryminowana to zawsze jeden z nprzypadków, a przechowywane dane mogą się różnić w zależności od przypadku.

Na przykład:

type GameState =
  | Menu of MenuState
  | Playing of SimulationState

Oto nasz GameStatetyp może być Menualbo Playing. Jeśli tak Menu, to będzie zawierać MenuStateobiekt. Jeśli tak Playing, to będzie zawierać SimulationStateobiekt.

Aby zaktualizować, będziemy matchna stanie i odpowiednio wywołać inną funkcję:

let update gameTime = 
  let nextState = 
    match gameState with
    | Menu menuState -> updateMenu gameTime menuState
    | Playing simulationState -> updateSimulation gameTime simulationState

  // Mutate the current state
  gameState <- nextState

I podobnie do renderowania:

let render gameTime = 
  let nextState = 
    match gameState with
    | Menu menuState -> renderMenu menuState
    | Playing simulationState -> renderSimulation simulationState

Jedną z zalet tego podejścia jest to, że można łatwiej obsługiwać różne stany (takie jak zasoby) bez globalizacji lub przekazywania obiektów „usługowych”.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.