Spaceshooter

Z Zasoby CoderDojo
Skocz do: nawigacji, wyszukiwania

Cele

Stworzymy grę typu Spaceshooter. Scenariusz naszej gry obejmuje zaprogramowanie sterowania statkiem kosmicznym za pomocą akcelerometru (akcelerometry poznaliśmy tworząc Squasha), oprócz tego zajmiemy się również zaprogramowaniem kolizji obiektów, które będą znajdowały się na drodze naszego statku oraz ich poruszania.

Spaceshooter

Rozpoczęcie pracy

Po wejściu na stronę http://appinventor.mit.edu wybierzmy Create, by uruchomić App Inventor. Następnie przejdźmy do zakładki My Projects (1), gdzie znajdziemy wszystkie nasze projekty (upewnijmy się tylko, czy jesteśmy zalogowani na nasze konto Google). W celu rozpoczęcia pracy nad nowym projektem kliknijmy na Start new project (2), i wpiszmy w oknie jego nazwę, np. Space_shooter.

Spaceshooter 1 opt.jpeg

Nastąpi teraz automatyczne przejście do okna budowy aplikacji.

Projektowanie interfejsu

Zacznijmy od zmiany właściwości komponentu Screen1 - w oknie Properties zmieńmy kolor tła tego komponentu na czarny (1) oraz ustawmy orientację ekranu - tutaj wybierzmy Portrait, czyli pionowy (2).

Spaceshooter 2 opt.jpeg

Następnie dodajmy do naszej aplikacji komponent Canvas (1). Wybierzmy go z grupy Drawing and Animation w oknie Palette i przeciągnijmy na obszar ekranu w oknie Viewer.

Spaceshooter 3 opt.jpeg

Po tym, jak dodaliśmy komponent Canvas1, po którym będą poruszały się obiekty, przejdźmy do ustawienia jego właściwości.

Zmieńmy kolor tła tego elementu na czarny (1) oraz ustawmy jego szerokość i wysokość tak, by przejmował te wartości z nadrzędnego komponentu, czyli Screen1. W tym celu zmieńmy parametry Width (szerokość) oraz Height (wysokość) na Fill parent.

Spaceshooter 4 opt.jpeg

Teraz zajmiemy się umieszczeniem w aplikacji statku kosmicznego. W tym celu dodajmy do obszaru ekranu aplikacji komponent ImageSprite, z grupy Drawing and Animation (1).

Potrzebujemy jeszcze ilustracji statku, którą wykorzystamy w naszej grze. Możemy wykorzystać w tym celu wyszukiwarkę Google wpisując takie hasła jak, spaceship sprite lub spaceship ico. Przeszukując materiały z wolną licencją można natrafić chociażby na taki statek:

Spaceshooter spascehip opt.png

Źródło: http://www.easyicon.net/language.en/15462-kspaceduel_spaceship_icon.html

Spaceshooter 5 opt.jpeg

Pamiętajmy, by nasz obrazek miał przezroczyste tło - plik musi być więc w formacie PNG lub GIF (pliki JPG nie obsługują przezroczystości). Zapiszmy więc plik, który chcemy wykorzystać jako statek na komputerze i dodajmy go do naszej aplikacji. W tym celu kliknijmy na Upload File w oknie Media (1). Wskażmy miejsce, gdzie znajduje się zapisany plik i kliknijmy OK. Po poprawnym dodaniu pliku zobaczymy jego nazwę w oknie Media (2).

Spaceshooter 6 opt.jpeg
Spaceshooter 7 opt.jpeg

Teraz ustawmy właściwości komponentu ImageSprite1, czyli naszego statku kosmicznego. Ustawmy jego obraz w polu Picture (1) na ten, który wcześniej załadowaliśmy w oknie Media. Następnie wyłączmy obracanie (2),a wysokość oraz szerokość ustawmy na 48 pikseli (3).

Spaceshooter 8 opt.jpeg

