Script Calle i jak je polubić! – Bomba, pozycja, wykrywanie klawiszy

Wstęp

Dawno, dawno temu, w odległej galaktyce, aby określić położenie jakiegoś zdarzenia potrzebne były niekończące się zmienne. Dziś na przykładzie bomby pokażę wam, jak zrobić to w nowszych makerach bez potrzeby marnowania kilkunastu takowych.

Zacznijmy jednak od początku. Do wykonania naszego zadania używać będziemy tak zwanych “Script Call”. To nic innego, jak polecenia zdarzeń. Różnica polega jednak na tym, że zamiast wklepywać je bezpośrednio za pomocą edytora wizualnego, korzystamy z nich za pomocą komendy “script”, wpisując je w formie kodu.

Takowe komendy posłużyć mogą nam do wielu niecnych czynów. Najważniejsze dziś dla nas będą jednak te:

$gamePlayer.x;
$gamePlayer.y;
$gameMap.event(n).x
$gameMap.event(n).y

Jak same nazwy wskazują, pozwolą one nam określić położenie X i Y postaci oraz eventu. Przejdźmy zatem do programu i wykorzystajmy je w praktyce.

W programie tworzymy nowe zdarzenie bez grafiki (ważne!), które najlepiej nazwać “bomba”. Będzie ono służyło nam jako baza dla naszego wybuchowego przyjaciela. Dorzucamy nową stronę przy pomocy „New Event Page” i w panelu warunku, po lewej stronie, ustawiamy, że uruchamiać ma się tylko, gdy przełącznik np. 001 jest włączony. Możemy przypisać mu nazwę np. “bomba”. W tym wypadku grafika powinna już zostać ustawiona. Będzie ona służyć nam jako pierwsza klatka animacji. W obydwóch przypadkach proces startowy ustawiamy na „w tle/parallel„. 

Przypisanie nowego przycisku i wykrycie wciśnięcia

Tak przygotowane zdarzenie pozostawiamy na razie puste i przechodzimy do bazy danych, a następnie do sekcji common eventów (zdarzeń globalnych). Tych potrzebne będą nam dwa. W pierwszej kolejności zajmiemy się przyciskiem odpowiedzialnym za podłożenie naszej bomby. W tym celu użyjemy:

Input.isTriggered(’button’)

Owy fragment kodu posiada takie samo działanie jak komenda „button” w warunku.

Dlaczego więc używam kodu, aby wykonać coś, co znajduje się już w programie? Podstawowym i najważniejszym argumentem przemawiającym za wykonaniem tego działania przy pomocy skryptu jest fakt, iż możemy użyć w nim każdego klawisza znajdującego się na klawiaturze. Wersja z programu posiada jedynie dziewięć przycisków, które możemy wykorzystać. Oczywiście, na tym etapie moglibyśmy zakończyć przygotowania guzika i w miejscu “button” wpisać np. jeden z klawiszy znanych już RPG Makerowi.

Aby stworzyć własny klawisz musimy dowiedzieć się, jaki kod przypisany jest do niego w javascriptcie. Skorzystać możemy z tego linku. Wchodzimy na stronę i naciskamy interesujący nas przycisk. Strona wyświetli nam odpowiedni kod. Na potrzeby tego tutoriala użyję “e”, który posiada numer 69. Gdy mamy takową informację, jedyne ,czego potrzebujemy, to kolejny script call.

Input.keyMapper[numer klawisza] = ’nazwa klawisza’

W numer klawisza wpisujemy naszą liczbę 69, a w nazwie treść, pod jaką chcemy używać naszego przycisku. Może to być cokolwiek, ja jednak zawsze określam je literką, którą trzeba wcisnąć. 

Input.keyMapper[69] = e’

Ten script call najlepiej umieścić na początku naszej gry (komendy zdarzeń > trzecia strona > advanced >  script…) w zdarzeniu ustawionym na „w tle/parallel„, które po dodaniu klawisza samo się usunie. Dzięki temu gra od początku będzie wiedziała, że dodatkowy przycisk został stworzony.

