Poruszanie klawiaturą - top down
Czwartek, 05 Października 2023, 18:22
Czas czytania 4 minuty, 56 sekund
Zgodne z GM:
Przykłady najprostszego sterowania w grze.
W tym kursie chciałbym wam przedstawić różne podejścia do sterowania postacią w grze typu top-down (z widokiem z góry).
Stwórzcie nowy projekt, a w nim dwa sprite'y, o rozmiarach 32x32. Ja skorzystałem z gotowej paczki z [url=kenney.nl/.../url]. Jeśli używacie grafik w innym rozmiarze, warto je przeskalować - założeniem tego artykułu jest korzystanie z domyślnej gamemakerowej siatki 32x32 do ustawiania obiektów, gdyż jest to też artykuł wyjściowy dla kolejnego wpisu, dotyczącego wyrównywania do siatki.
Tworzymy dwa obiekty:
-
-
W naszej grze chcemy umożliwić ruch w poziomie i w pionie, ale jeśli gracz zmienia oba kierunki, dopuszczamy ruch po skosie - który będzie po prostu sumą obu przesunięć.
Jest wiele sposobów na to, aby sprawdzić, w którą stronę porusza się gracz. Sporo osób sprawdza po kolei każdy z klawiszy góra/dół/lewo/prawo i tworzy odpowiednie warunki dla każdego z nich. Nie bez powodu wspomniałem jednak o poruszaniu w pionie i w poziomie, gdyż pozwala to na pewne uproszczenie kodu.
Wiemy bowiem, że poruszając się w poziomie, poruszamy się na osi x - w lewo odejmujemy od obecnej pozycji, a w prawo dodajemy. Nie ważna jaka będzie prędkość postaci, możemy użyć uogólnienia, że ruch w lewo to ruch ujemny, a ruch w prawo - dodatni. Jeśli więc nasza postać porusza się z prędkością A, to w lewo poruszy się z prędkością
Ponieważ funkcje sprawdzające, czy klawisz jest wciśnięty zwracają wartość true/false (inaczej 1/0), możemy skorzystać z matematyki, aby połączyć tę wcześniejszą wiedzę. Możemy bowiem sprawdzenie tego, czy klawisz w lewo i w prawo są wciśnięte przemnożyć przez liczby -1 i 1. Dzięki temu:
- jeśli nie jest wciśnięty żaden przycisk, otrzymamy 0
- jeśli wciskamy "lewo", otrzymamy -1
- jeśli wciskamy "prawo", otrzymamy 1
- jeśli wciskamy na raz lewo+prawo, otrzymamy... 0 (bo -1 + 1 = 0) i postać nie ruszy się.
Do sprawdzenia, czy przycisk został wciśnięty, służy funkcja
Wskazówka:
Dodajemy event
kodvar hor = -keyboard_check(vk_left) + keyboard_check(vk_right);
var ver = -keyboard_check(vk_up) + keyboard_check(vk_down);
Teraz w zmiennej tymczasowej "hor" mamy informację o tym, czy powinien nastąpić ruch poziomy (horyzontalny), a "ver", czy pionowy (vertical).
Chcielibyśmy jednak, aby nasza postać poruszała się szybciej, niż 1/-1 piksel na klatkę obrazu.
Dodajemy więc nową zmienną, spd, oraz przemnażamy przez nią wcześniejsze wartości:
kodvar sp = 3;
hor *= sp;
ver *= sp
Dzięki temu wiemy już, ile nasza postać mogłaby ruszyć się w tej klatce obrazu w pionie i w poziomie.
Trzeba jednak sprawdzić, czy nie zachodzi kolizja. GM ma wbudowaną bardzo prostą funkcję, która pozwala sprawdzić, czy gdyby nasz obiekt przesunął się na daną pozycję, nie zachodzi kolizja z obiektem z zaznaczoną flagą solid. Ta funkcja to
Wskazówka:
- funkcje z prefixem position_ sprawdzają, czy na pikselu na pozycji x,y nie zachodzi kolizja (uwzględniając maski obiektów na pozycji x,y)
- funkcje z prefixem place_ sprawdzają, czy nie zachodzi kolizja, gdyby obecny obiekt przesunął się na pozycję x,y (dokładniej - jego maska).
Różnica polega na tym, że gdy bierzemy pod uwagę całą maskę, pod uwagę brane są wszystkie przykryte piksele, a nie tylko 1x1.
- funkcje z sufiksem _free sprawdzają kolizje z obiektami solid, a _empty sprawdzają z każdym.
Sprawdzamy więc, czy można poruszyć się pionowo i osobno czy poziomo (nie wstawiamy tutaj słowa
kod if place_free(x+hor, y) {
x += hor;
}
if place_free(x, y+ver) {
y += ver;
}
To wszystko. Pierwszy warunek sprawdza czy możliwy jest ruch poziomo o tyle pikseli ile wynosi nasz
GM oferuje też inne sposoby na taki ruch. Jedną z funkcji dodanych w 2023 roku jest
Wystarczy zamienić oba warunki "if place free" na:
kodmove_and_collide(hor * sp, ver * sp, obj_wall);i uzyskamy dokładnie taki sam rodzaj ruchu.
Wskazówka:
Jeśli chcemy więcej niż jeden typ obiektu który jest przeszkodą, wystarczy stworzyć obiekt "rodzica" (jeśli chcemy go używać w roomie, musi mieć sprite i zaznaczoną flagę solid), a potem każdy inny obiekt z którym też ma zachodzić kolizja, ustawić jako jego rodzic (parent). Sprawdzanie kolizji z "rodzicem" będzie zwracać też kolizję dla "dzieci" (o ile mają ustawioną flagę solid, oraz ustawiony sprite).
Teraz wystarczy dodać 1 instancję obiektu gracza w room editorze, oraz kilka "ścian", np. tak:
Proste sterowanie z góry działa :)
Stwórzcie nowy projekt, a w nim dwa sprite'y, o rozmiarach 32x32. Ja skorzystałem z gotowej paczki z [url=kenney.nl/.../url]. Jeśli używacie grafik w innym rozmiarze, warto je przeskalować - założeniem tego artykułu jest korzystanie z domyślnej gamemakerowej siatki 32x32 do ustawiania obiektów, gdyż jest to też artykuł wyjściowy dla kolejnego wpisu, dotyczącego wyrównywania do siatki.
Tworzymy dwa obiekty:
-
obj_player
-
obj_wall
, któremu zaznaczamy "solid".W naszej grze chcemy umożliwić ruch w poziomie i w pionie, ale jeśli gracz zmienia oba kierunki, dopuszczamy ruch po skosie - który będzie po prostu sumą obu przesunięć.
Jest wiele sposobów na to, aby sprawdzić, w którą stronę porusza się gracz. Sporo osób sprawdza po kolei każdy z klawiszy góra/dół/lewo/prawo i tworzy odpowiednie warunki dla każdego z nich. Nie bez powodu wspomniałem jednak o poruszaniu w pionie i w poziomie, gdyż pozwala to na pewne uproszczenie kodu.
Wiemy bowiem, że poruszając się w poziomie, poruszamy się na osi x - w lewo odejmujemy od obecnej pozycji, a w prawo dodajemy. Nie ważna jaka będzie prędkość postaci, możemy użyć uogólnienia, że ruch w lewo to ruch ujemny, a ruch w prawo - dodatni. Jeśli więc nasza postać porusza się z prędkością A, to w lewo poruszy się z prędkością
A * -1
, a w prawo z prędkością A
(lub... A*1
).Ponieważ funkcje sprawdzające, czy klawisz jest wciśnięty zwracają wartość true/false (inaczej 1/0), możemy skorzystać z matematyki, aby połączyć tę wcześniejszą wiedzę. Możemy bowiem sprawdzenie tego, czy klawisz w lewo i w prawo są wciśnięte przemnożyć przez liczby -1 i 1. Dzięki temu:
- jeśli nie jest wciśnięty żaden przycisk, otrzymamy 0
- jeśli wciskamy "lewo", otrzymamy -1
- jeśli wciskamy "prawo", otrzymamy 1
- jeśli wciskamy na raz lewo+prawo, otrzymamy... 0 (bo -1 + 1 = 0) i postać nie ruszy się.
Do sprawdzenia, czy przycisk został wciśnięty, służy funkcja
keyboard_check()
.Wskazówka:
keyboard_check_pressed()
pozwala sprawdzić, czy w obecnej klatce nastąpiło pierwsze wciśnięcie klawisza (tzn. przejście ze stanu niewciśniętego do wciśniętego), a keyboard_check_released()
czy klawisz został zwolniony (czyli na odwrót). keyboard_check()
zwraca true/1 tak długo, jak klawisz jest przytrzymywany.Dodajemy event
step
w obj_player.kodvar hor = -keyboard_check(vk_left) + keyboard_check(vk_right);
var ver = -keyboard_check(vk_up) + keyboard_check(vk_down);
Teraz w zmiennej tymczasowej "hor" mamy informację o tym, czy powinien nastąpić ruch poziomy (horyzontalny), a "ver", czy pionowy (vertical).
Chcielibyśmy jednak, aby nasza postać poruszała się szybciej, niż 1/-1 piksel na klatkę obrazu.
Dodajemy więc nową zmienną, spd, oraz przemnażamy przez nią wcześniejsze wartości:
kodvar sp = 3;
hor *= sp;
ver *= sp
Dzięki temu wiemy już, ile nasza postać mogłaby ruszyć się w tej klatce obrazu w pionie i w poziomie.
Trzeba jednak sprawdzić, czy nie zachodzi kolizja. GM ma wbudowaną bardzo prostą funkcję, która pozwala sprawdzić, czy gdyby nasz obiekt przesunął się na daną pozycję, nie zachodzi kolizja z obiektem z zaznaczoną flagą solid. Ta funkcja to
place_free
.Wskazówka:
- funkcje z prefixem position_ sprawdzają, czy na pikselu na pozycji x,y nie zachodzi kolizja (uwzględniając maski obiektów na pozycji x,y)
- funkcje z prefixem place_ sprawdzają, czy nie zachodzi kolizja, gdyby obecny obiekt przesunął się na pozycję x,y (dokładniej - jego maska).
Różnica polega na tym, że gdy bierzemy pod uwagę całą maskę, pod uwagę brane są wszystkie przykryte piksele, a nie tylko 1x1.
- funkcje z sufiksem _free sprawdzają kolizje z obiektami solid, a _empty sprawdzają z każdym.
Sprawdzamy więc, czy można poruszyć się pionowo i osobno czy poziomo (nie wstawiamy tutaj słowa
else
, gdyż niemożliwość ruchu w jednej płaszczyźnie, nie wyklucza ruchu w drugiej; dodatkowo brak else pozwala poruszać się po skosie).kod if place_free(x+hor, y) {
x += hor;
}
if place_free(x, y+ver) {
y += ver;
}
To wszystko. Pierwszy warunek sprawdza czy możliwy jest ruch poziomo o tyle pikseli ile wynosi nasz
spd
(wartość będzie ujemna jeśli w lewo, dodatnia jeśli w prawo). Podobnie w pionie (ujemna w górę, dodatnia w dół).GM oferuje też inne sposoby na taki ruch. Jedną z funkcji dodanych w 2023 roku jest
move_and_collide
.Wystarczy zamienić oba warunki "if place free" na:
kodmove_and_collide(hor * sp, ver * sp, obj_wall);i uzyskamy dokładnie taki sam rodzaj ruchu.
Wskazówka:
Jeśli chcemy więcej niż jeden typ obiektu który jest przeszkodą, wystarczy stworzyć obiekt "rodzica" (jeśli chcemy go używać w roomie, musi mieć sprite i zaznaczoną flagę solid), a potem każdy inny obiekt z którym też ma zachodzić kolizja, ustawić jako jego rodzic (parent). Sprawdzanie kolizji z "rodzicem" będzie zwracać też kolizję dla "dzieci" (o ile mają ustawioną flagę solid, oraz ustawiony sprite).
Teraz wystarczy dodać 1 instancję obiektu gracza w room editorze, oraz kilka "ścian", np. tak:
Proste sterowanie z góry działa :)