Jeśli komponent ImageSprite1 został poprawnie skonfigurowany, powinniśmy zobaczyć nasz statek kosmiczny w obszarze okna aplikacji, tak, jak na ilustracji obok. Następnym krokiem będzie dodanie sterowania za pomocą akcelerometru do naszej gry. Komponent AccelerometerSensor znajdziemy w grupie Sensors (1). Przeciągnijmy go na obszar ekranu naszej gry i dodajmy do aplikacji. Komponent ten, jako że jest niewidoczny, pojawi się w sekcji Non-visible components (2).

Spaceshooter 9 opt.jpeg

Program sterowania statkiem

Stwórzmy pierwszą instrukcję. Będzie ona odpowiadała za sterowanie statkiem kosmicznym poprzez przechylanie urządzenia mobilnego. Przejdźmy zatem do zakładki Blocks (1).

Spaceshooter 10 opt.jpeg

W oknie Blocks odnajdźmy komponent AccelerometerSensor1 (1). Po kliknięciu na niego otwarte zostanie okno z instrukcjami właściwymi dla tego komponentu. Wybierzmy blok when[AccelerometerSensor1].AccelerationChanged (2) i dodajmy go do naszego obszaru bloków.Element ten jest słuchaczem (czyli funkcja when - kiedy) i będzie sprawdzał, czy urządzenie zmieniło swoje położenie Jest to funkcja, która udostępnia nam trzy parametry: przyspieszenie w osiach X, Y i Z. Te właśnie parametry, będące zmiennymi lokalnymi, użyte zostaną teraz przez nas do poruszania się naszym statkiem.

Spaceshooter 11 opt.jpeg

Zacznijmy od bloku, wprowadzającego statek w ruch. Zaznaczmy więc komponent ImageSprite1 (1), który jest naszym statkiem i odszukajmy blok call[ImageSprite1].MoveTo. Dołączmy ten blok do słuchacza, którego dodaliśmy chwilę wcześniej.

Spaceshooter 12 opt.jpeg

Zmienne lokalne w słuchaczu akcelerometru przyjmują wartości dziesiętne, w przedziale od -10 do 10, w zależności od strony, w którą przechylimy urządzenie. Użyjemy więc ich do zmiany aktualnej pozycji duszka o aktualny odczyt z czujnika. Jeśli statek ma teraz współrzędne x=150 y=150 to będziemy odpowiednio dodawać lub odejmować od tych współrzędnych odczytane wartości.

Spaceshooter 13 opt.jpeg

Kliknijmy na komponent ImageSprite1 i spośród dostępnych dla niego bloków wybierzmy ten, który będzie odczytywał wartość X tego komponentu, czyli [ImageSprite1].[X] (1). Potrzebujemy również drugiego bloku dla wartości Y, czyli [ImageSprite1].[Y].

Spaceshooter 14 opt.jpeg

Teraz przejdźmy do grupy Math (1), gdzie znajdziemy klocki funkcji matematycznych. Na obszar roboczy dodajmy bloki dodawania (2), odejmowania (3), oraz zaokrąglania - round (4).

Spaceshooter 15 opt.jpeg

Potrzebujemy również funkcji, która będzie odczytywała wartości zmiennych lokalnych. W tym celu użyjemy funkcji get[ ] (2), którą znajdziemy w grupie Variables (1).

Spaceshooter 16 opt.jpeg

Nasza kompletna instrukcja powinna wyglądać tak, jak na poniższej ilustracji. Jak to działa?

  • X będzie przybierał wartość: aktualna pozycja duszka na osi X - zaokrąglony odczyt ze zmiany położenia osi X.
  • Y będzie przybierał wartość: aktualna pozycja duszka na osi Y + zaokrąglony odczyt ze zmiany położenia osi Y.

Element round jest nam potrzebny po to, by aplikacja uzyskiwała tylko wartości całkowite z odczytywanych parametrów. W przypadku gdybyśmy nie użyli tego elementu, statek drgałby nawet przy minimalnych wychyleniach urządzenia. Różnica w wartościach X i Y wynika tylko z punktu odniesienia, jakiego używa urządzenie.

Spaceshooter 17 opt.jpeg

