Skręć Se Silnik, cz.2
 

autor: Kamil


 

   Dzisiaj postaram się przybliżyć, jak powinno się konstruować ruch platformowy w oparciu o Fast Loopa. Ruch platformowy to temat-rzeka, sprawił problem praktycznie każdemu klikowcowi. Mimo, iż mamy wbudowany ruch TGFowy, jak wszyscy wiedzą, nie jest on doskonały. Spróbujemy napisać własny ruch, unikając błędów tego wbudowanego. Zapraszam do lektury. Zalecam także małą porcyjkę kofeiny, bowiem dobrze wspomaga myślenie, a bez myślenia tutaj się nie obejdzie.

 

Z racji, że do zrozumienia artykułu potrzebna jest podstawowa znajomość Fast Loopa, postanowiłem pierwszą część artykułu poświęcić zrozumieniu tejże wtyczki.

 

Zrozumieć Fast Loopa

 

   Fast Loop, właśnie na nim wszystko się opiera. Najlepszym sposobem na zrozumienie jest przykład, natomiast najlepszym przykładem jest, moim zdaniem, grawitacja, ponieważ właśnie na takim przykładzie ja pojąłem zasadę działania FL.

 

   Trochę teorii grawitacji, jak wiadomo, grawitacja to jednostajnie przyspieszony ruch ciała w stronę ziemi. Gdy na ciało działa grawitacja, przyspiesza ono wedle wartości przyspieszenia ziemskiego (ok. 10m/s^2). W klikach najlepiej będzie gdzieś przechowywać prędkość i w każdej pętli przesuwać go o tyle pikseli, ile wynosi jego prędkość. Ponadto trzeba tę prędkość zwiększać w każdym cyklu. Obiekt ma spadać tylko wtedy, gdy nie koliduje z tłem. I właśnie zazwyczaj, robiąc w ten sposób, odkrywamy, że obiekt "wbija się w tło". Dlaczego? Przypuśćmy, że prędkość obiektu jest jednostajna i wynosi 5 pikseli na pętlę. Sprawdzanie, czy obiekt znajduje się w przeszkodzie zachodzi wobec tego raz na pętlę, czyli co pięć pikseli. Mało prawdopodobne jest, że kolejne pięć wypadnie akurat przed przeszkodą. Można oczywiście zrobić ruch z prędkością 1px, ale to w ogóle nie jest grawitacja i w ogóle prędkość równa jest prędkości dryfu kontynentów. Co zatem zrobić?

 

Posłużyć się Fast Lopem

 

   Jak działa FL? Powoduje zagnieżdżenie innej, szybszej pętli w standardowej, TGFowej. Co to znaczy? To znaczy, że gdy np. raz na pętlę wywołamy pięciokrotne odpalenie szybkiej pętli FL, a w niej ruch obiektu o jeden piksel w dół, da nam mniej więcej to samo, co przesuwanie obiektu o 5 pikseli na pętle. Jednak możemy w tej szybkiej pętli także sprawdzać kolizje. I tutaj ujawnia się cała potęga najpotężniejszego rozszerzenia – szybkość bez utraty dokładności. Sprawdzić, czy zachodzi kolizja możemy teraz nie co 5 pikseli, a co jeden, co praktycznie wyeliminuje wbijanie się w przeszkody. Trochę może ciężko to pojąć, więc czas na rysunki:

 

Rys.1 – kazałem przesuwać w każdej pętli obiekt o 20px gdy nie koliduje z tłem.

 

Jak widać, obiekt jest tam podczas sprawdzania, gdzie zaznaczyłem dłuższymi kreskami. A powinno zachodzić co jeden piksel.

 

Gdy używamy FL, obiekt nie robi skoków o 5 px, a płynnie przesuwa się o jeden piksel.

 

Rys. 2 – to samo z użyciem Fast Loopa.

 

A więc jak, już zrozumiane? Jeżeli tak – zapraszam do dalszej lektury.

 

Ruch teoretycznie

 

   Uzbrojeni w niezbędną do sukcesu wiedzę możemy przystąpić do sformułowania ogólnych założeń silnika i propozycji, jakby to zrealizować. Przypominam, że grawitacja do jednostajnie przyspieszony ruch obiektu w stronę ziemi. Najlepszym sposobem na grawitację jest stałe ustawianie obiektu względem siebie samego o prędkość i zwiększanie prędkości o 1 na pętlę, co sprowadza nas do takich akcji:

 

 

