Lekcja 3 – Poruszanie obiektami

Na początek małe wyjaśnienie. Obiekty na ekranie nie poruszają się. Nigdy. Zaskoczony? Jednak to prawda. Ekran komputera czy telefonu potrafi wyświetlać tylko statyczne obrazy. Jednak potrafi robić to bardzo szybko – w Corona SDK obraz ekranu jest odświeżany trzydzieści razy na sekundę. Oznacza to, że co 0.033 sekundy (33 milisekundy) obraz na ekranie jest ponownie malowany. Jeżeli obraz po odświeżeniu będzie się nieznacznie różnił położeniem niektórych elementów – uzyskamy wrażenie ruchu.

Teraz troszkę teorii, ale tylko tyle, ile trzeba dla zrozumienia dalszej konstrukcji i działania programu. Telefon, tablet czy komputer potrafi reagować na różne zdarzenia, np. na dotknięcie ekranu (w Corona SDK zdarzenie to nazywa się „touch”) lub  puknięcie w ekran („tap”). Niektóre zdarzenia są generowane automatycznie przez urządzenie w celu realizacji różnych funkcji, np. wyświetlanie powiadomień.

Jak wspominałem wcześniej, ekran w Corona SDK jest odmalowywany (fachowo: odświeżany) trzydzieści razy na sekundę. Przed każdym odświeżeniem jest automatycznie (niezależnie od naszego programu) generowane zdarzenie „enterFrame”. Przed odświeżeniem ekranu system sprawdza, czy jest jakaś funkcja, która oczekuje na to zdarzenie. Jeśli tak, wykonuje ją przed odświeżeniem ekranu. Funkcja oczekująca na zdarzenie określa się jako event hadler, czyli „obsługiwacz zdarzenia”. I najważniejsze: do każdego zdarzenia programista może „doczepić” własną funkcję.

Za zdarzenia generowane przez system (i parę innych rzeczy) odpowiada obiekt Runtime. Jest to obiekt specjalny, zawsze obecny w trakcie działania programu, służący m.in. do komunikacji z systemem oraz do generowania i obsługi zdarzeń.

Teraz trudne przejście, więc wyjaśnię każdy szczegół.

Do dowolnego obiektu można dodać reakcję na zdarzenie za pomocą funkcji addEventHandler (czyli dodajObsługęZdarzenia). Funkcja ta ma dwa parametry – pierwszy to nazwa zdarzenia, do którego chcemy podczepić naszą funkcję, a drugi – nazwa funkcji. Wygląda to tak:

Obiekt Runtime (czyli taki nadzorca wykonywania programu) przy każdym zdarzeniu „enterFrame” sprawdza, czy jakaś funkcja nie chciałaby obsłużyć tego zdarzenia. Jeśli tak, funkcja ta jest wykonywana przed malowaniem. Po wykonaniu powyższej linii taką funkcją będzie naszaFunkcja.

Teorii trochę było, teraz czas na praktykę. Na początek poruszymy planetę. Dzięki temu otrzymamy wrażenie ruchu statków.

Dodaj na końcu programu linię

Program natychmiast przestanie działać, ponieważ funkcja ruszajObiektami nie jest jeszcze gotowa 🙂

Funkcja ta ma poruszać obiektami, na początek planetą. Należy ją wstawić przed poleceniem addEventListener, tak aby była już znana systemowi (zdefiniowana) w momencie jej przypisania do zdarzenia.

Treść funkcji jest bardzo prosta. Zmniejszamy wartość współrzędnej x o 1 (pixel). Ponieważ będzie się to działo 30 razy na sekundę, planeta zacznie przesuwać się w lewo.

Efekt powinien być taki:

kr

Nieźle ale… planeta opuściła ekran i nie ma zamiaru wrócić. Trzeba ją uratować 😉

Lewa krawędź ekranu ma współrzędną 0 (czasami nieco mniej lub więcej, ale teraz to nieistotne). Ponieważ przy każdym odświeżeniu ekranu przesuwamy ją o jeden pixel w lewo, to po chwili wyjeżdża ona z ekranu. Kiedy jest na pozycji -150, na pewno nie widać na ekranie już ani kawałka planety. Wtedy właśnie przerzucimy ją na prawą stronę ekranu, w miejsce odległe o 150 pixeli od prawej krawędzi. Funkcja ruszajObiektami będzie wyglądała teraz tak

Dodaliśmy instrukcję warunkową. Jeśli (if) współrzędna x planety będzie mniejsza niż -150 (czyli ponad 150 pikseli za lewą krawędzią ekranu), to (then) przerzucamy ją o 150 pixeli za prawą krawędź (współrzędna prawej krawędzi to display.actualContentWidth).

Planeta uratowana.

kr2

Takim samym sposobem poruszymy statek przeciwnika, rozbudowując funkcję ruszajObiektami.

Planeta się dostojnie przesuwa, a statek przeciwnika lata…

kr3

… ale w zbyt przewidywalny sposób. Aby było ciekawiej, będziemy zmieniać jego położenie przy ‚przerzucaniu’ na prawą stronę ekranu, losując współrzędną y. Za każdym razem statek wyleci zza prawej krawędzi ekranu na innej wysokości. Posłuży do tego funkcja losująca – math.random(min, max). Funkcja ta zwraca liczbę losową całkowitą z zakresu od min do max. A zatem dołożenie linii

w odpowiednim miejscu spowoduje, że przeciwnik pojawi się ponownie na innej, losowo dobranej wysokości (z zachowaniem odstępu 50 pikseli od góry i od dołu, aby nie ucinało obrazka statku).

Na koniec zabiegi poprawiające odbiór gry. ‚Rozmażemy’ (blur) tło, aby zwiększyć wrażenie głębi, i powiększymy planetę, aby polepszyć wrażenie ruchu statku na jej tle. Corona SDK udostępnia mnóstwo funkcji do przetwarzania grafiki. Użyjemy filtru rozmazującego obraz:

I powiększymy planetę, aby była bardziej majestatyczna. Skalowanie w pionie i w poziomie można robić niezależnie:

Efekt powinien wyglądać tak:

kr5

Nie jest źle, jak na 22 linie (nie liczę komentarzy i pustych linii). Na koniec lekcji całość kodu:

W następnej lekcji poruszymy również naszym statkiem – w końcu celem gry ma być unikanie zderzeń 🙂

Poprzednia lekcja | Następna lekcja