Czas stworzyć system, który będzie wykrywał wciśnięcie danego klawisza. Wracamy więc do naszego common eventu, gdzie umieszczamy warunek. Przechodzimy do zakładki czwartej w warunku, opieramy go o “script…” i wklejamy do niego wcześniej poznany Input.isTriggered(’button’). W miejsce button wpisujemy oczywiście “e”.

W gotowy warunek wrzucamy aktywację naszego przełącznika, który przypisaliśmy do drugiej strony bomby.

Całe zdarzenie ustawiamy na parallel, a przełącznik na np. 002, który nazwiemy “Bomba Guzik”. W ten sposób będziemy mogli decydować, kiedy bomba może zostać użyta, włączając lub wyłączając jednego switcha. 

Wybuch bomby i obrażenia zadawane otoczeniu

Drugim zdarzeniem globalnym będzie akcja, która wykonuje się po „podłożeniu” bomby. Swoje nazwałem „Bomba Wybuch”. W tym przypadku trigger pozostawiamy na none, ponieważ event ma działać jedynie po wywołaniu, a nie jak wcześniejszy – w tle. Najważniejszą rzeczą w tej części będzie dopasowanie położenia zdarzenia do pozycji gracza. Zrobimy to za pomocą (tak, zgadliście!) kolejnego script callu. Ten będzie jednak dłuższy.

$gameMap.event(this._eventId).setPosition($gamePlayer.x, $gamePlayer.y);

Rozbijmy to na części pierwsze:

  • $gameMap.event(numer zdarzenia): funkcja określająca zdarzenie, które ma zostać poddane jakiejś akcji. W miejscu numer zdarzenia wpisać możemy dowolny ID eventu. Ja użyję jednak this._eventId. Stała ta pozwala programowi odczytać ID eventu, w którym aktualnie się znajduje. Przydatna rzecz przy tworzeniu automatycznych systemów, w których nie jesteśmy w stanie ustawić ID ręcznie.
  • .setPosition(x, y): informuje program o tym, że chcemy przenieść bombę/zdarzenie w miejsce określone za pomocą x i y.  W naszym przypadku jest to $gamePlayer.x, $gamePlayer.y czyli nic innego jak zmienne odpowiadające położeniu gracza, ale równie dobrze pisać tam można konkretne liczby. W ten sposób przeniesiemy zdarzenie w określone miejsce na mapie.

Dzięki wykorzystaniu stałych, kod sam pobierze potrzebne informacje bez potrzeby ingerencji twórcy. Tak jak wcześniej komendę wrzucamy w „script„.

Na tym etapie animacja oraz czas oczekiwania na wybuch zależą od was. Animację zrobiłem za pomocą „set movement route„, w którym to wybrałem opcję „change image„. Pamiętać trzeba, aby ustawić zdarzenie podległe zmianie jako „this event„, a nie „player” oraz ustawić opcję „through” na OFF. Nie chcemy przecież, aby gracz przenikał przez nasze zdarzenie.


Moja grafika posiada 8 klatek animacji (każda klatka to osobna grafika charsetu), które zmieniają się kolejno co 10 „frames„. Wyjątkiem jest pierwsza, która trwa 30, aby animacja nie odpalała się od razu po podłożeniu. Dodatkowo dorzucić możemy „direction fix” na ON jeżeli używacie mojego sposobu animacji. Pozwoli to uniknąć błędu, gdzie bomba „odwróci” się i nie będzie miała grafiki w tę stronę. Ewentualnie, tworząc klatki możemy zapełnić pełne pole charsetu. Ja jestem na to zbyt leniwy. Na końcu odpalamy animację „walki” na tym evencie.

