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 34 dni temu
LTS
2022.0.2.51 • 2022.0.2.49
wydana 363 dni temu
Beta
2024.1100.0.634 •
2024.1100.0.658
 0.13.0

wydana 11 dni temu
= IDE, = Runtime, = GMRT
Użytkownicy online
1 użytkownik aktywny:
gości: 1,
(~ostatnie 15 minut)
Discord
22 użytkownicy online na discordzie:
Carl-bot, EchoDuck, GibkiKaktus, lethian, Kowu, Kuzyn, GMRussell, HappyOrange, Tival, r..., Arrekin, yazaa, Domeen0, Dyno, Deusald, szmalu, 🧁Cupcake🧁, Draczeq, Sporek, RuLing, l..., xVANiLL
Shoutbox
Wojo (15:38, 05.09.24)
Ciekawe
gnysek (11:54, 14.08.24)
Ruszyła beta nowego runtime, a stary dostanie już tylko dwa ficzery (UI Layery i obsługę SVG jako vertexy).
Wojo (11:51, 14.08.24)
Co się stało?
gnysek (18:31, 25.07.24)
Ogłaszam nowy etap w historii GameMakera.
gnysek (11:36, 08.07.24)
Ale w sumie taki numer GG był bezpieczniejszy niż nr. telefonu czy kontakt społecznościowy. Utrudniał stalkowanie i ułatwiał banowanie.
Wojo (08:08, 08.07.24)
Niestety to już nie te czasy kiedy pytało się kasjerki o wiek i numer Gadu-Gadu...
Adriann (08:28, 05.07.24)
Albo okraść :|
Adriann (08:28, 05.07.24)
Może pani chciała zobaczyć twoje dane i Cię poderwać :d
gnysek (10:38, 03.07.24)
Mnie ostatnio w Żabce zapytali o wiek. A mam już ponad dwie osiemnastki.
Wojo (08:27, 30.06.24)
Ogólnie to miał być żart ponieważ portal internetowy, którego można opisać jako PH jest portalem przeznaczonym dla dorosłych. Miało być śmiesznie wyszło żenująco, a wiadomości w shoutboxie nie mogę skasować :P
Starsze wpisy znajdziesz w Archiwum.
Ankieta
Ile zarobiłeś do tej pory na grach stworzonych w GM?