Użytkownicy Makera nierzadko próbują urozmaicić swój projekt różnymi bardziej zaawansowanymi mechanikami. Jedną z bardziej popularnych jest implementacja pola widzenia wrogów w różnych formach. Niestety, w praktyce najczęściej okazuje się to być zbyt frustrujące dla wielu graczy.
Ale w czym problem?
Systemy pola widzenia w makerówkach okazują się aż nazbyt prymitywne. Pół biedy, jeśli chodzi tylko o potworki na mapie widzące w 360 stopniach, największą zmorą są sekcje skradankowe. Posłużę się przykładem – znaną wielu scenówką Spamthirowy Czołg autorstwa Ska’cia. Część graczy utknęła na dłuższą chwilę podczas minigry z kradnięciem paliwa: o ile można przeboleć nieznany zasięg widzenia strażnika, tak rentgen w jego oczach przyprawia o ból głowy. Pola, które widzi żołnierz, są ustawione „na sztywno” bez sprawdzania, czy między graczem a NPC jest jakaś ściana.
Co robić?
O ile takie podejście może się sprawdzić, kiedy zasięg widzenia jest mały, tak przy większych rozmiarach staje się to karkołomne. Na pewno da się to zrobić jakoś łatwiej, prawda? Dajmy na to taką sytuację:
Pomyślmy — w jaki sposób sprawdzić, czy między eventem a graczem znajduje się przeszkoda? Najprościej byłoby poprowadzić promień (ang. raycast) od eventu do gracza i sprawdzić, czy na jej drodze nie stoi ściana. Tylko jak to zrobić? Iść piksel po pikselu? Można spróbować — jeśli gracz stoi na tych samych koordynatach X lub Y ekranu co event to sprawa jest prosta, ale gdy jest inaczej to będziemy potrzebować kąta pod jakim poprowadzony jest promień.
A skąd kąt? Z funkcji trygonometrycznych… i w tym momencie użytkownicy 2k/2k3 (ci bez Maniacs Patcha) mogliby obejść się ze smakiem. Ale to nie jedyna wada tego podejścia, aby móc dokładnie odwzorować pole widzenia i nie przecinać rogów, promień musi stawiać odpowiednio małe kroki, z kolei im mniejsze te kroki tym więcej operacji musimy wykonać w ciągu jednej klatki. W przypadku wielu przeciwników rysujących linie w ten sposób nawet nowsze makery mogłyby dostać zadyszki, w końcu nie jest to silnik nastawiony na największą wydajność. Gdy wszystko wydaje się stracone, z pomocą przychodzi…
Algorytm Bresenhama
Metoda starsza od prawdopodobnie kogokolwiek zainteresowanego RPG Makerem, ale wciąż niesamowicie przydatna. Jej siła leży w prostocie: wystarczy możliwość porównania, dodawania i odejmowania dwóch liczb, a na dodatek nie trzeba uciekać się do liczb zmiennoprzecinkowych, co jest koniecznością, jeśli używamy funkcji trygonometrycznych. Pozwoli to operować na zwykłych koordynatach X/Y kafelków mapy zamiast ekranu, co znacznie zmniejsza ilość operacji dokonywanych na jedną klatkę.
Wróćmy do przykładu. Chcemy poprowadzony promień przerobić na ciąg kafelków, przez które przechodzi. Łatwo zauważyć, że w tym w przypadku zawsze stawiamy krok w lewo i jedynie czasem dodatkowo w dół. Funkcja sprawdzania ID terenu pozwoli stwierdzić, czy na drodze stoi ściana. Prawie się udało, tylko jak ustalić, w którym momencie pójść w dół?
Pora na trochę matematyki. Skoro znamy współrzędne dwóch punktów (eventu i gracza), to łatwo możemy wyprowadzić wzór na prostą przechodzącą przez te punkty. Dla uproszczenia załóżmy, że współczynnik kierunkowy znajduje się w przedziale
Stawiamy jeden krok w poziomie. Wtedy otrzymujemy:
Co oznacza, że przy stawianiu jednego kroku w poziomie stawiamy
Zatem poustawiajmy kilka zmiennych i główną pętlę.
Niestety, już widać pierwszy problem – współczynnik a rzadko kiedy będzie wartością całkowitą i nie będziemy mogli sprawdzić pola o koordynatach np.
Ale, ale, Axer, przecież miało nie być liczb zmiennoprzecinkowych! I faktycznie ich nie będzie — wystarczy przemnożyć wartości związane z błędem przez
Nadal pozostaje problem niecałkowitego
Uff, czy to już wszystko? Nie do końca — tak jak przyjęliśmy na początku, skrypt działa dopiero wtedy, kiedy
Okej, ale co jeśli
Po odpaleniu okazuje się, że nadal coś nie gra. Powodów jest kilka:
- SprawdzaneX i SprawdzaneY są zawsze inkrementowane, nawet jeśli którakolwiek z delt jest ujemna
- delta symbolizuje dystans, powinniśmy zatem używać wartości bezwzględnych, w końcu odległość nie może być ujemna!
Zatem tworzymy dwa dodatkowe warunki: Jeśli DeltaX < 0 i Jeśli DeltaY < 0, w których przemnażamy odpowiednią detlę przez
Zasięg widzenia
Skrypt już jest gotowy, ale przydałoby mu się jeszcze kilka szlifów. Jeśli chcemy, przykładowo, żeby nasz gracz był mniej zauważalny, możemy ograniczyć dystans, z którego strażnik może nas zauważyć. W tym przypadku zastosujemy znane wszystkim twierdzenie Pitagorasa. Jako że nie mamy dostępu do operacji pierwiastkowania, zasięg widzenia podajemy do kwadratu, np. jeśli chcemy, żeby dystans wynosił 5 kratek w linii prostej, przygotowujemy zmienną o wartości 25, jeśli 6 kratek, to 36, etc. Po modyfikacji początek skryptu powinien wyglądać mniej więcej tak:
Ograniczanie kąta widzenia
Jak na razie nasz strażnik ma oczy dookoła głowy. Jeśli nie odpowiada nam takie rozwiązanie, można ograniczyć kąt jego widzenia bardzo prostym sposobem. Wymagane jest jedynie zwykłe sprawdzanie znaku delty w zależności od kierunku, w który patrzy event. Przykładowo, jeśli wiemy, że strażnik patrzy w dół i znajdujemy się poniżej niego, to wystarczy, że przed uzyskaniem wartości bezwzględnej sprawdzimy czy
Aby uzyskać inny kąt, trzeba poeksperymentować z wartościami bezwzględnymi delt. Poniżej jedno z przykładowych ustawień.
Voilà! Nasz strażnik jest gotowy do obserwowania i można go powielać metodą kopiuj-wklej w dowolnych ilościach. Poniżej udostępniam przykładowy projekt opatrzony komentarzami, na wypadek problemów w reprodukowaniu tutoriala.
Axer
Cholernie zaawansowany poradnik. Dobrze, że takie rzeczy pojawiają się na stronie! Pomoże to wielu osobom.