Nie chcemy jednak, żeby bomba znikała, a dopiero później odpalała się animacja wybuchu, zatem nie ustawiamy w „set movement route” opcji „wait for completion„. Zamiast tego użyjemy zwykłego „wait” ustawionego na wartość 100. W ten sposób wybuch następuje chwilę przed zniknięciem ostatniej klatki animacji. Wartości animacji oczywiście można w pełni modyfikować, aby ją skrócić lub wydłużyć. Ponadto, jak można zauważyć, nie dodałem żadnego dźwięku. Spowodowane jest to faktem, że animacja posiada już własny SE.

W praktyce wygląda to tak. Proszę pamiętać, że animacje zostały w całości wykonane przeze mnie, zatem efekt może różnić się, w zależności od jakości waszych grafik.


Aktualnie nie ma to jednak żadnego efektu poza wizualnym, dlatego teraz dodamy zmienną, dzięki której określimy, czy przedmioty znajdujące się na mapie są w polu rażenia. Nie chcemy przecież, aby bomba wysadzała nam doniczki znajdujące się na drugim końcu etapu, prawda? Dodajemy więc nową zmienną, nazywamy ją i ustawiamy na „set = 1„. Zanim przejdziemy jednak do budowania „skryptu” na niszczenie przedmiotów, warto ustawić jedną dodatkową funkcję, a mianowicie obrażenia dla gracza, gdy ten nie zdąży wyjść z pola wybuchu.

Ponownie wchodzimy na czwartą stronę w warunku i wybieramy script. Tym razem funkcja, której użyjemy, będzie wyglądać trochę inaczej.

Math.abs($gamePlayer._y$gameMap._events[this._eventId]._y ) <= 1

W środku warunku tworzymy kolejny z praktycznie identycznym kodem. Różnica polega na tym, że tym razem sprawdzać będziemy położenie względem osi X.

Math.abs($gamePlayer._x$gameMap._events[this._eventId]._x ) <= 1

Powinno to wyglądać w ten sposób:

Warunki te pozwolą nam określić, czy gracz znajduje się w promieniu jednej kratki od zdarzenia wywołującego dany common event. Jeżeli chcemy, aby zasięg był większy, analogicznie ustawiamy x<=2, y<=2. Możemy też ustawić zasięg niestandardowy, w którym np x<=1, ale y sięgać będzie już na 2 kratki.

Nie było by to jednak możliwe, gdyby nie Math.abs. Składnia ta zwraca bowiem wartość bezwzględną danej liczby, a co za tym idzie, nieważne czy gracz znajdzie się po lewej, po prawej, górnej czy dolnej stronie zdarzenia, wartość zawsze będzie plusowa.

Skoro położenie zostało już określone, pozostało nam ustalić, co stanie się z graczem, gdy ten będzie zbyt wolny, aby uciec od wybuchu. W moim przypadku będzie to proste użycie animacji standardowego uderzenia i game over.

Nie możemy zapomnieć oczywiście o zakończeniu zdarzenia. Pod warunkiem, nie w nim, dodajemy kolejny „set movement„, w którym ustawiamy „through” na ON (bomba już wybuchła, więc nie powinna blokować gracza) oraz „image: none„, aby usunąć grafikę. Następnie dodajemy „wait” na 60 klatek (1 sekunda). Jest to czas działania wybuchu. Przez 1 sekundę, w danym obrębie, postać oraz inne zdarzenia będą mogły otrzymać obrażenia. Po tym czasie ustawiamy naszą zmienną na „set = 0„, a samo zdarzenie za pomocą „set event location” przesyłamy na współrzędne (0,0) (Pamiętaj o THIS EVENT!). Common event zamykamy ustawieniem przełącznika „bomba”, odpowiedzialnego za odpalenie drugiej strony eventu bomba, na OFF. Zapobiegnie to odpaleniu się zdarzenia więcej, niż jeden raz.  Cały kod powinien wyglądać mniej więcej w ten sposób. 

Po skompletowaniu wracamy na mapę do zdarzenia naszej bomby i na drugiej stronie, tej odpalanej przez przełącznik, ustawiamy za pomocą komendy „common event” uruchamianie się naszej akcji.

