Zasadniczo w każdej grze, którą do tej pory stworzyłem, zawsze mam zmienną, taką jak „aktualny stan”, która może być „grą”, „ekranem tytułów”, „ekranem gry” itp.
A potem na mojej funkcji aktualizacji mam ogromny:
if current_state == "game"
game stuf
...
else if current_state == "titlescreen"
...
Nie wydaje mi się jednak, aby był to profesjonalny / czysty sposób radzenia sobie ze stanami. Wszelkie pomysły, jak to zrobić w lepszy sposób? Czy jest to standardowy sposób?
lua
architecture
love2d
David Gomes
źródło
źródło
Odpowiedzi:
Ponieważ mówisz o ekranach, uważam, że najlepiej jest rozdzielić całą logikę na różne ekrany. Co zwykle robię:
Zdefiniuj interfejs o nazwie screen i zaimplementuj go na wielu ekranach. Podobnie jak LoadingScreen, MainMenuScreen, GameScreen, GameOverScreen, HighScoreScreen itp. W grze umieszczasz zmienną, która przechowuje bieżący ekran. W każdej pętli wywołujesz screen.update () i renderujesz bieżący ekran. Zaoszczędzi ci to dużo „jeśli ten stan to zrobi”, ponieważ stan jest określony przez bieżący ekran.
To bardzo ładnie oddzieli Twoją logikę.
Przykładowy kod:
Lub w zależności od konfiguracji gry, być może masz nieskończoną pętlę jako grę.
źródło
Jeśli już używasz klasy Middleclass, istnieje znakomita biblioteka automatów stanów, która nazywa się Statefull . Jest łatwy w użyciu i zawiera te same pomysły, które zaproponował Matsemann.
źródło
Jeśli twoja
current_state
zmienna jest łańcuchem, to jest to bardzo łatwe w Lua:źródło
To, co robię, jest z grubsza następujące:
Mam ukierunkowaną strukturę danych wykresu acyklicznego , która jest w zasadzie tylko grupą węzłów, które wskazują na siebie. Każdy węzeł reprezentuje system gry. np. interfejs użytkownika, świat, dane wejściowe, rendering. I każdy węzeł wskazuje na inne węzły, które pojawiają się przed nim lub po nim. Po umieszczeniu wszystkich węzłów łatwo jest spłaszczyć je na prostej liście. Konfigurowanie tego DAG to pierwsza rzecz, którą robię podczas uruchamiania gry. Za każdym razem, gdy chcę dodać nowy system, powiedzmy AI, mogę po prostu napisać ten kod, a następnie powiedzieć mojej grze, od czego zależy i od czego powinien zależeć.
Moja główna pętla gry pojawia się później i po prostu uruchamia kolejno każdy system. Obsługiwane są pierwsze dane wejściowe, później aktualizacje świata, a następnie inne rzeczy ... Interfejs użytkownika jest na końcu, a renderowanie jest ostatnie. Gdy gra zaczyna się po raz pierwszy, nie ma świata, fizyki ani sztucznej inteligencji, więc te kroki są w zasadzie pomijane i wyświetla się tylko ekran tytułowy. Po uruchomieniu właściwej gry interfejs użytkownika wysyła komunikat do systemu światowego, aby się włączył, a on sam się o to zadba. Zarządzanie stanem gry oznacza po prostu włączanie i wyłączanie różnych systemów. Każdy system ma swój własny zestaw informacji o stanie, który jest obsługiwany mniej lub bardziej niezależnie od wszystkich innych (to nie jest całkowicieto prawda, że wiele systemów działa na tym samym zestawie danych - na przykład system interfejsu użytkownika pobiera dane ze świata, aby na przykład wyświetlać informacje. System AI musi także patrzeć i wysyłać wiadomości do podmiotów na świecie).
źródło
Oto jak organizuję swoje stany w Lua + Love2d. Pozwala to uniknąć długich instrukcji if / then.
Najpierw tworzę podstawową klasę zawierającą metody update (dt) i render (). Możesz także nadać mu metody obsługi zdarzeń, takie jak onKeyDown (klucz). Nazywam tę klasę Stage, ale każdy obiekt implementujący metody będzie działał. Następnie tworzę instancję tej klasy dla każdego stanu gry, wdrażając niezbędne metody. Następnie tworzę tabelę kluczy / wartości z nazwą stanu i jego instancją. Następnie śledź bieżący stan w zasięgu globalnym, aby stany mogły go zmienić, gdy spełniony zostanie określony warunek.
źródło
Cóż, chociaż nie jest to całkiem w porządku, obsługa stanów w ten sposób, IMO. Możesz uczynić go o wiele czystszym, używając funkcji dla każdego stanu, takich jak:
czy coś innego przeszkadza ci w tym podejściu (mam na myśli, że metoda aktualizacji jest bardzo długa)?
źródło