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 kenney.nl. 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.06.2.162 • 2024.6.1.208
wydana  2 dni temu
LTS
2022.0.2.51 • 2022.0.2.49
wydana 274 dni temu
Beta
2024.600.0.585 • 2024.600.0.609
wydana 20 dni temu
= IDE, = Runtime
Użytkownicy online
2 użytkowników aktywnych:
gości: 1, userów: 1
 Chell
(~ostatnie 15 minut)
Discord
34 użytkownicy online na discordzie:
Kysiu, s..., Alice, Nitro Slav, Carl-bot, LadyLush, debil debilowski, OdrzuconyKrakers, HappyOrange, fervi, Sevitaus, PhysX ᴺⱽᴵᴰᴵᴬ, lethian, Michał Parkoła, Draczeq, MKP (GEM), Arrekin, Dyno, 🆅🅸🆃🅾74🅼, LeD, 𝕳𝖚𝖌𝖔 𝕲𝖔𝖓𝖝𝖆𝖑𝖊𝖝, Miłosz, ArturG, m..., bagno, Tidżi, Danieo, g..., l..., Add92, Shockah, Cosplyfanka, exigo, PeekoHiko
Shoutbox
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
Wojo (09:40, 28.06.24)
Tymon jak co wizytę musiałem potwierdzić wiek
gnysek (14:15, 17.06.24)
Bo Łapusz woli alkohol, niż się organizować. Co tam Pixel Heaven, sprawdźcie jego zbiórki na książki...
Adriann (21:02, 13.06.24)
Bardzo słusznie, straszna patola z tą organizacją :D
I am Lord (08:35, 13.06.24)
Ale co jak co, zrobiło się o imprezie głośno.
Starsze wpisy znajdziesz w Archiwum.
Ankieta
Ile zarobiłeś do tej pory na grach stworzonych w GM?