W tym momencie powinniśmy posiadać już sprawną bombę, odpalaną za pomocą przycisku „e„, która wybucha po 100 klatkach, a wybuch trwa 60 klatek. Następnie przenosi się ona na pole o współrzędnych (0,0), gdzie czeka na kolejne wciśnięcia klawisza. Ponadto, jeżeli gracz zostanie złapany przez wybuch, pogodzić się będzie musiał z ekranem końca gry.

Tworzenie zdarzeń podatnych na wybuch

Aby stworzyć obiekt, który poddany może zostać jakieś akcji, gdy znajduje się w zasięgu wybuchu, musimy porównać położenie tego obiektu do położenia naszej bomby. Zaczynamy od stworzenia nowego zdarzenia z grafiką obiektu. Ja użyję skrzyneczki.

Dzięki użyciu zmiennej w common evencie, pierwsza strona zostaje całkowicie do naszej dyspozycji. Gracz może normalnie wchodzić w interakcję z obiektem, a co za tym idzie możemy wstawić tam chociażby jakąś wiadomość. Cała magia dziać będzie się na stronie drugiej, a zatem bez chwili zawahania dodajemy ją przyciskiem „new event page” i ustawiamy na „w tle/parallel„.

W panelu warunku, po lewej stronie, ustawiamy uruchomienie na „variable >= 1„. Zmienna oczywiście musi pokrywać się z tą stworzoną w common evencie. Ten mały warunek spowoduje, że strona uruchomi się jedynie wtedy, gdy zdarzenie globalne odpowiedzialne z wybuch zostanie odpalone. Jednakże aktualnie akcja wykonała by się niezależnie od odległości w jakiej znajduje się skrzynka od eventu bomby.

Math.abs($gamePlayer._y$gameMap._events[n]._y ) <= 1

Do wykrycia położenia użyjemy tego samego kodu, co wcześniej. Będziemy musieli go jednak lekko zmodyfikować. Z uwagi na to, że tym razem wykrywamy położenie dwóch zdarzeń, z kodu zniknąć musi wzmianka o graczu.

Math.abs(._y$gameMap._events[n]._y ) <= 1

Tę zastąpimy drugą stałą eventu $gameMap._events[n]._y.

Math.abs($gameMap._events[n]._y. – $gameMap._events[n]._y ) <= 1

Aby program wiedział jednak, jakie zdarzenia ma ze sobą porównać, określić musimy ich ID. W związku z tym, że pudełko posiadać będzie owy kod wewnątrz samego siebie, możemy skorzystać z this._eventId, co daje nam:

Math.abs($gameMap._events[n]._y. – $gameMap._events[this._eventId]._y ) <= 1

Nadal potrzebujemy jednak ID bomby. Takowe znajdziemy w lewym górnym rogu edytora zdarzeń nad nazwą.

Na tej mapie bomba posiada ID = 001. W skrócie można zapisać to jako po prostu 1.

Math.abs($gameMap._events[1]._y. – $gameMap._events[this._eventId]._y ) <= 1

Math.abs($gameMap._events[1]._x. – $gameMap._events[this._eventId]._x ) <= 1

Taki kod powinien działać, jednakże nie jest on przystosowany do automatycznego funkcjonowania.  Nie jest bowiem powiedziane, że na każdej mapie bomba posiadać będzie ID = 001. Możemy tego dokonać dodając za każdym razem bombę jako pierwsze zdarzenie na mapie, ale jest to uciążliwe, dlatego użyjemy pewnego sposobu na ominięcie tej niedogodności, a mianowicie wykorzystamy do tego script call, który może modyfikować dowolną zmienną. Wracamy zatem do zdarzenia naszej bomby i na pierwszej stronie (tej bez grafiki, która odpala się jako niewidzialne zdarzenie w tle) dodajemy skrypt (komendy zdarzeń > trzecia strona > advanced >  script…):