+Zawsze

   - Dodaj 1 do licznika V (prędkości)

   - Ustaw pozycję obiektu A na YobiektuA + WartośćV.

 

 

   Ten sposób jest o tyle dobry, że aby wywołać ruch obiektu do góry wystarczy ustawić prędkość na wartość ujemną (wiadomo, plus i minus daje minus, więc obiekt zacznie zmniejszać swoje Y, czyli zacznie się przesuwać do góry).

 

   W Fast Loopie praktycznie nie będzie się to różnić – będziemy wywoływać V-razy pętlę #0 i w niej przesuwać obiekt o jeden px w dół. Ale zaraz, w dół? No tak, to powoduje, że musimy przesuwać obiekt w górę, lub w dół, zależnie od znaku V. Należy również pamiętać, że nie jest rzeczą dobrą odpalać pętlę –x razy. A więc trzeba zamienić V na liczbę dodatnią. Jedynym sposobem na to jest stworzenie dwóch liczników – jeden będzie przechowywał faktyczną prędkość, dodatnią lub ujemną i będzie pomagał w ustaleniu, czy obiekt ma się ruszać w górę, czy w dół, a drugi będzie zawierał tylko prędkość, lecz zawsze dodatnią i będzie wskazywał, ile razy ma być wykonana pętla.

 

   I już dysponujemy niemalże wszystkim do wykonania pionowego ruchu w naszym silniku. Należy wspomnieć również, że obiekt ma się oczywiście przesuwać tylko wtedy, gdy jest w powietrzu (tj. nie koliduje z tłem). Najlepszym sposobem na sprawdzenie tego są detektory. Jeden dolny (na dół, wykrywa kolizję z podłożem) i jeden na górze (wykrywa uderzenia w sufit).

 

   A teraz nieco o skoku. Oczywiście, by go wywołać, należy ustawić prędkość na wartość ujemną. Skok może zajść tylko wtedy, gdy obiekt stoi na ziemi (dolny detektor koliduje z tłem). No i nie zapominajmy o tym, by wywołać pętlę, by nasz obiekt mógł rozpocząć ruch.

 

   Ruch na boki będzie najprostszym elementem tego silnika – nie będzie kontrolowany przez Fast Loopa. Zarys wygląda mniej więcej tak – gdy klikamy strzałkę w lewo i lewy, detektor nie koliduje z tłem, przesuń obiekt o ileśtam pikseli w lewo.

 

   I jeszcze ostatnia ważna sprawa – ruch detektorów. Najprostszym sposobem na ich przemieszczanie byłoby oczywiście zawsze ustawianie ich w określonej odległości od obiektu, jednak to w przypadku ruchu FL-owego nie wypali, ponieważ detektory ustawiają się co pętlę TGFową, a w czasie tej pętli obiekt przesunie się o wiele więcej pikseli, wobec czego detektory zostaną z tyłu. Najlepszym sposobem jest ustawienie obiektowi hot spotu na sam środek i odpowiednie ustawienie hot spotu detektorom tak, by wypadał on dokładnie na gorące miejsce obiektu, gdy detektory są na odpowiedniej pozycji. Czyli, gdy obiekt ma 32 piksele szerokości, prawy detektor powinien mieć hot spot na Y=-16. W czasie każdego ruchu, czy to poziomego, czy pionowego detektory muszą być poruszane osobno tak jak obiekt.

 

   Omówiłem, mam nadzieję, wszystkie ważne aspekty. Nieco ambitniejsi powinni teraz spróbować sami coś napisać, a nuż wyjdzie? Tym bardziej leniwym polecam dalszą część, zajmiemy się już praktyczną konstrukcją.

 

Ruch praktycznie

 

   Całość sprowadzi się tylko do 11 zdarzeń. To naprawdę niewiele. Stworzy to niezłą platformę startową do dalszych zabaw z silnikiem i bazę na kolejne gadżety.

 

Potrzebujemy równie niewiele – obiektu (nazwijmy go A), 4 detektorów (lewy, prawy, górny, dolny), dwóch liczników (V1 i V2) i jakiejś konstrukcji z obiektów tła będącego placem manewrowym do testowania naszego ruchu.

 

Rys. 3 – nasz "plac manewrowy".

 

   Najpierwsiejszym zdarzeniem będzie zdarzenie związane z odpalaniem pętli – należy zawsze odpalić pętle #0 tyle razy, ile wynosi V2. Chyba nie muszę tłumaczyć, dlaczego...

 

   Kolejne dwa zdarzenia dotyczą sytuacji, gdy obiekt jest w powietrzu i na ziemi. Pierwsze – gdy dolny detektor nie zachodzi na tło – dodawaj 1 do V1. Drugie – w czasie #0 i gdy dolny zachodzi na tło – ustaw V1 na 0 (obiekt się nie porusza). Należy do tego dodać również tylko jeden raz gdy zdarzenie się powtarza (only one action when event loops). Jest to bardzo ważne, gdy robimy skok (bo bez tego wartość zawsze ustawiałaby się na 0 i skok byłby niemożliwy, a tak ustawia się tylko raz na kolizję z tłem).

 