Dzięki tym kilku bloczkom nasz statek kosmiczny zacznie się poruszać. Przejdźmy teraz do stworzenia funkcji, która będzie umożliwiała strzelanie laserem ze statku. Założenie jest takie, że po dotknięciu ekranu palcem statek wystrzeli wiązkę lasera, która po osiągnięciu górnej krawędzi zniknie. Przejdźmy zatem do wykonania tej instrukcji.

Stworzenie wiązki lasera

Przejdźmy ponownie do sekcji Designer, klikając odpowiedni przycisk na górnej belce okna programu. Dodajmy teraz kolejny ImageSprite, który znajdziemy w grupie Drawing and Animation (2). Właśnie z tego duszka zrobimy laser.

Spaceshooter 18 opt.jpeg

Teraz musimy przygotować i załadować do aplikacji plik graficzny lasera. Wystarczy nam mały prostokąt w dowolnym kolorze i rozmiarze 2x6 pikseli. Możemy go przygotować więc np. w programie Paint. Przejdźmy więc ponownie do sekcji Designer, klikając odpowiedni przycisk na górnej belce okna programu. Dodajmy teraz kolejny ImageSprite, który znajdziemy w grupie Drawing and Animation (2). Właśnie z tego duszka zrobimy laser. Następnie załadujmy grafikę lasera tak samo, jak dodaliśmy grafikę statku. Kliknijmy na UploadFile w palecie Media i wybierzmy naszą grafikę. Po dodaniu grafiki w oknie Media zobaczymy drugi element.

Spaceshooter 19 opt.jpeg

Po tym, jak dodaliśmy komponent ImageSprite2 oraz załadowaliśmy drugi plik graficzny, możemy przejść do ustawienia właściwości naszego duszka. Zatem w polu Properties dla naszego komponentu ustawmy czas odświeżania (Interval) na 20 (1). W polu Picture wczytajmy plik graficzny (2), wyłączmy rotację obiektu (3), aby obiekt się nie obracał i nie zmieniał swojej orientacji oraz wyłączmy jeszcze widoczność naszego obiektu (4). Tę ostatnią wyłączamy po to, by duszek nie był widoczny po starcie aplikacji, a dopiero po dotknięciu ekranu, zaś czas odświeżania będzie nam potrzebny do poruszania duszkiem. Zmieńmy jeszcze nazwę naszego komponentu klikając na przycisk Rename (5). Nazwijmy go DuszekLaser. Ułatwi nam to późniejszą pracę przy tworzeniu instrukcji.

Spaceshooter 21 opt.jpeg

Teraz zajmijmy się dodaniem instrukcji, która umożliwi nam strzelanie laserem, gdy dotkniemy ekranu. Zacznijmy od słuchacza (warunek when), który będzie reagował, kiedy stukniemy w ekran, a ściślej mówiąc, kiedy dotkniemy obszaru komponentu Canvas1. Wróćmy zatem do zakładki Blocks i element when[Canvas1].TouchDown (2).spośród bloków dostępnych dla komponentu Canvas1 (1).

Spaceshooter 22 opt.jpeg

Jak będzie działał nasz laser? Po dotknięciu ekranu laser powinien przyjąć aktualne współrzędne statku, stać się widoczny oraz ustawić kierunek na 90 stopni, a także otrzymać prędkość. Parametry ustawmy ustawimy za pomocą klocków w grupie DuszekLaser, zaś współrzędne statku weźmy z grupy ImageSprite1.
Użyjmy klocków z funkcją set (1), czyli ustaw (nazwijmy je setterami), które będą ustawiały odpowiednie wartości. Nasze settery są w zasadzie identyczne - możemy więc bazować na jednym i go duplikować, zmieniając tylko niektóre parametry. Część z nich - np. Visible (widoczność) przyjmują tylko wartości true/false (prawda/fałsz) (2) - znajdziemy je w grupie Logic w oknie Blocks. Do pobierania wartości służą jasnozielone klocki z wypustką po lewej stronie, nazwijmy je getterami od słowa get - pobierać (3).

