|
|
|
||
|
|
|||
| Kod w klikach, czyli pierwsze kroki z Lua | |||
|
autor: Andy
Największym atutem programów ze stajni Clickteamu jest możliwość tworzenia aplikacji bez pisania żadnego kodu. To zdecydowanie zaleta, gdyż w łatwy sposób możemy szybko coś zrobić. Czy zawsze? Niekoniecznie - choć klikanie jest fajne, czasem kod jest wygodniejszy. Niestety domyślnie (w przeciwieństwie do np. Game Makera, który oferuje swój własny język skryptowy GML) żaden program Clickteamu takiej możliwości nie daje. Na szczęście społeczność nie śpi i powstało wiele rozszerzeń, które umożliwiają programowanie w MMF'ie. Python, .net, basic, lua. Ja zajmę się tym ostatnim. Do obsługi Lua powstało kilka plugin'ów, jednak tylko jedno z nich zasługuje na naszą uwagę – Xlua i to właśnie z niego będziemy korzystać. Do roboty!
Uwaga: do zrozumienia konieczna jest umiejętność programowania w czymkolwiek (i nie, HTML to nie programowanie).
Na początek coś łatwego. Zrobimy wymyśloną przez brytyjskiego matematyka Johna Conwaya w 1970 „Grę w życie”. Gra toczy się na nieskończonej planszy podzielonej na kwadratowe komórki. Komórka może być martwa lub żywa w zależności od ilości sąsiadów (8 pól dookoła danej komórki). • Martwa komórka, która ma dokładnie 3 żywych sąsiadów, staje się żywa w następnej jednostce czasu (rodzi się) • Żywa komórka z 2 albo 3 żywymi sąsiadami pozostaje nadal żywa; przy innej liczbie sąsiadów umiera (z "samotności" albo "zatłoczenia").
Tak więc w tej grze nie ma graczy w dosłownym znaczeniu. My tylko ustalamy początkowy stan komórek, a dalej jedynie obserwujemy przebieg (ew. integrujemy dostawiając lub odejmując komórki). Nie będziemy komplikować i nasza plansza będzie skończona. Zanim jednak się zabierzemy za właściwą grę w życie, krótkie wprowadzenie do tego języka skryptowego w MMF'ie. Gdy zaczynałem pisać ten artykuł, zastanawiałem się „jak rysować planszę?”. Ostatecznie zdecydowałem się na Draw Object. Żywa komórka to będzie kwadracik zamalowany, martwa to puste pole.
1. Dodaj obiekt Xlua oraz Draw Object.
2. Dodaj następujące zdarzenie:
3. Zaraz wszystko się wyjaśni. Kliknij dwukrotnie na obiekt Xlua i wpisz kod oraz zaznacz checkBoxa „Run at start”:
4. Odpal aplikację i... jeśli wszystko dobrze zrobiłeś ujrzysz kwadrat w punkcie (20; 20) o boku 32px.
Q: Co tu się stało? A: To tylko prosty kod Lua, który wydaje polecenie MMF'owi, które je obsługuje tak jak to napisaliśmy.
Q: Nigdy nie programowałem, zrozumiem to? A: Jeśli nigdy wcześniej w niczym nie programowałeś (jeszcze raz - HTML to nie jest programowanie), to możesz mieć problem ze zrozumieniem. Tak więc od początku. W Xlua napisaliśmy funkcję o nazwie test, która jest bezparametrowa, którą potem wywołujemy na początku ramki. W tej funkcji wywołujemy kolejną funkcję MF_RysujKomorke z parametrami: 20, 20, 52, 52. Będziemy ją obsługiwać z poziomu zdarzeń. W zdarzeniach mamy: „w przypadku funkcji MF_RysujKomorke → Draw Object: przesuń wskaźnik na pozycję X równą pierwszemu parametrowi, pozycję Y drugiemu parametrowi i potem narysuj prostokąt. Proste? Proste i oczywiste. Nic skomplikowanego.
Q: Czy funkcje, które będą obsługiwane z poziomu zdarzeń muszą zaczynać się od MF_? A: Nie, to tylko dobry nawyk, który ułatwia czytanie kodu. Skoro mamy już podstawy, zacznijmy pisać grę (nie usuwaj tego pierwszego zdarzenia).
1. Edytuj kod w Xlua i wpisz (funkcję test() możesz usunąć):
Ten kod rzeczywiście jest już nieco bardziej zawiły, ale wcale nie trudny! Na początku deklarujemy tablicę o nazwie plansza, zmienne ILOSC i ROZMIAR, a potem funkcję start, która przyjmuje parametr ilość i rozmiar. Ilość to liczba komórek w rzędzie, a rozmiar to rozmiar jednej komórki. Potem w tej funkcji ustawiamy w tablicy wartości 0 dla wszystkich komórek.
Q: Nie mogę sobie wyobrazić tej tablicy... A: Dla ilości = 5 wygląda tak:
2. Ustaw Draw Object w punkcie (0; 0) i ustaw jego szerokość i wysokość na 400px. Dodaj zmienne globalne w MMFie: IloscKomorek i Rozmiar
3. Dodaj zdarzenie (usuń poprzednie Start of Frame)
4. Odpal aplikację. Jeśli wszystko jest dobrze... to nic nie powinno się zadziać. W końcu nigdzie jeszcze nie napisaliśmy co (Widocznego) ma się stać.
5. Dopisz kolejną funkcję:
Ta funkcja przechodzi przez wszystkie komórki i jeśli jakaś jest ustawiona na 1 (żywa) wywołuje funkcję MF_RysujKomorke (już nam znaną) podając punkt w którym ma się pojawić i jej rozmiar (precyzyjniej: punkt, w którym kończy się komórka (kwadrat), czyli współrzędne początku + rozmiar jednej komórki. W Lua tablice zaczynają się od 1, dlatego musimy odjąć od współrzędnych 1 (w przeciwnym razie pierwsza komórka zaczynałaby się w punkcie 1*ROZMIAR, np. (40, 40), a chcemy aby zaczynała się w punkcie (0, 0))
6. Odpal aplikację teraz i... znowu nic. W końcu nigdzie nie wywołujemy funkcji rysuj(). Poza tym cała tablica jest pusta (wartości 0), więc warunek nigdy nie zostanie spełniony. Chcemy mieć możliwość przełączania stanu komórki klikając na nią. Tak więc dodaj zdarzenie:
Gdy klikniemy, wywołujemy funkcję przelacz (która jeszcze nie istnieje) z współrzędnymi myszki. Potem czyścimy Draw Object i wywołujemy znaną funkcję rysuj,
Funkcja przelacz:
Funkcja przelacz pobiera współrzędne myszki. Musimy ustalić, która komórka odpowiada tym współrzędnym, dlatego dzielimy je przez rozmiar. Ponieważ to może dać ułamek, zaokrąglamy go w górę funkcją wbudowaną math.ceil(liczba). Potem odpowiednio dana komórka przybiera wartość 0 (martwa) lub 1 (żywa).
7. Odpal aplikację i... działa! Klikasz – pojawia się kwadrat. Klikasz drugi raz – znika. No dobra, brakuje już tylko najważniejszego elementu gry w życia, czyli generowania kolejnych pokoleń. Przewiń trochę w górę i przypomnij sobie zasady gry w życia. Może sam postarasz się napisać odpowiednią funkcję?
8. Moja propozycja funkcji nastepnePokolenie():
Od początku. Potrzebujemy nową macierz o takim samym rozmiarze jak plansza z wartościami 0. Wystarczy skopiować kod z funkcji start(). Aby jednak kod był łatwiejszy w czytaniu podzieliłem go na funkcje, i tak funkcja stworzPlansze() zwraca macierz z wartościami 0. Za chwilę podam jej kod. Dalej przechodzimy przez wszystkie komórki i liczymy jej sąsiadów za pomocą funkcji policzSasiadow, która pobiera współrzędne komórki. Potem postępujemy zgodnie z regułami gry. „Jeśli komórka ma dwóch lub trzech sąsiadów i jest żywa (wartość 1), to dalej (na nowej planszy) dalej jest żywa”. „Jeśli komórka ma trzech sąsiadow i jest martwa (wartość 0), to ożywa (na nowej planszy)”. Potem już tylko aktualizujemy zmienną plansza.
Funkcja stworzPlansze() to kopiuj-wklej z funkcji start():
Q: Skoro ten sam kod jest w funkcji start() i w funkcji stworzPlansze() nie można tego skrócić? A: To jest nawet wskazane. Ładna funkcja start() wgląda teraz tak:
9. Funkcja policzSasiadow(x, y) jest zdecydowanie najbardziej zawiła. Sposobów liczenia jest wiele. Oto moja propozycja:
Na początku zmiennej liczba ustalamy wartość 0. Będzie ona przechowywała liczbę sąsiadów. Potem mamy pętlę, która przechodzi przez kolumnę z lewej, kolumnę, na której jest komórka i kolumnę z prawej. Musimy jednak pamiętać, że przy sprawdzaniu sąsiadów dla komórki (1; 4) zmienna i przybiera wartości 0, 1 i 2. Nie istnieje kolumna 0, dlatego musimy sprawdzić czy i jest większe od 0 i czy na pewno i jest mniejsze lub równe ilości kolumn. Potem kolejna pętla, która działa identycznie jak poprzednia, tylko dla wierszy. Podobnie jak wcześniej sprawdzamy czy wiersz istnieje (większy od 0 i mniejszy lub równy ilości wiersz). Jeśli te warunki są spełnione, sprawdzamy czy dana komórka żyje. Jeśli tak dodajemy jeden do zmiennej liczba. Jednak w ten sposób policzylibyśmy też komórkę, dla której sprawdzamy, a ona nie jest sąsiadem. Dlatego kolejny warunek „jeśli komórka żyje oraz i jest takie samo jak x oraz j jest takie samo jak y → odejmij 1 od liczby komórek”.
10. Musimy jeszcze jakoś wywołać funkcję nastepnePokolenie(). Dodaj zdarzenie:
11. Wreszcie możesz włączyć aplikację, narysuj jakiś kształt i powciskaj spację. Zobaczysz jak wyglądają kolejne pokolenia Twoich komórek. Niezbyt fascynujące? Ale za to ile wiedzy udało się przekazać!
Wszystko działa, ale musimy wprowadzić małą poprawkę w funkcji MF_RysujKomorke. Wszystko się wyjaśni, jeśli zrobisz ćwiczenie (patrz niżej). Poprawna funkcja rysuj() (a dokładniej jej jedna linijka) powinna wyglądać tak:
Jak widzisz teraz po prostu przekazujemy współrzędne komórki. To oczywiście wywołuje potrzebę zmiany zdarzenia:
Co nam to daje? Otóż teraz kod Lua nie ma pojęcia jak narysować daną komórkę. Przekazuje tylko informację, którą komórkę trzeba zamalować. Dzięki temu mamy oddzieloną logikę aplikacji od warstwy prezentacyjnej.
Podsumowanie
Cała logika została napisana w Lua. MMF służy tylko jako warstwa prezentacyjna. Dzięki temu łatwiej jest wprowadzać zmiany, a kod i zdarzenia są bardziej czytelne. Niestety operowanie na obiektach MMFa z poziomu Lua jest uciążliwe – gdy chcemy przesunąć obiekt, musimy wywołać funkcję, którą potem musimy obsłużyć w MMF'ie (tak jak z funkcją MF_RysujKomorke). Dla większej ilości obiektów to rzeczywiście męczące. Jednak tutaj objawia się potęga rozszerzenia Xlua, które umożliwia bezpośrednie działanie na obiektach MMFa... ale o tym następnym razem.
Ćwiczenie
1. W tej wersji do prezentowania macierzy z komórkami zastosowałem Draw Object. Spróbuj przerobić kod na obiekt aktywny. Zauważ, że dzięki małej poprawce wyżej nie musimy w ogóle ruszać kodu Lua.
od redakcji: Kurs w formie pliku tekstowego zachęcamy do korzystania ze strony: http://korczynskij.pl/shared/klikod/
|
|||
|
Copyright (c) 2005-2009 Ślimaczek |
|||