$gameVariables.setValue(a, b);
  • $gameVariables.setValue: funkcja pozwalająca ustawienie dowolnej wartości liczbowej w dowolnej zmiennej,
  • a: numer zmiennej, w której chcemy zapisać jakąś wartość,
  • b: wartość, która ma zostać zapisana w zmiennej.

Zapewne domyślacie się dlaczego umieściliśmy tę funkcję w zdarzeniu bomba. Dzięki stałej this._eventId będziemy w stanie w zmiennej A zapisać wartość B, czyli ID TEGO eventu, w którym znajduje się ta komenda.  Wybieramy zatem zmienną (inna, niż ta służąca do wykrywania wybuchu), wpisujemy dane do kodu i dodajemy przez komendę „script…„.

$gameVariables.setValue(2, this._eventId);

W ten sposób kopiując zdarzenie na nową mapę, ID tego zdarzenia automatycznie zapisywane jest w zmiennej 2. Dane te możemy przekazać programowi za pomocą:

$gameVariables.value(2);

Teraz wystarczy podmienić numer 1 w warunku znajdującym się w skrzynce, która ma zostać wysadzona, na powyższą stałą.

Math.abs($gameMap._events[$gameVariables.value(2);]._y. – $gameMap._events[this._eventId]._y ) <= 1

Math.abs($gameMap._events[$gameVariables.value(2);]._x. – $gameMap._events[this._eventId]._x ) <= 1

Dzięki temu zyskaliśmy skrzynkę, która uruchomi stronę numer 2, podczas „akcji” ze zdarzenia globalnego, uruchomionego przyciskiem „e”, jednakże akcję wykona dopiero wtedy, gdy this._eventId (to zdarzenie – skrzynka) będzie w odległości x <= 1 oraz y <= 1 od zdarzenia, które posiada ID przechowane w $gameVariables.value(2);

W skrócie: jeżeli skrzynka będzie w odległości 1 kratki od bomby, to wybuchnie.

Największym plusem takiego rozwiązania jest fakt, że dzięki użyciu script calli byliśmy w stanie w pełni zautomatyzować proces, a co za tym idzie zdarzenie z obiektem podlegającym destrukcji możemy kopiować wiele razy bez potrzeby zmieniania jakiejkolwiek wartości w środku.

Na koniec pozostało nam jedynie wprowadzenie akcji, która wykonać ma się, gdy zdarzenie rzeczywiście wybuchnie. Jak w przypadku animacji bomby, mamy tutaj pełną dowolność, dlatego efekty wybuchu pozostawię waszej wyobraźni, a sam dodam jedynie „erase event„, co spowoduje wykasowanie danego zdarzenia.

To by było na tyle jeżeli chodzi o dzisiejszy tutorial. Jak widać, script calle mogą być bardzo przydatne przy tworzeniu bardziej zaawansowanych systemów, ponieważ potrafią więcej, niż sam edytor. Jeżeli kogoś zainspirował ten tutorial do stworzenia swojego własnego systemu, polecam link z pełną listą: RPG MAKER MV / MZ Script Calls! Cya!

Crashykk