Spaceshooter 23 opt.jpeg

Kompletna instrukcja powinna wyglądać tak, jak na ilustracji powyżej. Sekcja z ustawianiem wartości ma taką postać, ponieważ chcemy, by laser wychodził dokładnie ze środka naszego statku. W tym celu wykorzystamy szerokość statku dzieloną na połowę. Możemy teraz sprawdzić, jak wyglądają efekty naszej pracy. Zauważymy, że laser zachowuje się nieco dziwnie. Po stuknięciu w ekran zostanie wystrzelony, ale kiedy stukniemy ponownie, laser zniknie z ekranu i nowa wiązka pojawi się przy statku. Musimy dodać więc do naszej instrukcji warunki sprawdzające, czy DuszekLaser jest widoczny oraz czy laser nie dotyka górnej krawędzi. Ta druga funkcja będzie odpowiedzialna za ukrywanie duszka po to, byśmy mogli go ponownie użyć. Przejdźmy więc do kategorii Control, gdzie znajdziemy interesujący nas warunek if (1), który wykorzystamy. Funkcja if (jeśli) będzie w naszym przypadku sprawdzała, czy duszek jest widoczny i w zależności od tego zwróci nam prawdę lub fałsz.

Spaceshooter 34 opt.jpeg

Instrukcja, którą dodaliśmy powinna wyglądać tak, jak na poniższej ilustracji (1). Zatem program sprawdzi, czy duszek jest widoczny - jeśli tak, to zwrócona zostanie wartość false (fałsz).

Spaceshooter 25 opt.jpeg

Teraz możemy przejść do dodania funkcji sprawdzającej, czy laser dotyka górnej krawędzi ekranu. Jeśli tak, to zostanie on ukryty. Zacznijmy od dodania słuchacza when[DuszekLaser].EdgeReached (1), czyli kiedy krawędź osiągnięta.

Spaceshooter 26 opt.jpeg

W tej funkcji możemy ustawić zmienną lokalną, której parametrem jest numer krawędzi, do której odnosi się funkcja. W naszym przypadku nie jest to potrzebne, ponieważ nas interesuje tylko jedna, górna - ponieważ laser leci wyłącznie do góry. Dodajmy więc pozostałe bloki, by nasza instrukcja wyglądała tak, jak na poniższej ilustracji:

Spaceshooter 27 opt.jpeg

Po tej zmianie laser nie będzie znikał pomiędzy stuknięciami w ekran, tylko będzie czekał, aż DuszekLaser zniknie z ekranu poprzez zderzenie się z górną krawędzią.

Stworzenie przeciwnika

Ostatnim krokiem w budowie naszej aplikacji będzie dodanie przeciwnika, do którego będziemy mogli strzelać. Po zderzeniu lasera z przeciwnikiem oba duszki (czyli laser i przeciwnik) znikną, zaś przeciwnik pojawi się w nowym, losowym miejscu.
Musimy oczywiście dodać komponent ImageSprite, z którego zrobimy naszego przeciwnika. Zróbmy to analogicznie, jak w przypadku duszków statku i lasera. Dodajmy więc komponent ImageSprite, przygotujmy grafikę (możemy ponownie poszukać odpowiedniej ilustracji w internecie), wgrajmy ją i przypiszmy duszkowi. Oprócz tego wyłączmy rotację, ustawić interwał na 10 oraz wyłączmy widoczność. Zmieńmy też nazwę naszego nowego duszka na DuszekPrzeciwnik.
Teraz przejdźmy do zakładki Blocks, by stworzyć odpowiednie instrukcje. Zacznijmy od przygotowania własnej procedury, która będzie losowała pozycję duszka przeciwnika oraz nadawała mu prędkość. Poza tym procedura ta włączy również widoczność duszka oraz ustawi jego kierunek. Przejdźmy więc do sekcji Prodedures (1) i dodajmy nową procedurę do, czyli wykonaj (2). Zmieńmy jeszcze nazwę naszej procedury, klikając na pole z jej nazwą (3) - wpiszmy ustaw_przeciwnika.

