Spis treści
Maniacs Patch w sposób trudny do przecenienia ułatwił korzystanie z myszy w RPG Makerze 2003. Kilka nowych komend i mechanik sprawiło, że nasz projekt dość łatwo może zostać uwolniony z uciskających go ram przycisków na klawiaturze (i padzie) oraz przesuwania ekranu co 16 pikseli. W dzisiejszym poradniku przedstawię kilka sposobów na wykorzystanie myszy w starym, poczciwym RM2k3.
Pokazujemy kursor
Zaczynamy od rzeczy absolutnie podstawowej – pokazania kursora myszy w naszym projekcie. Kwestia ta została już wytłumaczona przez Soula, ja ją tylko zobrazuję konkretnym przykładem.
Najpierw importujemy do naszego projektu obrazek z kursorem. Ja pożyczyłem sobie grafikę z Kinskiego, mam nadzieję, że Deathwing mnie za to nie pozwie:
Cały kod na pokazanie kursora prezentuje się następująco:
Wszystko umieszczamy w common evencie ustawionym na Parallel Process (dzięki temu skrypt będzie sczytywać położenie kursora w czasie rzeczywistym. Przy pomocy maniacowej komendy Get Mouse Position (ostatnia strona komend) zapisujemy X oraz Y kursora do dwóch wybranych zmiennych. W zasadzie to by było wszystko – przy pomocy Show Picture i posiadanych współrzędnych możemy już pokazać kursor.
Dociekliwi makerowcy pamiętają jednak, że współrzędne obrazka wskazane w komendzie pokazują jego środek, co przy kursorze może stanowić problem. Nasza grafika ma wymiary 12×16, dlatego przy pomocy Control Variables „przesuwamy” obrazek o 6 pikseli w prawo i 8 w dół. Gdy teraz odpalicie projekt zobaczycie ładnie poruszający się kursor bez żadnych lagów!
Przewijanie mapy przy pomocy kursora
Tym razem coś bardziej skomplikowanego i, w pewnych momentach, mocno nieintuicyjnego – przewijanie ekranu gry przy pomocy myszy. Na początku stwórzmy sobie nieco urozmaiconą mapę o rozmiarze 40×40 pól, ustawiając gdzieś po środku bohatera.
Na krańcach mapy znajdują się cztery eventy, które są kluczowe dla naszego skryptu – 1 to event góra, 2 event dół, 3 event lewo, a 4 event prawo. Muszą znajdować się na samym krańcu mapy, ale nie ma znaczenia, na którym konkretnie polu.
Teraz musimy stworzyć common event z Triggerem na None, który będzie sprawdzał Współrzędną X względem ekranu lewego i prawego eventu oraz współrzędną Y względem ekranu górnego i dolnego. To prosty kod:
Czemu w ogóle mamy sprawdzać te wartości? Ponieważ zaproponowana przeze mnie dalej metoda zawiera jeden podstawowy mankament – gdy mapa dojedzie do końca, a my dalej trzymamy na krawędzi kursor, nic się już nie przesuwa, ale we współrzędnych zaczyna się bajzel.
Dla ułatwienia przyjmijmy, że ekran będzie się przesuwał, gdy kursor znajdzie się w odległości 16 pikseli lub mniej od krawędzi, czyli 1 pola. Nasz skrypt podzielimy sobie na 8 części zgodnie z poniższym rozróżnieniem:
Dla każdej białej krawędzi oraz czerwonego narożnika stworzymy odrębny kod. Zanim jednak do tego przejdziemy, sprawdźmy, jak w ogóle przesuwać ekran po pikselach, a nie polach.
Jeśli zaopatrzyliście się w TPC, o którym pisałem w ostatniej części tego poradnika, spójrzcie jeszcze do części 4 napisanej przez Axera. By przesunąć ekran w pożądany przez nas sposób musimy wprowadzić za pomocą TPC komendę:
@scr.scroll .pxShift X, Y .speed Z
X to liczba pikseli przesuwanych w poziomie, Y to liczba pikseli przesuwanych w pionie, a Z to szybkość przesuwania. Nic bardziej banalnego, prawda?
Tworzymy nowego common eventa ustawionego na Parallel Process, jako pierwszą komendę ustawiamy znane nam już Get Mouse Position, a następnie wywołujemy wcześniej przygotowany common event sprawdzający współrzędne czterech eventów na mapie.
Cały kod dotyczący przesuwania ekranu będzie znajdował się w tym jednym common evencie.
Przesuwanie w podstawowych kierunkach
Przesuwanie w podstawowych kierunkach (góra, dół, lewo, prawo) jest dość proste. Spójrzmy na ten kod:
Wykonujemy tutaj pięć rzeczy:
- w pierwszym warunku sprawdzamy, czy nasz kursor znajduje się na najwyższym polu ekranu (czyli na górnej, białej belce);
- w drugim warunku sprawdzamy, czy kursor znajduje się z prawej strony górnego lewego narożnika;
- w trzecim warunku sprawdzamy, czy kursor znajduje się z lewej strony górnego prawego narożnika;
- w czwartym warunku sprawdzamy, czy współrzędna Y względem ekranu górnego eventa z mapy nie jest równa 16. Dlaczego to robimy? Ponieważ jeśli Screen Y tego eventa będzie wynosić 16, dojedziemy tym samym do górnego końca mapy i nie powinniśmy dalej wywoływać komendy z przesuwaniem – inaczej nastąpi bajzel, o którym mówiłem;
- wstawiamy wspomnianą komendę z TPC, nie przesuwając ekranu w poziomie, a jedynie w pionie o 5 pikseli w górę (-5 oznacza tak naprawdę 5 w górę) – jako szybkość ustawiamy 1200 (to bardzo ważne, co wytłumaczę dalej).
Podsumowując, dzięki naszemu skryptowi przesuwamy ekran w górę tylko wtedy, gdy nasz kursor znajduje się przy górnej krawędzi ekranu, ale nie w narożnikach, i nie dojechaliśmy jeszcze do końca mapy. Jeśli nie jest to dla ciebie jasne, zatrzymaj się tutaj i spróbuj to jeszcze raz przetrawić – bez tej wiedzy dalsza część poradnika będzie jeszcze bardziej zagmatwana.
Skoro znamy już konstrukcję mojego rozwiązania, możemy przejść do pozostałych trzech kierunków.
Analogicznie do góry tworzymy dół. Pierwszy warunek sprawdza, czy kursor jest na najniższej linii ekranu (pamiętajcie, że w 2k3 podstawowa rozdzielczość to 320×240. A 240 – 16 to właśnie 224. Dwa kolejne warunki są takie same i sprawdzamy, czy kursor nie jest na narożniku. Następnie sprawdzamy, czy Screen Y dolnego eventu nie jest równe 240. Jeśli będzie, to znaczy że dojechaliśmy do samego dołu. Skąd wiemy, jaka wartość Screen Y eventa oznacza dojechanie to końca mapy? Można to wyliczyć, ale ja zawsze po prostu dojeżdżam do końca mapy i ręcznie sprawdzam, jaką wartość daje mi event. W komendzie z TPC usunęliśmy tylko minus przy cyfrze 5, dzięki czemu ekran będzie jechał w dół.
Przy ruchu w lewo sprawdzamy trzema warunkami, czy kursor znajduje się na lewej białej belce, a czwartym czy nie dojechaliśmy już do końca mapy. Z niezrozumiałych dla mnie powodów Screen X pierwszego zdarzenia od lewej jest równe 8, a Screeny Y pierwszego zdarzenia od góry wynosi 16. Czy ktoś wie, czemu tak się dzieje? Jeśli tak, napisz w komentarzu! Ostatnia kwestia to przesunięcie mapy wyłącznie w lewo (-5 w pierwszej wartości).
Jeśli prawidłowo przerobiliście dotychczasowe fragmenty, ruch w prawo powinien być jedynie formalnością:
Teraz czeka nas ta trudniejsza część.
Przesuwanie po skosie
Przesuwanie po skosie wykorzystuje wszystkie rozwiązania przesuwania w podstawowych kierunkach, ale jest nieco bardziej skomplikowane z uwagi na możliwość wystąpienia różnych sytuacji. A dokładnie mogą wystąpić cztery, które opiszę na przykładzie lewego górnego narożnika:
- ruch w lewo i w górę jest możliwy jednocześnie – mapa przesuwa się po skosie;
- ruch w lewo jest możliwy, ale w górę już nie – mapa przesuwa się tylko w lewo;
- ruch w lewo jest niemożliwy, ale można jeszcze przesuwać ekran w górę – mapa przesuwa się tylko w górę;
- dojechaliśmy do końca w obu kierunkach i mapy nie da się już bardziej przesunąć ani w lewo, ani w górę – mapa w ogóle się nie przesuwa.
Każdy z narożników wymaga odrębnego kodu. Dla opisywanego górnego lewego narożnika wygląda to tak:
Pierwsze dwa warunki sprawdzają, czy nasz kursor znajduje się w górnym lewym narożniku ekranu. Następnie sprawdzamy trzecim warunkiem, czy gracz dojechał już do górnej krawędzi mapy. Jeśli tak, sprawdzamy następnie, czy dojechał też do lewej krawędzi. W zależności od wyniku tego sprawdzenia przesuwamy ekran albo po skosie w górę i lewo, albo tylko w górę.
Jeśli z trzeciego warunku wyszło nam, że gracz dojechał już do górnej krawędzi mapy, musimy jeszcze sprawdzić, czy dojechał też do lewej. Jeśli nie, przesuwamy ekran wyłącznie w lewo. Jeśli nie możemy już przesuwać ekranu ani w górę, ani w lewo, ustawiamy opcje przesunięcia na 0 i 0 (program nie zawiera odrębnej komendy na zastopowanie przesuwania).
Wbrew początkowym obawom powyższe rozwiązanie jest proste i w miarę jasne. Na jego podstawie kodujemy pozostałe trzy narożniki, zmieniając jedynie zmienne i wartości:
Na sam koniec tego common eventa musimy wprowadzić następujące komendy.
Po co to robimy? Trzy puste Waity to mniej więcej szybkość przesuwania ekranu wskazana przez nas w komendzie TPC. Po nich musimy jeszcze unieruchomić ekran. Do tej pory taka komenda znajdowała się tylko w warunkach przy narożnikach. Jeśli tego nie zrobimy, ekran będzie przesuwał się dalej niezależnie od pozycji naszego kursora.
Uff, działające scrollowanie mapy przy pomocy myszki mamy już gotowe! Teraz czas na coś jeszcze bardziej szalonego.
Zaznaczanie pola na mapie kliknięciem
Pójdźmy o krok dalej w naszych zabawach z myszą i zakodujmy fragment, dzięki któremu będziemy mogli zaznaczać konkretną kratkę w siatce eventów. Największe wyzwanie z tym związane jest takie, że dzięki scrollowaniu po pikselach nasz ekran nie zawsze będzie pokazywał idealnie całe kratki, ale czasami będzie np. w połowie jednej kolumny. Skrypt musi sobie oczywiście z tym poradzić.
Do zaznaczania wykorzystamy taki prosty wskaźnik w formie picture o rozmiarach 16×16:
Zaczynamy od czegoś prostego, czyli bazy pod nasz skrypt:
W nowym common evencie, oczywiście ustawionym na Parallel Process, przy pomocy Key Input Processing przechwytujemy wciśnięcie lewego i prawego przycisku myszy. Ten ostatni zamyka nam grę, w tym pierwszym natomiast wykonujemy następujące operacje:
- usuwamy obrazek o numerze 100 (to on będzie stanowił wskaźnik);
- przechwytujemy pozycję myszy;
- wywołujemy common eventa odpowiedzialnego za obliczenie poziomej osi naszego obrazka;
- wywołujemy common eventa odpowiedzialnego za obliczenie pionowej osi naszego obrazka;
- wyświetlamy obrazek ze wskaźnikiem;
- odpalamy dźwięk kursora.
Założenia skryptu
Zanim przejdziemy dalej (a to „dalej” będzie zapewne mocno chaotyczne), przypomnijmy sobie kilka rzeczy:
- pola mapy numerowane są od 0, a nie 1, czyli pierwszy kafelek od lewej ma numer 0, drugi ma numer 1 itd.;
- to samo tyczy się numerowania od góry do dołu;
- rozdzielczość ekranu zawsze (przynajmniej w naszym skrypcie) wynosi 320×240, natomiast rozdzielczość całej mapy jest u nas dużo większa i wynosi dokładnie 640×640;
- pamiętacie te cztery eventy, które umieściliśmy na krańcach mapy? Będą nam cholernie potrzebne w tej części. Screen X pierwszego eventu od lewej wynosiło 8, a Screen Y pierwszego od góry 16.
Mój pomysł na skrypt jest taki:
- dzięki sprawdzeniu pozycji myszy podczas kliknięcia wiemy, jaki kafelek wskazuje ona na wyświetlonym fragmencie mapy;
- nie wiemy jednak, o ile pikseli widok jest przesunięty względem krawędzi, nie znamy zatem dokładnego numeru kafelka;
- znając wartość Screen X lewego eventa na mapie oraz wartość Screen Y górnego eventa na mapie możemy obliczyć, jak względem krawędzi przesunięty jest obraz na ekranie;
- znając przesunięcie, możemy wyliczyć, na jaki dokładnie kafelek mapy kliknięto (mamy jego pozycję na osi X i Y, ale nie w pikselach, tylko całych polach);
- mając X oraz Y kafelka liczone w polach, możemy wyświetlić nasz wskaźnik zakrywający dokładnie to pole niezależnie od tego, jak przesunięty jest obraz w pikselach.
Prościej się już chyba nie dało tego wytłumaczyć. Generalnie chodzi o zależność pomiędzy osią X i Y liczoną w pikselach wyświetlanych na ekranie, a osią X i Y kafelków na mapie liczoną bezwzględnie od krawędzi, niezależnie od tego, jakie obecnie mamy przesunięcie ekranu.
Szukamy pozycji X klikniętego pola
Najpierw zajmiemy się common eventem odpowiedzialnym za wyliczenie poziomej osi X. Początek zdarzenia wygląda tak:
Na samym początku zerujemy zmienną odpowiedzialną za liczenie, o ile pikseli ekran przesunął się w prawo względem krawędzi mapy. Następnie ustawiamy Numer X na 0 – ta zmienna będzie zawierać numer naszego pola na osi X, a jak wspominałem – właśnie od 0 pola te numeruje RPG Maker. Następnie do trzeciej zmiennej przypisujemy wartość Screen X lewego eventu. Cały pozostały skrypt będzie znajdował się w warunku sprawdzającym, czy wartość Screen X lewego eventu jest mniejsza lub równa 8. Co prawda mógłbym tutaj zostawić po prostu sprawdzenie, czy jest równa 8, ponieważ w naszym skrypcie nie może być mniejsza, ale jeśli będę chciał kiedyś bardziej rozbudować skrypt, ta dodatkowa opcja w warunku pozwoli mi uniknąć niespodziewanych nieprzyjemności.
Dla większej przejrzystości sam warunek podzieliłem na dwa elementy. W punkcie 1 omawiamy to, co program wykonuje przy spełnieniu warunku, a w punkcie 2 – wszystko znajdujące się w polu ELSE.
Jeśli Screen X lewego eventa jest równe 8 oznacza to, że ekran gry został przesunięty maksymalnie w lewo, czyli używając słownictwa wykorzystywanego w tym poradniku – przesunięcie w poziomie wynosi 0, ponieważ żadnego nie ma. W komentarzu między linijkami jest błąd – chodzi o lewą krawędź, a nie prawą.
Wewnątrz spełnionego warunku:
- ustawiamy zmienną X i Y do porownania (dalej: zmienna porównawcza) na 16, ponieważ będziemy sprawdzali co 16 pikseli miejsce, w które kliknął gracz (pola mają szerokość 16 pikseli, więc w ten sposób policzymy numer kafelka na mapie);
- do kolejnej zmiennej przypisujemy pozycję X myszy na ekranie;
- następnie tworzymy standardową pętlę, w której sprawdzamy, czy zmienna zawierająca pozycję myszy jest mniejsza od 16 (bo tyle przypisaliśmy do zmiennej porównawczej)
- jeśli pozycja myszy jest mniejsza od zmiennej porównawczej, kończymy pętlę;
- jeśli natomiast pozycja myszy jest większa, zwiększamy zmienną porównawczą o 16 oraz dodajemy 1 do zmiennej numer X i zaczynamy całe działanie od początku aż do przerwania pętli.
W ten sposób otrzymaliśmy skrypt, który tak długo będzie zwiększał zmienną porównawczą o 16 pikseli, aż trafi na pole, które kliknęliśmy myszką. Gdy tak się stanie, przerwie pętlę, a my otrzymamy w zmiennej Numer X dokładny numer kafla mapy, który kliknęliśmy.
Nieco trudniej jest w przypadku, gdy przesunięcie względem lewej krawędzi mapy istnieje – za obsługę tego przypadku odpowiada wszystko to, co znajduje się pod numerem 2 na obrazku (czyli w sekcji ELSE naszego głównego warunku).
Zabawę zaczynamy od pętli, w której:
- zwiększamy zmienną zawierającą Screen X lewego eventa o 1;
- zwiększamy wartość przesunięcia o 1;
- sprawdzamy, czy zmienna zawierająca Screen X lewego eventa osiągnęła już swoją podstawową wartość 8. Jeśli tak – kończymy pętlę.
Czemu rozwiązaliśmy to w taki sposób? Ponieważ podstawowa wartość Screen X lewego eventa to 8 (cyfra dodatnia), ale każde przesunięcie w prawo oznacza jej zmniejszenie. Najprościej jest to więc zrobić inkrementacją i w ten sposób zliczyć, o ile pikseli przesunięty w prawo jest ekran względem lewego krańca mapy.
Dalej znajduje się już prawie identyczny kod jak ten, który wstawiliśmy przy spełnieniu się warunku. Jedyna różnica jest taka, że tym razem do zmiennej zawierającej X kursora dodajemy wartość przesunięcia. W ten sposób otrzymujemy X będące sumą miejsca kursora na ekranie oraz przesunięcia ekranu względem lewej krawędzi mapy. Innymi słowy, otrzymujemy bezwzględną odległość kafelka, na który kliknęliśmy, od krańca mapy, a nie krańca ekranu.
Szukamy pozycji Y klikniętego pola
Jak zapewne się domyślacie, kolejny common event, który dotyczy tym razem ustalenia wartości Y klikniętego kafelka, jest zbudowany analogicznie do tego omówionego wyżej. Wygląda on tak:
Jak widać używam tutaj innych zmiennych, które dotyczą wartości Y. Sprawdzam Screen Y górnego eventa. Do obliczeń wykorzystuję te same zmienne numer 18 i 19 – common eventy wykonywane są po kolei, więc nie powinno być tu żadnych zgrzytów. Najważniejsze, że wartość przesunięcia i pozycja Y eventa znajdują się w odrębnych zmiennych.
Wyświetlenie wskaźnika
Jak mam nadzieję pamiętacie, skrypt na wyświetlenie wskaźnika składa się z trzech głównych common eventów. Po ustaleniu X oraz Y kafelka, w który kliknęliśmy, musimy jeszcze wywołać zdarzenie z pokazaniem obrazka. Wygląda ono tak:
Koordynaty X oraz Y naszego obrazka umieszczone są w specjalnie stworzonych do tego zmiennych o numerach 39 i 40. Do zmiennej X obrazka przypisujemy numer X kafla wyliczony w omówiony wyżej common evencie, a do zmiennej Y obrazka analogicznie przypisujemy numer Y kafla.
Następnie obie zmienne mnożymy przez 16 (bo taka jest wielkość kafli) i dodajemy do nich 8 (ten sam motyw co przy kursorze – musimy przesunąć obrazek względem środka). Na koniec od naszych zmiennych odejmujemy wartość przesunięcia X i Y, które także wyliczyliśmy w poprzednich common eventach. I gotowe! Teraz nasz obrazek pokazuje się (prawie) dokładnie tam, gdzie ma.
Pedantyczni użytkownicy Makera po testach mojego rozwiązania mogą zauważyć, że niedokładność mojej metody wynosi 1 piksel. Jeśli klikamy mniej więcej na środek kafla, nic nie zauważymy. Ale jeśli będziemy próbować klikać dokładnie na granice tile’i, niedokładność tę idzie zauważyć. Można to łatwo naprawić, a metodę na to zostawiam jako swoistą pracę domową. Chętnie poznam wasze rozwiązania w komentarzach!
Klikanie w zdarzenia
Znając X oraz Y kafla, na który kliknęliśmy, możemy sprawdzać, czy gracz wskazał myszką konkretny event. Poniżej modyfikacja common eventa z klikaniem uwzględniająca sytuację, w której kliknęliśmy na postać gracza:
Koncepcja jest chyba dość prosta i nie wymaga komentarza.
Myszka w okienku wiadomości
Ostatnia omówiona dziś opcja związana z myszką to możliwość dokonywania nią wyborów i zamykania standardowego okna wiadomości. By uzyskać taką opcję, należy wykonać w dowolnym miejscu naszego projektu następującą komendę w TPC:
@sys.gameOpt .mouse.disableMsgProcession 0
Można to zrobić np. usuwanym od razu eventem:
Pamiętajcie, że opcja wykorzystania myszy siłą rzeczy nie działa na podstawowym ekranie tytułowym. Nic jednak nie stoi na przeszkodzie, by ten ekran wyłączyć w zakładce w bazie danych i stworzyć własny title screen lub całkowicie z niego zrezygnować. Gdy dodamy do tego możliwość wyłączenia gry prawym przyciskiem myszy okazuje się, że w naszym przykładowym projekcie można od początku do końca nawigować wyłącznie myszą!
Michał „Michu” Wysocki