5 thoughts on “Script Calle i jak je polubić! – Bomba, pozycja, wykrywanie klawiszy

  1. Dużą frajdę sprawiła mi redakcja tego tekstu. Dzięki niemu poważnie zacząłem myśleć nad tym, by zainteresować się RPG Makerem MV. Mam nadzieję, że to nie ostatni tutorial od Crashykka 😉

  2. Fajny tekst, ale mam parę uwag (jak zwykle XD)
    – sztywne przypisywanie klawiszy – według mnie jak nie trzeba wychodzić po za to co oferuje tutaj RM, to lepiej nie wychodzić. Ten sposób nie uwzględnia grania na padzie, a to ważne. Sam RM ma tak dopasowane klawisze, że obsługuje pada.
    – sprawdzanie czy gracz nie oberwał jest robione tylko raz, a wybuch ma trwać 60 klatek, więc jeśli przed pierwszą klatką bohater nie znajduje się w polu zasięgu bombki to jak nawet wejdzie w nie powiedzmy w 30 klatce jej wybuchu to już nie oberwie
    – skoro efent i tak idzie w odstawkę w prawy górny róg mapy, to nie ma potrzeby resetowania jego ustawień graficznych (po za zmianą grafiki na puste, ale to i tak z tego co rozumiem samo się robi, bo włącza się jego 1 strona)
    – no i na koniec, w sumie nie widzę tego co miało zdeklasować efenty bez dostępu do kodu (RM2k/3), może jedynie funkcja .abs, ale i to da się wykonać. Po za tym jak wie się jak RM działa, to nadal da się to zautomatyzować i np używać tylko jednej pary zmiennej dla wszystkich efentów (jeśli zapisanie współrzędnych i sprawdzenie odbywa się w kodzie zaraz obok siebie, to nie ma potrzeby trzymania ciągle współrzędnych w zmiennej – a więc jedną parą można obrobić wszystkie efenty, kod z nich nigdy nie jest przetwarzany jednocześnie). Jedyne co może przeszkodzić w RM2k i starszych 2k3 (ale nie 1.12), to to że this efent ze zdarzeń globalnych nie działał, ale mogę coś mieszać tutaj.

    Trzeba by sprawdzić czy zadziała to też w ten sam sposób w MZ, i porobić komendy do działania w XP-ACE, bo jeśli nawet sposób może być ten sam, to same kody w script callach pewnie się różnią.

  3. Fajnie poprowadzony, merytoryczny tutorial! Przy tym pokazuje przewagę nowszych wersji RPG Makera – które w wersji surowej pozwalają na tak dogodną optymalizację zdarzeń i metodę kopiuj-wklej przy bardziej skomplikowanych mapach.
    Wbrew dyskusji discordowej, uważam też trzymanie wartości w zmiennych lokalnych eventu za lepsze rozwiązanie niż przez stosowanie funkcji zmiennej w Database standardowej dla RPG Makera. Twój kod w zdarzeniu jest czysty i łatwiej pozwala na wykrycie błędu.
    Jak dobrze rozumiem, skrypt zakłada posiadanie jednej bomby na mapę i odpowiedniego cooldownu przed postawieniem kolejnej, tak? Czy jest jakaś metoda na to, by w dość optymalny sposób dostosować powyższy tutorial do możliwości używania kilku bomb jedna po drugiej?

    1. Stworzenie kilku bomb nie było by takie trudne jak się wydaje. Najważniejszymi elementami były np 2 kolejne zdarzenia odpowiadające za bombę nr 2 i 3. W środku ten sam kod na ustalenie ID, ale do innych zmiennych np 2 i 3. Bombki musiałby mieć własne switche, które by je odpalały. Wtedy przy kliknięciu klawisza „e” musiałabyś ustalić warunki.

      ◆If:Script:Input.isTriggered(’e’)
      ◆If:Bomba is ON
      ◆If:Bomba 2 is ON
      ◆Control Switches:#0026 bomba 3 = ON

      :Else
      ◆Control Switches:#0014 Bomba 2 = ON

      :End

      :Else
      ◆Control Switches:#0001 Bomba = ON

      :End

      :End

      Dzięki temu po ponownym kliknięciu przenosiłoby do Ciebie 2 i 3 zdarzenie.

      W zdarzeniu pudełka trzeba by było wtedy troszeczkę zmodyfikować, ponieważ musiałabyś dorzucić warunki dla dwóch kolejnych bomb. Czytaj: ten sam warunek tylko zmieniasz numer zmiennej na te z dwóch pozostałych bomb.

      1. Dziękuję za znalezienie chwili na wyjaśnienie! Faktycznie brzmi całkiem prosto – aż chce się potestować MV dla tego skryptu. Czekam na więcej takich tutoriali technicznych. <3

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.