Jest to tłumaczenie kursu Davida Newtona, znanego jako DavidN. Oryginalny kurs można znaleźć na stronie Clickteamu.
Spis treści:
- Prolog
- Podstawy Ruchu z Fastloopem
- Skoki i Grawitacja
- Ruch Horyzontalny (Poziomy)
- Zmiana Ruchu
Kiedy już stworzysz w MMF kilka pierwszych projektów, jednym z najwazniejszych kroków będzie umiejętność tworzenia własnego ruchu opartego o Event Editor (Edytor Zdarzeń) zamiast korzystania z wbudowanych ruchów. Wbudowany ruch platformowy jest wszakże jednym z najbardziej niesławnych elementów programów klikowych, biorac pod uwagę mnóstwo niedogodności, takie jak zacinanie się na ścianiach i przyklejanie do sufitu czy resetowanie pozycji horyzontalnej gracza po skoku.
Większość z podstawowych własnych ruchów platformowych (tych, które nie używają funkcji fastloopa - szybkiej pętli) potrafi obejść te problemy, ale rodzi nowe - bez wykorzystania wbudowanych ruchów trzeba się uporac z własnym wykrywaniem kolizji oraz liczyć się z tym, że postać może zaciąć się w przeszkodzie, gdy porusza się więcej niż o jeden piksel.
Właśnie wtedy przydaje się fastloop. Normalnie, lista eventów (zdarzeń) jest czytana przez program od góry do dołu, gdzie wszystkie akcje są wykonywane po kolei. Po "przeczytaniu" całej listy, ekran jest odświeżany i wszystko zaczyna się od nowa. Fastloopy, szybkie pętle, jak wskazuje ich nazwa, mogą być wykonywane po kilka razy w jednym takim cyklu. Akcja "Start loop" (Zacznij Pętlę) pod obiektem "Special" (Specjalne) jest używana do włączania fastloopa, i w każdej pętli, eventy które zaczynają się od warunku "On loop (nazwa pętli)" są wykonywane po kolei, tyle razy na cykl, ile ustawisz.
Jeśli nie rozumiesz o co chodzi, tym bardziej powinieneś czytać dalej. Najlepiej uczyć się na przykładach.
Podstawy Ruchu z Fastloopem
Na początek będziesz potrzebował obiektu gracza i kilku przeszkód z którymi mógłby kolidować. Póki co używaj czworokątów/kwadratów - właściwą grafikę można dodać potem. Nie ustawiaj obiektowi Gracza żadnego ruchu, pozycję na ekranie będziemy kontrolować za pomocą zdarzeń.
Skoki i Grawitacja
Najpierw w naszym ruchu powinniśmy rozważyć jak na naszego gracza wpływa grawitacja. By wykonać przekonujący skok, gracz powinien wzbić się szybko do góry, następnie zacząć zwalniać i zacząć spadać po osiągnięciu maksymalnej wysokości. Dlatego, wartość grawitacji oddziałującej na gracza powinna się zaczynać od ujemnej wartości, a następnie stopniowo wzrastać póki nie stanie on na ziemi.
Dodaj nową alterable value (wartość zmienną) obiektowi Gracza i nazwij ją "Grav" ("Gravity" jest słowem zarezerwowanym dla MMF2). Będziemy używac tej wartości by przechowywać liczbę pikseli, o które gracz powinien się ruszyć w jednym cyklu zdarzeń w zwiazku z ciążącą grawitacją. Powinna zaczynać się od 0, więc nie musisz zmieniać domyślnej wartości.
Grawitacja powinna ściągać obiekt Gracza w dół (dopóki nie znajdzie się na obstacle backdrop - przeszkodzie tła). Utwórz nową grupę zdarzeń, jeśli chcesz by później kod wygladał czytelniej i dodaj zdarzenie:
| Gravity/Jump |
| 1 |
• Always
Add 1 to Grav("Player")
|
Tak naprawdę nie będziemy używali tej wartości by bezpośrednio przesunąć Gracza. Zamiast tego użyjemy fastloopa by obsłużyć grawitację Gracza. Zdarzenia które będzie kontrolował nasz fastloop będą sprawdzały czy nasz gracz może się ruszyć w górę lub w dół i jeżeli tak, to będą przesuwały go o jeden piksel. Ten proces musi być powtarzany tak długo jak trzeba, więc Gracz przechodzi przez wszystkie punkty pośrednie zanim ekran zostanie odświeżony. To różni ten sposób od silnika bez szybkich pętli, który po prostu porusza gracza o żądaną liczbę pikseli naraz.
Dodaj zdarzenia:
| 2 |
• On loop "gravity"
• Grav("Player") > 0
Set Y position of Player to Y("Player")+1
|
| 3 |
• On loop "gravity"
• Grav("Player") < 0
Set Y position of Player to Y("Player")-1
|
Te zdarzenia sprawdzają czy czy Gracz powinien się ruszyć w górę czy w dół i odpowiednio przesuwają obiekt Gracza o 1 piksel we właściwym kierunku.
| 4 |
• On loop "gravity"
• Player is overlapping an obstacle background
• Grav("Player") > 0
Set Y position of Player to Y("Player")-1
Set Grav("Player") to 0
Stop loop "gravity"
|
| 5 |
• On loop "gravity"
• Player is overlapping an obstacle background
• Grav("Player") < 0
Set Y position of Player to Y("Player")+1
Set Grav("Player") to 0
Stop loop "gravity"
|
Te zdarzenia sprawdzają czy Gracz wpadł na tło i cofają go o piksel. Pierwsze zdarzenie przesuwa Gracza o piksel w górę jeśli natrafił na "podłogę", a drugie o piksel w dół jeśli trafił na "sufit". Kiedy Gracz trafi na tło, nie chcemy by dalej wznosił się lub opadał, więc grawitacja jest ustawiana na 0 i przestajemy wykonywać kolejne pętle.
Teraz, gdy mamy już eventy, które obsługują grawitację powinniśmy sprawdzać kiedy powinny zostać włączone lub wyłaczone. Gdy gracz stoi na ziemi, nic nie powinno się dziać, ale gdy tylko grawitacja nie będzie równa 0, powinna się zacząć pętla, którą właśnie stworzyliśmy.
| 6 |
• Grav("Player") <> 0
Start loop "gravity" ABS(Grav("Player")) times.
|
Ten event włączy pętlę "gravity" zawsze gdy grawitacja będzie różna od 0. Gdy pętla jest włączona, wszystkie zdarzenia zaczynające się od "On loop 'gravity'" będą wykonywane tyle razy, ile wskażemy. Każda pętla przemieszcza Gracza o jeden piksel, więc chcemy odtwarzać pętlę tyle razy ile nam wynosi wartość grawitacji. Funkcja ABS() jest tam by zwracać nam zawsze wartość bezwzględną z liczby, ponieważ liczba ujemna sprawiłaby, że nasza gra by się zawiesiła.
Kolejne zdarzenie, które dodamy jest zdecydowanie bardziej przyjazne...
| 7 |
• Player presses Fire 1
Set Grav("Player") to -10
|
Kiedy zostanie wciśnięty klawisz skoku, wartość grawitacji powinna zostac ustawiona na ujemną, by Gracz został wyrzucony do góry. Wartość grawitacji stopniowo się zmniejsza przez pierwsze zdarzenie, które stworzyliśmy, więc w końcu wartość grawitacji stanie się liczbą dodatnią i gracz zacznie spadać w dół.
Przyszedł czas, żeby odpalić naszą grę i sprawdzić jak w praktyce działają nasze zdarzenia. Gdy wciskamy przycisk Fire 1 (domyślnie Shift), Gracz podskoczy w górę i spadnie nigdy nie "wbijając się" w podłoże, ponieważ sprawdza to nasz fastloop. To samo stanie się jeżeli gracz dotknie sufitu - będziesz mógł zobaczyć jak pętla broni Gracza przed tym by przebił się przez przeszkodę.
Zauważysz jednak szybko, że możesz skakać nawet w powietrzu, ponieważ nie sprawdziliśmy jeszcze czy gracz stoi na podłożu gdy chce skoczyć - ale zaraz to dodamy. Jest kilka sposobów by to sprawdzić, ale żeby specjalnie nie gmatwać sprawy, dodamy detektor, który zawsze będzie pod Graczem i będziemy testowac czy nachodzi na tło (overlapping the backdrop) czy nie.
Stwórz nowy obiekt, tak samo szeroki jak obiekt gracza i wysoki na jeden piksel (jeden piksel wystarcza, ponieważ z użyciem fastloopa naszą metoda nie ma niebezpieczeństwa, że "przeoczymy" tło). Jako, że Gracz właściwie nidy nie będzie nachodził na tło, a nawet jeśli to fastloop go "cofnie", musimy umieścić detektor tuż pod Graczem by, gdy Gracz będzie stał na ziemi, detektor nachodził na tło.
Nazwij obiekt "Detector". Tego obiektu nie powinno być widać podczas gry, ale póki co testujemy czy wszystko działa, więc zostaw funkcję "Visible at start" (widoczny na początku) zaznaczoną i włącz Event Editor. Do wszystkich zdarzeń zaczynających się od "On loop 'gravity'" dodaj akcję ustawiającą detektor tuż pod graczem.
Pamiętaj by akcja ustawiająca detektor pod Graczem była w każdym zdarzeniu naszej pętli. To jest haczyk używania fastloopa - musisz pamiętać by aktualizować wszystkie ważne zdarzenia, inaczej twój silnik może mieć problemy z działaniem.
Detektor musi być sprawdzany zawsze gdy zostanie wciśnięty klawisz skoku. To bardzo łatwe - po prostu zmień zdarzenie "Player presses Fire 1" na takie:
| 7 |
• Player presses Fire 1
• Detector is overlapping a backdrop
Set Grav("Player") to -10
|
To sprawia, że Gracz może skoczyć tylko wtedy gdy stoi na podłożu (a detektor nachodzi na podłoże). Włącz grę by sprawdzić efekty.
Ruch Horyzontalny (Poziomy)
Teraz gdy masz już działającą grawitację, ruch poziomy/horyzontalny, czyli na boki jest bardzo podobny, a nawet łatwiejszy do zrobienia, ponieważ w większości platformówek postać porusza się ze stałą prędkością, a wiec nie zwalnia ani nie przyśpiesza (co oczywiście będziesz mógł potem dodać). Kolejna pętla fastloopa będzie używana do obsługiwania ruchu poziomego.
Dodaj nową "alterable value" do obiektu Gracza i nazwij ją "Horiz" - będziemy jej używać do przechowywania ilości pikseli jakie gracz ma pokonać po horyzontalnej. Stwórz kolejną grupę zdarzeń i nazwij ją "Horizontal Movement" (Ruch Poziomy) albo coś podobnego. Potem dodaj w niej następujące eventy:
| Horizontal |
| 8 |
• Repeat while player presses Right
Set Horiz("Player") to 3
|
| 9 |
• Repeat while player presses Left
Set Horiz("Player") to -3
|
| 10 |
• X Repeat while player presses Left
• X Repeat while player presses Right
Set Horiz("Player") to 0
|
| 11 |
• Horiz("Player") <> 0
Start loop "horiz" ABS(Horiz("Player")) times
|
| 12 |
• On loop "horiz"
Set X position of Player to X("Player") + (Horiz("Player")/ABS(Horiz("Player")))
Ustaw detektor pod Graczem
|
| 13 |
• On loop "horiz"
• Player is overlapping an obstacle background
Set X position of Player to X("Player") - (Horiz("Player")/ABS(Horiz("Player")))
Ustaw detektor pod Graczem
Set Horiz("Player") to 0
Stop loop "horiz"
|
Większość z nich jest taka sama jak dla grawitacji, więc możesz je po prostu skopiować i wkleić zmieniając nazwę zmiennej. Jedynym nowym zdarzeniem jest to z dwoma zanegowanymi (Negate) warunkami "Repeat while player presses" (Powtarzaj, gdy gracz wciska) - to po to, by Gracz się zatrzymał gdy nie jest wciśnięty żaden kierunek.
Używam raczej zagmatwanego wzoru w dwóch zdarzeniach "On loop 'horiz'" po to by jednocześnie obsługiwać ruch w lewo i prawo i oszczędzić na ilości eventów. Dodawanie wartości (Horiz("Player")/ABS(Horiz("Player"))) do istniejącej pozycji X po prostu dodaje 1 or -1 zależnie od tego, czy wartość Horiz("Player") jest dodatnia czy ujemna - wartość Horiz jest dzielona przez jej wartość bezwzględną dając +1 jeśli jest dodatnia i -1 jeśli jest ujemna. Dzięki temu mamy jedno zdarzenie kontrolujące oba kierunki zamiast dwóch robiących praktycznie to samo, dla różnych kierunków.
Zauważ też, że musieliśmy ustalać pozycję detektora z zdarzeniach "On loop 'Horiz'" - jeżeli byśmy tego nie zrobili detektor zostawałby w miejscu.
Sprawdź teraz jak działa twoja gra - ruch w lewo i w prawo powinien działać bez żadnych problemów z blokowaniem się w ścianach.
Zmiana Ruchu
Ruch który stworzyliśmy jest "szybki" tak jak grawitacja - nie możesz podskoczyć zbyt wysoko, a grawitacja bardzo szybko ściąga Gracza w dół. Aby to zmienić, możemy zedytować zdarzenia, które obsługują grawitację i skoki.
Zmień pierwsze zdarzenie które stworzyłeś (Always: Add 1 to Grav) na takie:
| 1 |
• Grav("Player") < 10
Set Grav("Player") to Grav("Player") + 0.5
|
To sprawi, że, po pierwsze, limit "ściągania" grawitacji to 10 pikseli na cykl. To sprawi, że nie ważne z jak wysoka spadać będzie gracz, osiągnie najwyżej 10 pikseli "prędkości końcowej". Po drugie, grawitacja będzie zmieniała się wolniej więc efekt nie będzie tak ostry.
Powód dla którego używam "Set" (Ustaw) zamiast "Add" (Dodaj) wynika z błędu, który miały wczesne wersje MMF2 z obsługą liczb po przecinku. Jeżeli używasz build'a 243 lub nowszego, używanie "Add 0.5 to Grav("Player")" powinno dać taki sam efekt.
W ten sam sposób możesz zmienić horyzontalną prędkość Gracza - pozmieniaj kilka wartości i zobacz jakie efekty otrzymasz. Możesz dodac także ciensze platformy by zobaczyć jak szybko fastloop radzi sobie z wykrywaniem kolizji.
Masz już ruch platformowy, który obsługuje dwa kierunki i skok, oraz zapobiega przed zablokowaniem się Gracza w ścianie lub platformie. Właściwie mógłbyś już stworzyć grę platformową używając tego silnika, jednakże jest kilka usprawnień, które można dodać. A skoro jest to silnik oparty w pełni na zdarzeniach, możemy zmienić i dodać ich tak wiele jak chcemy.
O usprawnieniach do tego ruchu można poczytać tutaj (część pierwsza). Część druga wkrótce. Wkrótce także przykładowy plik. Już w tej chwili przykład w języku angielskim można pobrać ze strony Clickteamu.
Ostatnio edytowane 15 kwietnia 2009, 16:32 przez
PoW