Spaceshooter 28 opt.jpeg
Spaceshooter 29 opt.jpeg

Dodajmy teraz do naszej instrukcji wspomniane wcześniej funkcje. Ponownie wykorzystujemy tutaj settery, których użyliśmy już wcześniej.

Spaceshooter 30 opt.jpeg

Ustawmy kolejno - widoczność duszka jako prawda, pozycję Y na 0 (czyli na górze ekranu). Użyjmy również funkcji random integrer, która losuje liczby całkowicie z podanego przedziału. Naszym przedziałem są wartości od 0 do szerokości ekranu ([Canvas].[Width]). Dzięki temu duszek otrzyma losową pozycję na osi X. Dodatkowo ustawiamy jeszcze heading na -90, czyli w dół.
Teraz możemy przejść do wykonania pozostałych instrukcji z wykorzystaniem naszej procedury. Po przejściu do grupy Procedures zobaczymy, że pojawiły się tam nowe bloki, w tym wywołanie naszej procedury, czyli call[ustaw_przeciwnika] (1). Wybierzmy więc ten blok.

Spaceshooter 31 opt.jpeg

Pierwsza, krótka instrukcja będzie odpowiadała za uruchomienie procedury ustaw_przeciwnika razem ze startem aplikacji. Przejdźmy więc do grupy Control i wybierzmy klocek when[Screen1].Initialize - czyli kiedy Screen1 zostanie uruchomiony, instrukcja zostanie włączona.

Spaceshooter 32 opt.jpeg

Gdybyśmy sprawdzili działanie aplikacji już teraz, moglibyśmy dostrzec, że duszek przeciwnika leci w dół i zatrzymuje się na dolnej krawędzi ekranu. Sytuacja jest nieco podobna do tej z laserem, dlatego musimy dodać obsługę ponownego losowania pozycji duszka przeciwnika, kiedy ten dotknie dolnej krawędzi. Instrukcja powinna wyglądać tak, jak na poniższej ilustracji.

Spaceshooter 33 opt.jpeg

W tym przypadku dodatkowo sprawdźmy jeszcze, czy krawędź, którą dotknie duszek, jest krawędzią dolną (przyjmuje ona wartość -1). Zatem teraz, kiedy duszek dotknie krawędzi i jeśli jest to krawędź dolna, to wywołana zostanie procedura call[ustaw_przeciwnika], zatem duszek się zresetuje i pojawi na górze.

Szybkimi krokami zbliżamy się do końca. Potrzebujemy jeszcze tylko instrukcji, która będzie odpowiadała za obsługę zderzenia lasera z przeciwnikiem. Użyjmy do tego funkcji when[DuszekPrzeciwnik].CollidedWith (1), która sprawdza spotkania ze sobą różnych obiektów. Ten blok znajdziemy rzecz jasna w grupie DuszekPrzeciwnik.

Spaceshooter 34 opt.jpeg

Jak możemy zauważyć, po najechaniu kursorem na element other, w tej funkcji mamy dostępną zmienną lokalną, sprawdzającą, z czym zderzył się obiekt. Dodajmy więc sprawdzanie, czy DuszekPrzeciwnik zderzył się z DuszekLaser, a jeśli tak, to wywołajmy utworzoną przez nas wcześniej funkcję resetującą przeciwnika oraz ustawmy widoczność lasera na fałsz. Spowoduje to zniknięcie przeciwnika i pojawienie się go w innym miejscu oraz zniknięcie lasera, byśmy mogli oddać ponowny strzał.

Spaceshooter 35 opt.jpeg

Nasza ostatnia instrukcja powinna wyglądać więc tak, jak na powyższej ilustracji. Po jej wykonaniu gra jest już gotowa.

Podsumowanie

Poznaliśmy zasady animacji ruchu postaci (duszków) oraz wiemy, jak rozpoznawać wychylenia urządzenia w dwóch płaszczyznach. Powtórzyliśmy sprawdzanie kolizji pomiędzy elementami gry, a także rozpoznawanie dotknięcia ekranu urządzenia.