Nigdy wcześniej tak naprawdę nie zajmowałem się programowaniem gier, dość proste pytanie.
Wyobraź sobie, że buduję grę Tetris, w której główna pętla wygląda mniej więcej tak.
for every frame
handle input
if it's time to make the current block move down a row
if we can move the block
move the block
else
remove all complete rows
move rows down so there are no gaps
if we can spawn a new block
spawn a new current block
else
game over
Jak do tej pory wszystko w grze dzieje się natychmiast - rzeczy są odradzane natychmiast, rzędy są usuwane natychmiast itp. Ale co, jeśli nie chcę, aby coś się stało natychmiast (tj. Animacja)?
for every frame
handle input
if it's time to make the current block move down a row
if we can move the block
move the block
else
?? animate complete rows disappearing (somehow, wait over multiple frames until the animation is done)
?? animate rows moving downwards (and again, wait over multiple frames)
if we can spawn a new block
spawn a new current block
else
game over
W moim klonie Pong nie było to problemem, ponieważ każdą klatkę po prostu poruszałem piłką i sprawdzałem kolizje.
Jak mogę owinąć głowę tym problemem? Z pewnością większość gier wymaga akcji wymagającej więcej niż klatki, a inne rzeczy zatrzymują się do momentu wykonania akcji.
Action
klasę i kolejkę działań do wykonania. Po zakończeniu akcji usuń ją z kolejki i wykonaj następną akcję itp. O wiele bardziej elastyczna niż automat stanów.Biorę to z Game Coding Complete autorstwa Mike'a McShaffry'ego.
Mówi o „menedżerze procesów”, który sprowadza się do listy zadań, które należy wykonać. Na przykład proces kontrolowałby animację rysowania miecza (AnimProcess), otwierania drzwi lub, w twoim przypadku, powodowania zniknięcia rzędu.
Proces zostałby dodany do listy menedżera procesów, która byłaby iterowana w każdej ramce i wywołanej Update () dla każdej z nich. Tak bardzo podobne byty, ale do działań. Po zakończeniu tej operacji pojawi się flaga „zabicia”.
Inną fajną rzeczą w nich jest to, w jaki sposób mogą się połączyć, mając wskaźnik do następnego procesu. W ten sposób animowany proces wiersza może faktycznie składać się z:
(Ponieważ procesy mogą być jednorazowe, warunkowo tam lub tam przez X czasu)
Jeśli chcesz więcej szczegółów, zapytaj.
źródło
Możesz użyć priorytetowej kolejki działań. Wrzucasz akcję i czas. W każdej klatce dostajesz czas i odsuwasz wszystkie akcje, które mają określony czas jak poprzednio, i je wykonujesz. Bonus: Podejdź ładnie do paraleli, a tak naprawdę możesz zaimplementować prawie całą logikę gry.
źródło
Zawsze musisz znać różnicę czasu między poprzednią i bieżącą ramką, a następnie musisz zrobić dwie rzeczy.
- Zdecyduj, kiedy zaktualizować swój model: np. w tetris, gdy zaczyna się usuwanie wiersza, nie chcesz, aby rzeczy już kolidowały z wierszem, więc usuwasz wiersz z „modelu” aplikacji.
-Musisz następnie obsłużyć obiekt będący w stanie przejściowym do osobnej klasy, która rozwiąże animację / zdarzenie w pewnym okresie czasu. W przykładzie tetris wiersz powoli zanikałby (nieco zmieniaj nieprzezroczystość każdej klatki). Po nieprzezroczystości wynoszącej 0 przenosisz wszystkie bloki na rząd wiersza jeden w dół.
Na początku może się to wydawać nieco skomplikowane, ale zrozumiesz to, po prostu upewnij się, że dużo streszczasz w różnych klasach, to ułatwi ci to. Upewnij się także, że zdarzenia, które wymagają czasu, takie jak usunięcie wiersza w tetris, są tego rodzaju „Fire and Forget”, po prostu stwórz nowy obiekt, który obsługuje wszystko, co należy zrobić automatycznie, a gdy wszystko jest zrobione, usuwa się ze scenariusza.
źródło
Musisz myśleć o grze jako o „skończonej maszynie stanów”. Gra może być w jednym z kilku stanów: w twoim przypadku „oczekuje wejścia”, „kawałek przesuwa się w dół”, „eksploduje rząd”.
Robisz różne rzeczy w zależności od stanu. Na przykład podczas „przesuwania elementu w dół” ignorujesz dane gracza i zamiast tego animujesz kawałek z bieżącego wiersza do następnego. Coś takiego:
źródło