Poruszanie klawiaturą - top down

Czwartek, 05 Października 2023, 18:22
Czas czytania 4 minuty, 56 sekund
Zgodne z GM: gms2 gms1
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:
- obj_player
- obj_wall, któremu zaznaczamy "solid".

Grafika: /upload/ajax/20231005_9c8a01d98d249e60d170533911a27b1d.png

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:

Grafika: /upload/ajax/20231005_8cb247f169b68c406fe86f9904f8ea10.png

Proste sterowanie z góry działa :)
Komentarze (łącznie 0):
Nie ma jeszcze żadnego komentarza. Czas to zmienić

Najnowsze wersje GameMakera:

Stabilna
2024.8.1.171 • 2024.8.1.218
wydana 72 dni temu
LTS
2022.0.2.51 • 2022.0.2.49
wydana 401 dni temu
Beta
2024.1100.0.686 •
2024.1100.0.707
 0.13.0

wydana  6 dni temu
= IDE, = Runtime, = GMRT
Użytkownicy online
1 użytkownik aktywny:
gości: 1,
(~ostatnie 15 minut)
Discord
Shoutbox
gnysek (11:46, 17.11.24)
Witamy, witamy!
baca (12:22, 16.11.24)
To już 25 lat.. Witam po paru latach nieobecności.
gnysek (11:05, 15.11.24)
Natomiast obecne forum istnieje od 2004, jak z iglu.cz na gmclan.org przeszliśmy i od tego czasu nie było resetów danych.
gnysek (12:35, 13.11.24)
Ogólnie GMCLAN istnieje 22 lata, ale na to trofeum nie zrobiłem (jeszcze xD)
Chell (20:41, 08.11.24)
wow, ta emotka w ogóle nie wygląda jak : O xD
Chell (20:40, 08.11.24)
tylko? :O 4tk ma 15
Borek (18:12, 07.11.24)
Właśnie dostałem powiadomienie z forum, że jestem na GMClanie 18 lat :D Ja pierdzielę...
S
Sutikku (08:43, 18.10.24)
TIL, gamemaker jest starszy ode mnie
gnysek (16:04, 15.10.24)
Za równo miesiąc, GameMaker kończy 25 lat.
Wojo (15:38, 05.09.24)
Ciekawe
Starsze wpisy znajdziesz w Archiwum.
Ankieta
Ile zarobiłeś do tej pory na grach stworzonych w GM?