Zmiany

Scenariusz 4 - Spaceshooter

Dodane 17 883 bajty, 18:38, 11 mar 2015
Utworzono nową stronę "[[Category:Scenariusze MIT App Inventor]] [[Category:Scenariusze CoderDojo]] == Cele == Stworzymy grę typu Spaceshooter. Scenariusz naszej gry obejmuje zaprogramowanie..."
[[Category:Scenariusze MIT App Inventor]] [[Category:Scenariusze CoderDojo]]
== 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.'''
[[Plik:Spaceshooter_1_opt.jpeg|center]]
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).'''
[[Plik:Spaceshooter_2_opt.jpeg|center]]
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.'''
[[Plik:Spaceshooter_3_opt.jpeg|center]]
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.'''
[[Plik:Spaceshooter_4_opt.jpeg|center]]

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:
[[Plik:Spaceshooter_spascehip_opt.png|center]]
Źródło: http://www.easyicon.net/language.en/15462-kspaceduel_spaceship_icon.html
[[Plik:Spaceshooter_5_opt.jpeg|center]]
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).'''
[[Plik:Spaceshooter_6_opt.jpeg|center]]
[[Plik:Spaceshooter_7_opt.jpeg|center]]
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).'''
[[Plik:Spaceshooter_8_opt.jpeg|center]]
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).'''
[[Plik:Spaceshooter_9_opt.jpeg|center]]

=== 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).'''
[[Plik:Spaceshooter_10_opt.jpeg|center]]
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.
[[Plik:Spaceshooter_11_opt.jpeg|center]]
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.
[[Plik:Spaceshooter_12_opt.jpeg|center]]
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.
[[Plik:Spaceshooter_13_opt.jpeg|center]]
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].'''
[[Plik:Spaceshooter_14_opt.jpeg|center]]
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).'''
[[Plik:Spaceshooter_15_opt.jpeg|center]]
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).'''
[[Plik:Spaceshooter_16_opt.jpeg|center]]
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.
[[Plik:Spaceshooter_17_opt.jpeg|center]]
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.
[[Plik:Spaceshooter_18_opt.jpeg|center]]
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.
[[Plik:Spaceshooter_19_opt.jpeg|center]]
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.
[[Plik:Spaceshooter_21_opt.jpeg|center]]
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).
[[Plik:Spaceshooter_22_opt.jpeg|center]]
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.'''<br />
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).'''
[[Plik:Spaceshooter_23_opt.jpeg|center]]
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.
[[Plik:Spaceshooter_34_opt.jpeg|center]]
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).
[[Plik:Spaceshooter_25_opt.jpeg|center]]
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.
[[Plik:Spaceshooter_26_opt.jpeg|center]]
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:
[[Plik:Spaceshooter_27_opt.jpeg|center]]
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.<br />
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.'''<br />
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.'''
[[Plik:Spaceshooter_28_opt.jpeg|center]]
[[Plik:Spaceshooter_29_opt.jpeg|center]]
Dodajmy teraz do naszej instrukcji wspomniane wcześniej funkcje. Ponownie wykorzystujemy tutaj settery, których użyliśmy już wcześniej.
[[Plik:Spaceshooter_30_opt.jpeg|center]]
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ół.<br />
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.
[[Plik:Spaceshooter_31_opt.jpeg|center]]
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.
[[Plik:Spaceshooter_32_opt.jpeg|center]]
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.
[[Plik:Spaceshooter_33_opt.jpeg|center]]
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.<br />

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.'''
[[Plik:Spaceshooter_34_opt.jpeg|center]]
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ł.
[[Plik:Spaceshooter_35_opt.jpeg|center]]
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.
Biurokrata, administrator
530
edycji