Następne dwa ustalają wartość licznika V2 – gdy V1>0 ustaw V2 na V1, a gdy V1<0 ustaw V2 na odwrotność V1 (-(V1)).

 

   Teraz samo jądro – dwa zdarzenia odpowiadające za ruch w pionie. W czasie pętli #0 i gdy V1>0 przesuń obiekt o 1px w dół (i wszystkie detektory także). Drugie zdarzenie na odwrót, gdy V1<0 – przesuń obiekty o 1px w górę.

 

   Skok – gdy naciskamy klawisz odpowiedzialny za skok i obiekt jest na ziemi (dolny koliduje z tłem), ustaw V1 na minus ileśtam (ważne by na wartość ujemną) i odpal #0 V2 razy.

 

I odbicie od sufitu – w czasie pętli #0 i gdy górny koliduje z tłem ustaw V1 na 0 i przerwij pętle #0.

 

   A na koniec ostatnie dwa zdarzenia dotyczące ruchu poziomego – gdy naciskamy lewy przycisk + lewy detektor nie zachodzi na tło – przesuń obiekty o 1px w lewo. Analogicznie w prawo.

 

I to wszystko! Prawda, że łatwe? Spróbuj, jeżeli się uda, możesz sobie pogratulować – stworzyłeś (zapewne) swój pierwszy ruch platformowy! Jeżeli nie, przeczytaj poniższą część.

 

Rzeź błędów

 

A teraz kilka wskazówek, co i w jaki sposób może spowodować krytyczny błąd całego silnika.

 

- Podczas pętli #0 zawsze pierwszy:

To najważniejsza zasada Fast Loopa, zapomniałem o niej wspomnieć. Zdarzenie dotyczące FL zawsze musi być pierwsze, gdy jest ich więcej. Układ taki jak na tym obrazku:

jest niedopuszczalny i najczęściej prowadzi do krytycznego błędu!

 

- Odpalanie pętli ujemną ilość razy:

Karygodny błąd. W takich sytuacjach zwykle FL szaleje co kończy się zwisem całego TGFa. Postarajmy się nigdy nie dopuszczać do odpalania pętli ujemnych (pamiętajmy o zdarzeniu #5)

 

- Umiejscowienie detektorów:

Ważne jest, by boczne detektory wystawały o ok. 2px w stosunku do szerokości detektora dolnego. Gdy nie wystają może dojść do zawieszania się obiektu na bocznych ścianach lub ślizgania się po nich.

Natomiast dolny (i górny) detektor nie powinien wystawać poza wysokość detektorów bocznych, może bowiem spowodować to "wkopanie się" obiektu w ziemię podczas naskoku z boku na platformę.

 

- Only one action when event loops w zdarzeniu #3:

Tutaj też łatwo o błąd. Wytłumaczę pokrótce, o co chodzi: gdy detektor dolny koliduje z tłem, bez tego zdarzenia akcja zachodziłaby ciągle, dopóki obiekt jest na ziemi. Gdybyśmy równolegle wykonali skok, nic by z tego nie wyszło, bo dopiero co ustawiona V1 na ujemną, zamieniłaby się na 0. Dodanie tego zdarzenia powoduje, że zatrzymywanie obiektu w ruchu poziomym zachodzi tylko raz (co w zupełności wystarczy) i możemy spokojnie wywoływać skok.

 

Podsumowując

 

   I dobrnęliśmy do końca tego rozległego tematu-morza. O ruchu platformowym można napisać wiele, wiele więcej. Możemy go mocno rozbudowywać o kolejne funkcje takie jak dokładna kontrola ruchu poziomego z przyspieszeniem, ruchome platformy, trampoliny, łapanie się za przeszkody itd. Wszystko zależy od chęci – polecam dalsze eksperymenty w ramach treningu. Jak już mówiłem – to dobry, suchy ruch do zabaw.

 

I jeszcze jedna mała wskazówka – gdy zechcemy zmniejszyć siłę grawitacji, dzielmy prędkość przez 2 (lub ile tam chcecie).

 

A dla nierozumnych: przykład

 

 

 

Copyright (c) 2005-2006 Ślimaczek