Scenariusz 2 - Squash: Różnice pomiędzy wersjami
M Kelniarz (dyskusja | edycje) (→Scenariusz 2) |
M Kelniarz (dyskusja | edycje) (→Scenariusz 2) |
||
(Nie pokazano 12 wersji utworzonych przez 2 użytkowników) | |||
Linia 21: | Linia 21: | ||
'''<li>Squash - projektowanie interfejsu</li>''' | '''<li>Squash - projektowanie interfejsu</li>''' | ||
− | Po zablokowaniu obrotu ekranu przejdźmy do dodania komponentów. W naszej aplikacji wykorzystamy trzy | + | Po zablokowaniu obrotu ekranu przejdźmy do dodania komponentów. W naszej aplikacji wykorzystamy trzy elementy - wszystkie znajdziemy w grupie Drawing and Animation. Są to: |
<ol>'''<li>Canvas''' ''(zamknięty obszar)'' - jest to komponent ograniczający obszar animacji oraz rysowania. W obszarze tego komponentu poruszają się Ball oraz ImageSprite.</li> | <ol>'''<li>Canvas''' ''(zamknięty obszar)'' - jest to komponent ograniczający obszar animacji oraz rysowania. W obszarze tego komponentu poruszają się Ball oraz ImageSprite.</li> | ||
'''<li>Ball''' ''(piłka)'' - w naszej aplikacji to po prostu piłka, którą będziemy odbijać za pomocą paletki.</li> | '''<li>Ball''' ''(piłka)'' - w naszej aplikacji to po prostu piłka, którą będziemy odbijać za pomocą paletki.</li> | ||
Linia 68: | Linia 68: | ||
<ol><li>'''Ustawienie pliku graficznego''' - wygląd paletki będzie wczytany z pliku graficznego, który załadujemy do programu. Paletka bez załadowanej grafiki byłaby przezroczysta, a to zdecydowanie utrudniłoby nam grę. Musimy zatem przygotować dowolny plik graficzny, np. w formacie png i wczytać go do mediów aplikacji, by następnie przypisać do paletki. Kliknijmy więc na '''Upload File''' (1) w oknie '''Media''' i odszukajmy plik, który chcemy wczytać do programu. Następnie przechodzimy do okna '''Properties''' i tam w polu '''Picture''' z rozwijanej listy wybierzmy nasz plik. Plików multimedialnych nie możemy przypisać bezpośrednio do komponentów, stąd w pierwszej kolejności musieliśmy wczytać plik do biblioteki mediów.</li> | <ol><li>'''Ustawienie pliku graficznego''' - wygląd paletki będzie wczytany z pliku graficznego, który załadujemy do programu. Paletka bez załadowanej grafiki byłaby przezroczysta, a to zdecydowanie utrudniłoby nam grę. Musimy zatem przygotować dowolny plik graficzny, np. w formacie png i wczytać go do mediów aplikacji, by następnie przypisać do paletki. Kliknijmy więc na '''Upload File''' (1) w oknie '''Media''' i odszukajmy plik, który chcemy wczytać do programu. Następnie przechodzimy do okna '''Properties''' i tam w polu '''Picture''' z rozwijanej listy wybierzmy nasz plik. Plików multimedialnych nie możemy przypisać bezpośrednio do komponentów, stąd w pierwszej kolejności musieliśmy wczytać plik do biblioteki mediów.</li> | ||
<li>'''Wielkość i pozycja''' - po tym, jak wczytaliśmy już plik graficzny, przejdźmy do ustawienia pozostałych parametrów. Współrzędną X ustawmy na 100 pikseli, zaś Y - na 270 (3). Następnie parametry '''Width''' (szerokość) na 70 pikseli, a '''Height''' (wysokość) na 20 pikseli.</li></ol> | <li>'''Wielkość i pozycja''' - po tym, jak wczytaliśmy już plik graficzny, przejdźmy do ustawienia pozostałych parametrów. Współrzędną X ustawmy na 100 pikseli, zaś Y - na 270 (3). Następnie parametry '''Width''' (szerokość) na 70 pikseli, a '''Height''' (wysokość) na 20 pikseli.</li></ol> | ||
+ | |||
'''<li>Squash - programowanie aplikacji</li>''' | '''<li>Squash - programowanie aplikacji</li>''' | ||
Po tym, jak zakończyliśmy projektowanie interfejsu aplikacji, możemy zająć się stworzeniem odpowiedniego programu. Tym razem zbudowanie poprawnego kodu będzie wymagało od nas większej pracy niż w przypadku poprzedniej aplikacji. Tam wystarczyła nam tylko jedna instrukcja zbudowana z bloków, natomiast tutaj potrzebujemy ich kilka. Przejdźmy więc teraz do zakładki '''Blocks''', a poniżej, krok po kroku, omówimy wszystkie instrukcje. | Po tym, jak zakończyliśmy projektowanie interfejsu aplikacji, możemy zająć się stworzeniem odpowiedniego programu. Tym razem zbudowanie poprawnego kodu będzie wymagało od nas większej pracy niż w przypadku poprzedniej aplikacji. Tam wystarczyła nam tylko jedna instrukcja zbudowana z bloków, natomiast tutaj potrzebujemy ich kilka. Przejdźmy więc teraz do zakładki '''Blocks''', a poniżej, krok po kroku, omówimy wszystkie instrukcje. | ||
Linia 88: | Linia 89: | ||
[[Plik:s2-10.png]] | [[Plik:s2-10.png]] | ||
− | [[Plik:info.png | + | [[Plik:info.png]]''Wszystkie instrukcje, tak jak w Scratchu, podzielone są na kategorie oznaczone odpowiednimi kolorami, co ułatwia nawigację.'' |
− | ''Wszystkie instrukcje, tak jak w Scratchu, podzielone są na kategorie oznaczone odpowiednimi kolorami, co ułatwia nawigację.'' | + | |
'''Numeracja krawędzi ekranu w App Inventorze.''' | '''Numeracja krawędzi ekranu w App Inventorze.''' | ||
+ | |||
Przed momentem skonfigurowaliśmy uderzenie piłki w dolną krawędź ekranu, która jest oznaczona numerem -1. Skąd wziął się właśnie taki numer? Krawędzie w programie App Inventor mają takie oznaczenia, jakie zaprezentowano na poniższej ilustracji. Krawędź północna oznaczona jest numerem 1, północno-wschodnia numerem 2 i w ten sposób docieramy do krawędzi dolnej, która jest oznaczona numerem -1. | Przed momentem skonfigurowaliśmy uderzenie piłki w dolną krawędź ekranu, która jest oznaczona numerem -1. Skąd wziął się właśnie taki numer? Krawędzie w programie App Inventor mają takie oznaczenia, jakie zaprezentowano na poniższej ilustracji. Krawędź północna oznaczona jest numerem 1, północno-wschodnia numerem 2 i w ten sposób docieramy do krawędzi dolnej, która jest oznaczona numerem -1. | ||
[[Plik:s2-11.png]] | [[Plik:s2-11.png]] | ||
+ | |||
+ | '''Zderzenie piłki z krawędzią i odbicie piłki od krawędzi.''' | ||
+ | |||
+ | Teraz zaprogramujemy wydarzenie zderzenia piłki z krawędzią. Tutaj musimy rozróżnić dwa rodzaje krawędzi - krawędź boczną i krawędź dolną. Jeśli piłka zderzy się z krawędzią boczną, to zostanie odbita, a wartość jej prędkości zwiększy się o 1. Natomiast jeśli zderzy się krawędzią dolną, to nastąpi ponowne rozpoczęcie gry poprzez wywołanie odrębnej procedury, którą przygotujemy. | ||
+ | |||
+ | [[Plik:squash-9.png|600px]] | ||
+ | |||
+ | Najpierw sprawdzamy, czy piłka uderzyła w krawędź dolną (wartość edge wynoszącą -1). Krawędź -1 oznacza, że gracz przepuścił piłkę (nie odbił jej) i powoduje to rozpoczęcie gry od początku – poprzez wywołanie procedury reset Call[reset], którą przygotujemy za chwilę. | ||
+ | |||
+ | Jeśli piłka uderzy w krawędź boczną, to zostaną wykonane dwie akcje: | ||
+ | |||
+ | 1. Odbij Piłkę tak, jakby się zderzyła z odpowiednią krawędzią (identyfikator krawędzi uzyskujemy przy pomocy '''get[edge]''') | ||
+ | |||
+ | 2. Zwiększ prędkość piłki o jeden więcej '''(Set[Piłka].Speed to [Piłka].[Speed] + 1)'''. | ||
+ | |||
+ | Na zakończenie dołóżmy jeszcze akcję '''set[Screen1].[Title]''' na „Squash - ”&[Piłka]. [Speed], czyli ustaw pasek tytułu na napis Squash oraz prędkość poruszania się Piłki. | ||
+ | |||
+ | '''Wariant pierwszy - poruszanie paletką za pomocą ruchu palca.''' | ||
+ | |||
+ | Kolejnym krokiem będzie zaprogramowanie mechanizmu poruszania paletki poprzez przeciągnięcie palcem. Tutaj wykorzystamy funkcję <b>when[Paletka].Dragged.</b> | ||
+ | |||
+ | [[Plik:squash-10.png|600px]] | ||
+ | |||
+ | '''when[Paletka].Dragged''' ''(kiedy Paletka przeciągnięta)'', to ustaw współrzędną X Paletki na wartość '''currentX''' (czyli aktualna współrzędna X - miejsce, gdzie dotkniemy/przeciągniemy palcem ekranu) zmniejszona o połowę szerokości Paletki '''([Paletka].[Width] / 2)'''. Musimy więc wewnątrz działania matematycznego odejmowanie zawrzeć kolejne działanie - dzielenie. | ||
+ | |||
+ | Dlaczego zmniejszyliśmy szerokość o połowę? Polecenie '''set[Paletka].[X]''' ustawia lewy górny róg Paletki w miejscu X. Z tego powodu musimy odjąć połowę jej szerokości, żeby palec wskazywał środek paletki, a nie jej lewą krawędź. | ||
+ | |||
+ | '''Przygotowanie procedury reset''' | ||
+ | |||
+ | Teraz przygotujmy procedurę własną reset. Będzie ona uruchamiana zawsze, gdy piłka dotknie dolnej krawędzi oraz zawsze na początku gry. Będą w niej zawarte wszystkie domyślne dla naszej gry parametry, takie jak kolor tła, czy wymiary boiska. Dzięki temu nasza gra po porażce i przy każdym wznowieniu oraz na początku zawsze będzie wyglądała i działała tak samo. W obszarze '''Blocks''' w grupie '''Procedures''' znajdźmy '''to[procedure] do''' i przeciągnijmy ten element do obszaru ''Viewer''. Następnie zmieńmy jego nazwę na ''reset'' i wstawmy poszczególne klocki, jak na poniższej ilustracji. | ||
+ | |||
+ | [[Plik:squash-10a.png|600px]] | ||
+ | |||
+ | 1. Na początek ustawmy kolor tła naszego Boiska – jeżeli kolor jest szary (czyli jeśli przegraliśmy), to ustawiamy na biały. Dodajmy jeszcze warunek, że jeżeli boisko ma jakikolwiek inny kolor niż szary, to ustawiamy na biały - o tym za chwilę. | ||
+ | |||
+ | 2. Następnie ustawmy parametry początkowe Piłki – współrzędne X i Y, kierunek ('''Heading''') oraz prędkość piłki ('''Speed'''). Dzięki temu na początku gry piłka zawsze będzie w tej samej pozycji. | ||
+ | |||
+ | 3. Na samym dole, wzdłuż dolnej krawędzi Boiska (linia x1) rysujemy linię (w kolorze i szerokości ustawionej w procedurze '''when[Screen1].Initialize''', którą stworzymy za chwilę). Linia ta musi być za każdym razem rysowana ponownie, ponieważ ustawienie tła Boiska (na szare lub białe) powyżej powoduje jej usunięcie (wyczyszczenie całości Boiska). | ||
+ | |||
+ | Przypomnijmy jeszcze raz, że procedura reset będzie uruchamiana za każdym razem, gdy Piłka dotknie dolnej krawędzi Boiska (czerwonej linii) oraz podczas uruchomienia aplikacji. | ||
+ | |||
+ | '''Instrukcja when[Screen1].Initialize''' | ||
+ | |||
+ | Została nam już ostatnia instrukcja, która będzie uruchamiana w momencie inicjowania komponentu Screen1, czyli w naszym przypadku po prostu przy każdym starcie aplikacji. W tej instrukcji zdefiniujemy parametry początkowe naszej aplikacji. | ||
+ | |||
+ | [[Plik:squash-11.png|600px]] | ||
+ | |||
+ | 1. Szerokość Paletki ustawmy na ¼ szerokości Boiska. | ||
+ | |||
+ | 2. Ustalmy parametry rysowania Boiska (kolor czerwony, szerokość/grubość rysowania 9) – to wykorzystamy do rysowania czerwonej linii na dole Boiska. | ||
+ | |||
+ | 3. Na sam koniec uruchamiamy jeszcze procedurę reset. I tutaj znajdziemy odpowiedź, dlaczego w procedurze reset sprawdzane są również inne kolory boiska niż tylko szary. Program rozpoczyna od procedury '''when[Screen1].Initialize''' i ustawia obrys koloru boiska na czerwony o grubości linii 9. Procedura '''reset''' z kolei sprawdza, jaki jest kolor boiska i jeżeli jest szary lub inny niż szary, zmienia kolor na biały, rysując dodatkowo trzy linie - górną oraz boczne. W ten sposób dolna linia w czerwonym kolorze pozostaje na boisku, również po wykonaniu procedury reset. Musieliśmy rozwiązać to w taki sposób, ponieważ porażkę sygnalizujemy zmianą koloru tła, natomiast zamiana koloru tła spowodowałaby usunięcie tej linii. | ||
+ | |||
+ | '''<li>Udostępnianie aplikacji</li>''' | ||
+ | |||
+ | Nasza aplikacja działa teraz prawidłowo, zaś paletka przemieszcza się, kiedy przesuwamy palcem po ekranie. Korzystając z faktu, że mamy ciekawą, działającą aplikację, poświęćmy teraz chwilę na udostępnienie tej aplikacji dalej po to, by można było zainstalować ją na dowolnym smartfonie. W tym celu kliknijmy w menu Build (1), gdzie znajdziemy dwie funkcje (2): | ||
+ | |||
+ | 1.App (Provide QP code for .apk) - wybranie tej opcji spowoduje wyświetlenie kodu QR i da możliwość załadowania przy pomocy tego kodu samodzielnej aplikacji na telefonie, bez użycia MIT AI2 Companion. | ||
+ | |||
+ | 2.App (save .apk to my computer) - wybranie tego polecenia spowoduje zapisanie aplikacji na komputerze jako plik .apk. Dzięki temu możemy chociażby przesłać aplikację jako załącznik w e-mailu. | ||
+ | |||
+ | [[Plik:squash-12.png|600px]] | ||
+ | |||
+ | '''<li>Suqash, wariant drugi - sterowanie paletką poprzez wychylenia telefonu</li>''' | ||
+ | |||
+ | Teraz przejdźmy do zaprogramowania drugiego wariantu, czyli sterowania paletką poprzez obracanie smartfonem czy tabletem. Chcemy oczywiście zachować pierwszy wariant gry, dlatego stworzymy teraz nowy zapis projektu i to na nim wprowadzimy odpowiednie zmiany. | ||
+ | Wybierzmy zatem '''Projects (1)''' w menu głównym, a następnie '''Save projects as... (2)''' i w polu ''<b>New name:</b>'' wpiszmy nową nazwę: '''Squash_przechylanie.''' | ||
+ | |||
+ | [[Plik:squash-12a.png|600px]] | ||
+ | |||
+ | Z grupy '''Sensors <i>(czujniki</i>)''' wybierzmy komponent o nazwie '''AccelerometerSensor (1)''' i przeciągnijmy go na obszar projektowania interfejsu. Jako że '''AccelerometerSensor''' jest obiektem niewidocznym, to nie zajmuje on miejsca na ekranie, ale możemy zobaczyć go poniżej ekranu, w sekcji '''Non-visible components (2).''' | ||
+ | Komponent '''AccelerometerSensor''' będzie przez nas wykorzystany do odczytywania przechylenia telefonu. | ||
+ | |||
+ | [[Plik:info.png|left]]''Akcelerometr, czyli użyty przez nas komponent jest przyrządem służącym do pomiaru przyspieszeń liniowych lub kątowych. Akcelerometry są coraz częściej instalowane w telefonach komórkowych, umożliwiając automatyczne wykrywanie ułożenia przestrzennego (pochylenie, przekręcenie) urządzenia.'' | ||
+ | |||
+ | |||
+ | |||
+ | Zanim zaczniemy sterować paletką przy pomocy wychyleń telefonu musimy dezaktywować (lub usunąć całkowicie) sterowanie za pomocą przeciągania palcem, czyli instrukcję '''when[Paletka].Dragged.''' | ||
+ | |||
+ | W celu zdezaktywowania tej instrukcji przejdźmy do '''Blocks''', najedźmy kursorem myszy na procedurę sterowania paletką, czyli '''when[Paletka].Dragged (1)''' i kliknijmy prawym przyciskiem myszy. W ten sposób wywołamy menu podręczne, z którego musimy wybrać polecenie '''Disable Block''', czyli ''dezaktywuj'' (2). Cała nasza instrukcja zmieni kolor na szary, co oznacza, że jest nieaktywna i nie będzie wykonywana podczas działania aplikacji. | ||
+ | |||
+ | [[Plik:squash-13.png|600px]] | ||
+ | |||
+ | Korzystając z okazji, omówmy teraz pozostałe polecenia z menu podręcznego bloków: | ||
+ | 1. '''Duplicate ''(powiel)''''' - tworzy kopię danego bloku bądź całej instrukcji złożonej z bloczków. | ||
+ | 2. '''Add Comment ''(dodaj komentarz)''''' - umożliwia dodanie komentarza do bloku bądź całej instrukcji. Komentarz wyświetla się w postaci ikony ze znakiem zapytania w lewym górnym rogu bloku. Kliknięcie na tę ikonę powoduje rozwinięcie pola tekstowego. | ||
+ | 3. '''Collapse Block ''(złóż klocek)''''' - minimalizuje klocek bądź całą instrukcję poprzez “zwinięcie” do elementu zawierającego tylko tytuł. | ||
+ | 4. '''Delete x Blocks ''(Skasuj x bloków)''''' - usuwa wszystkie bloczki w instrukcji, gdzie x oznacza liczbę bloków. W naszym przypadku jest to 7. | ||
+ | 5. '''Help ''(pomoc)''''' - kliknięcie na ten element powoduje przeniesienie nas na stronę, gdzie opisane jest działanie danego bloku | ||
+ | |||
+ | Przejdźmy teraz do ułożenia kompletnej instrukcji, pozwalającej sterować paletką poprzez obracanie telefonem. | ||
+ | |||
+ | [[Plik:info.png|left]]'''UWAGA:''' Zaprezentowany program został przygotowany na telefon, jednak w przypadku stosowania tabletu koniecznym może być skorzystanie ze zmiennej '''yAccel''' (przyspieszenie względem osi y) zamiast '''xAccel''' - (przyspieszenie względem osi x). Jest to związane z faktem, iż na części testowanych tabletów oś X była przypisana do szerszej krawędzi (środka) ekranu, co powodowało wychylenia w porządku góra-dół. Natomiast w przypadku telefonów oś X jest przypisana do krótszej krawędzi i prezentuje wychylenia na prawo i lewo. | ||
+ | |||
+ | Na początek potrzebujemy blok '''when[AccelerometerSensor1].AccelerationChanged''' (czyli wydarzenie: gdy zmieniło się położenie telefonu). Procedura ta posiada trzy parametry, które reprezentują położenie telefonu w trzech wymiarach. Nas interesować będzie tylko '''xAccel''', czyli pochylenie telefonu w prawo lub w lewo. Leżący płasko telefon ma wartość '''xAccel''' równą 0. Gdy przechylamy go w prawo, to wartość rośnie, a gdy przechylamy w lewo, to wartość '''xAccel''' maleje, przyjmując wartości ujemne. | ||
+ | |||
+ | [[Plik:squash-14.png|600px]] | ||
+ | |||
+ | Następnym krokiem będzie wprowadzenie zmiennej lokalnej (czyli aktywnej w ramach niniejszego zbioru klocków) '''nachylenieX''' - nadajmy je wartość równą '''xAccel''' '''''(1)'''''. | ||
+ | |||
+ | Dodajmy teraz dwa warunki '''''(2)''''': | ||
+ | |||
+ | - jeżeli '''nachylenieX > 5''', to ustaw '''nachylenieX = 5''' | ||
+ | |||
+ | - jeżeli '''nachylenieX < -5''', to ustaw '''nachylenieX = -5''' | ||
+ | |||
+ | Te dwa warunku służą ograniczeniu zakresu przechylenia telefonu. Chodzi o to, żeby paletka przemieszczała się w kierunku krawędzi telefonu przy nieznacznych przechyleniach urządzenia. | ||
+ | |||
+ | Po wykonaniu obu warunków zmienna reprezentująca nachylenie będzie przyjmować wartości od -5 do 5. Przeliczmy tę zmienną tak, żeby zmieniała wartość | ||
+ | od 0 do 1 (a nie od -5 do 5) – to nam ułatwi kolejne obliczenia. W tym celu ustawmy wartość zmiennej poprzez odjęcie od 5 nachylenia X (otrzymujemy | ||
+ | liczbę 0 lub 10), a następnie podzielenie tego wyniku przez 10, co ostatecznie da nam wartość z przedziału 0-1 '''''(3)'''''. | ||
+ | |||
+ | '''Alternatywna, skrócona instrukcja przechylania''' | ||
+ | |||
+ | Zamiast zmiany lokalizacji paletki przy pomocy akcelerometru, możemy wykorzystać akcelerometr do sterowania prędkością (i kierunkiem) poruszania się paletki. Inaczej mówiąc, pochylenie telefonu nie steruje tym, w którym miejscu ma ustawić się paletka, ale tym, z jaką prędkością przesuwa się w stronę krawędzi. | ||
+ | |||
+ | Jeżeli chcemy skorzystać z takiego rozwiązania, musimy usunąć poprzednią wersję procedury '''when.[AccelerometerSensor1].AccelerationChanged''' i zamiast niej wprowadzić poniższą wersję (musimy pamiętać, że w przypadku tabletów zamiast '''xAccel''' musimy skorzystać z '''yAccel'''): | ||
+ | |||
+ | [[Plik:squash-15.png|600px]] | ||
+ | |||
+ | '''<li>Podsumowanie</li>''' | ||
+ | Nauczyliśmy się wykonywać proste animacje oraz wiemy już, jak sterować obiektami poprzez przeciąganie palcem po ekranie, a także z wykorzystaniem akceleratora - obracając telefonem. Poznaliśmy też podstawy definiowania interfejsu użytkownika. To wszystko daje nam dobrą podstawę do tworzenia kolejnych, bardziej rozbudowanych aplikacji w systemie Android. |
Aktualna wersja na dzień 05:09, 1 paź 2015
Squash w dwóch wariantach
Scenariusz 2
Cele:
Stworzymy prostą grę Squash, polegającą na odbijaniu piłeczki paletką, w dwóch wariantach. W ten sposób poznamy m.in. podstawy definiowania interfejsu użytkownika oraz nauczymy się wykonywać proste animacje. Po wykonaniu ćwiczenia będziemy też potrafili sterować obiektami za pomocą przeciągania palcem (pierwszy wariant) po ekranie oraz poprzez przechylanie telefonu (drugi wariant).
W tej wersji Squasha nie będzie systemu naliczania punktów, jak w tradycyjnej wersji tej gry. W naszej aplikacji na dole będzie umieszczona czerwona linia i jeśli piłka się z nią zderzy, to nastąpi przegrana. Co więcej, gdy nie odbijemy piłeczki i ta spadnie na czerwoną linię, boisko zmieni kolor na szary, co będzie oznaczało koniec gry.
- Rozpoczęcie pracy
- Squash - projektowanie interfejsu
- Canvas (zamknięty obszar) - jest to komponent ograniczający obszar animacji oraz rysowania. W obszarze tego komponentu poruszają się Ball oraz ImageSprite.
- Ball (piłka) - w naszej aplikacji to po prostu piłka, którą będziemy odbijać za pomocą paletki.
- ImageSprite (“duszek”) - znany ze Scratcha duszek. W naszej aplikacji będzie to paletka. Image Sprite jest podobny do komponentu Ball, jednak duszek ma kształt prostokąta, a jego tłem może być dowolny plik graficzny, np. w formacie jpg.
- Automatic (automatyczna) - system samodzielnie dobierze odpowiednią wartość szerokości i wysokości lub pozostawi je w standardowym ustawieniu.
- Fill parent (wypełnienie obiektu nadrzędnego) - sprawia, że komponent przejmuje wielkość komponentu nadrzędnego. W przypadku naszej aplikacji zaznaczenie tej opcji sprawiłoby, że obszar Canvas1 przejąłby szerokość i wysokość od komponentu Screen1, co możemy zauważyć na ilustracji powyżej, w oknie Components - Cavas1 jest obiektem podrzędnym dla Screen1.
- ... pixels - szerokość/wysokość o podanej przez nas liczbie pikseli.
- Heading (kierunek)- wpiszmy wartość 50 (2)
- Paint Color (kolor)- wybierzmy Blue (3)
- Radius (promień)- promień, czyli po prostu wielkość piłki ustalmy na 5 (4)
- Speed (prędkość) - tutaj wpiszmy wartość 100 (5)
- Współrzędne X i Y - obu współrzędnym nadajmy wartość 100 (6)
- Ustawienie pliku graficznego - wygląd paletki będzie wczytany z pliku graficznego, który załadujemy do programu. Paletka bez załadowanej grafiki byłaby przezroczysta, a to zdecydowanie utrudniłoby nam grę. Musimy zatem przygotować dowolny plik graficzny, np. w formacie png i wczytać go do mediów aplikacji, by następnie przypisać do paletki. Kliknijmy więc na Upload File (1) w oknie Media i odszukajmy plik, który chcemy wczytać do programu. Następnie przechodzimy do okna Properties i tam w polu Picture z rozwijanej listy wybierzmy nasz plik. Plików multimedialnych nie możemy przypisać bezpośrednio do komponentów, stąd w pierwszej kolejności musieliśmy wczytać plik do biblioteki mediów.
- Wielkość i pozycja - po tym, jak wczytaliśmy już plik graficzny, przejdźmy do ustawienia pozostałych parametrów. Współrzędną X ustawmy na 100 pikseli, zaś Y - na 270 (3). Następnie parametry Width (szerokość) na 70 pikseli, a Height (wysokość) na 20 pikseli.
- Squash - programowanie aplikacji
- Udostępnianie aplikacji
- Suqash, wariant drugi - sterowanie paletką poprzez wychylenia telefonu
- Podsumowanie Nauczyliśmy się wykonywać proste animacje oraz wiemy już, jak sterować obiektami poprzez przeciąganie palcem po ekranie, a także z wykorzystaniem akceleratora - obracając telefonem. Poznaliśmy też podstawy definiowania interfejsu użytkownika. To wszystko daje nam dobrą podstawę do tworzenia kolejnych, bardziej rozbudowanych aplikacji w systemie Android.
Wejdźmy na stronę http://appinventor.mit.edu i wybierzmy Create, by uruchomić App Inventor. Następnie przejdźmy do zakładki My Projects (1), gdzie znajdziemy wszystkie nasze projekty - wystarczy tylko zalogować się na odpowiednie konto Google. W celu rozpoczęcia pracy nad nowym projektem kliknijmy na Start new project (2) i wpiszmy w oknie jego nazwę, np. Squash.
Nastąpi teraz automatyczne przejście do okna budowy aplikacji.
Jak już wspomnieliśmy powyżej - w pierwszym wariancie naszej gry sterowanie paletką będzie odbywało się poprzez przeciąganie palcem po ekranie smartfona, natomiast w drugiej wersji będziemy sterować obracając nim. Obracanie ekranu zgodnie z pozycją telefonu czy tabletu jest domyślnym zachowaniem. Dlatego też w pierwszym wariancie musimy zablokować ekran po to, by ten nie zmieniał swojej orientacji. I od tego właśnie zaczniemy budowę naszej gry.
Przejdźmy zatem do okna Properties i dla komponentu Screen1, w polu Screen Orientation (1) wybierzmy Portrait. Dzięki temu nasz ekran zawsze będzie wyświetlany pionowo, niezależnie od tego, w jakiej pozycji znajduje się urządzenie. Dodatkowo w polu Title wpiszmy tytuł naszego bieżącego komponentu (2). Nazwijmy go Squash.
Po zablokowaniu obrotu ekranu przejdźmy do dodania komponentów. W naszej aplikacji wykorzystamy trzy elementy - wszystkie znajdziemy w grupie Drawing and Animation. Są to:
Jako pierwszy komponent dodajmy Canvas (1).Przeciągnijmy go na nasz obszar roboczy, czyli Viewer.
Po tym, jak wstawiliśmy komponent Canvas, musimy zmienić jego cechy w oknie Properties. Zmodyfikujmy dwa atrybuty: Width (szerokość) oraz Height (wysokość). Dla większości komponentów zarówno szerokość, jak i wysokość można ustawić jako:
Ustawmy zatem dla komponentu Canvas1 wartości Width jako Fill Parent (1) oraz Height jako 300 pikseli(2).
Teraz czas na kolejne komponenty. Dodajmy Ball (1) oraz ImageSprite (2) w dowolne miejsca w obrębie komponentu Canvas1. Tak jak wspomnieliśmy wcześniej, komponenty Ball oraz ImageSprite mogą być umieszczone jedynie na komponencie Canvas. Nie można umieścić ich poza tym obszarem, bezpośrednio na ekranie telefonu.
Po dodaniu dwóch następnych komponentów dostosujmy ich właściwości tak, by odpowiadały naszym założeniom. Zacznijmy od komponentu Ball - na początek zmieńmy nazwę tego obiektu, klikając Rename (1) i wpisując Piłka w polu New Name. Następnie zmieńmy kilka cech tego komponentu w oknie właściwości, czyli Properties:
Inaczej niż w Scratchu, w programie App Inventor komponenty Ball oraz ImageSprite mogą mieć nadaną własną prędkość. W Scratchu efekt ten osiągaliśmy poprzez wielokrotne przesuwanie obiektu. Tutaj wystarczy, że nadamy komponentowi kierunek (Heading) oraz prędkość (Speed), zaś resztę pracy wykona za nas komputer.
Warto zwrócić uwagę na hierarchię komponentów w oknie Components. Jak pamiętamy, w poprzedniej aplikacji wszystkie komponenty były bezpośrednio podrzędne dla Screen1. Tutaj podrzędny dla Screen1 jest tylko Canvas1, natomiast pozostałe dwa komponenty (Piłka oraz ImageSprite) są podrzędne dla komponentu Canvas1.Zmieńmy jeszcze nazwy pozostałych komponentów. Canvas1 przestawmy na Boisko (1), zaś ImageSprite1 na Paletka (2).
Teraz przejdziemy do następnego kroku, czyli do skonfigurowania paletki.
Przejdźmy zatem do zmiany właściwości komponentu o nazwie Paletka. Na początek kliknijmy na paletkę w oknie Components, by ją zaznaczyć - dzięki temu w oknie Properties pojawią się opcje, które pozwolą nam skonfigurować naszą paletkę. Konfigurację jej cech podzielimy na dwa kroki. W pierwszym kroku zadbamy o jej wygląd, zaś w drugim zajmiemy się jej rozmiarem i pozycją.
Po tym, jak zakończyliśmy projektowanie interfejsu aplikacji, możemy zająć się stworzeniem odpowiedniego programu. Tym razem zbudowanie poprawnego kodu będzie wymagało od nas większej pracy niż w przypadku poprzedniej aplikacji. Tam wystarczyła nam tylko jedna instrukcja zbudowana z bloków, natomiast tutaj potrzebujemy ich kilka. Przejdźmy więc teraz do zakładki Blocks, a poniżej, krok po kroku, omówimy wszystkie instrukcje.
Zderzenie piłki z paletką i odbicie piłki
Podstawową interakcją w naszej grze jest zderzenie piłeczki z paletką. Gdy do tego dojdzie, piłka musi odbić się od paletki. Musimy zatem ustalić, w jaki sposób ma zachować się piłka i określić, w stosunku do jakiego obiektu to zachowanie ma wystąpić.
Naszą instrukcję można opisać w następujący sposób: Kiedy piłka zderzy się z innym obiektem, to odbij piłkę tak, jakby dotknęła dolnej krawędzi.
Jak to działa? Przede wszystkim pamiętajmy, że piłka ma swoją prędkość. Gdy poruszająca się Piłka uderza w krawędź Canvas (nasze Boisko), to wywołuje wydarzenie EdgeReached (zetknięcie z krawędzią), a gdy uderza w inny obiekt, to wywołuje wydarzenie CollidedWith (zderzenie z...). My na ekranie mamy tylko jeden obiekt inny niż piłka, czyli paletkę. Zatem gdy piłka uderzy w paletkę, to zostanie uruchomiona akcja call[Piłka].Bounce (“odbij piłkę”). Akcja odbicia musi jeszcze wiedzieć, w którą stronę ma piłkę odbić, gdy ta uderzy w krawędź boczną lub górną i właśnie do tego służy parametr edge (krawędź). Jego wartość ustawiona na -1 powoduje odbicie Piłki tak, jakby dotknęła dolnej krawędzi (oznaczenia wszystkich krawędzi znajdują się dalej).
Other (inny obiekt), można wykorzystać do ustalenia, w który obiekt uderzyła Piłka. My na ekranie mamy tylko paletkę, więc nie musimy sprawdzać wartości other.
Polecenia When[Piłka].CollidedWith oraz Call[Piłka].Bounce znajdziemy w grupie Piłka (1), zaś obiekt z wartością liczbową - w grupie Math (2).
Wszystkie instrukcje, tak jak w Scratchu, podzielone są na kategorie oznaczone odpowiednimi kolorami, co ułatwia nawigację.
Numeracja krawędzi ekranu w App Inventorze.
Przed momentem skonfigurowaliśmy uderzenie piłki w dolną krawędź ekranu, która jest oznaczona numerem -1. Skąd wziął się właśnie taki numer? Krawędzie w programie App Inventor mają takie oznaczenia, jakie zaprezentowano na poniższej ilustracji. Krawędź północna oznaczona jest numerem 1, północno-wschodnia numerem 2 i w ten sposób docieramy do krawędzi dolnej, która jest oznaczona numerem -1.
Zderzenie piłki z krawędzią i odbicie piłki od krawędzi.
Teraz zaprogramujemy wydarzenie zderzenia piłki z krawędzią. Tutaj musimy rozróżnić dwa rodzaje krawędzi - krawędź boczną i krawędź dolną. Jeśli piłka zderzy się z krawędzią boczną, to zostanie odbita, a wartość jej prędkości zwiększy się o 1. Natomiast jeśli zderzy się krawędzią dolną, to nastąpi ponowne rozpoczęcie gry poprzez wywołanie odrębnej procedury, którą przygotujemy.
Najpierw sprawdzamy, czy piłka uderzyła w krawędź dolną (wartość edge wynoszącą -1). Krawędź -1 oznacza, że gracz przepuścił piłkę (nie odbił jej) i powoduje to rozpoczęcie gry od początku – poprzez wywołanie procedury reset Call[reset], którą przygotujemy za chwilę.
Jeśli piłka uderzy w krawędź boczną, to zostaną wykonane dwie akcje:
1. Odbij Piłkę tak, jakby się zderzyła z odpowiednią krawędzią (identyfikator krawędzi uzyskujemy przy pomocy get[edge])
2. Zwiększ prędkość piłki o jeden więcej (Set[Piłka].Speed to [Piłka].[Speed] + 1).
Na zakończenie dołóżmy jeszcze akcję set[Screen1].[Title] na „Squash - ”&[Piłka]. [Speed], czyli ustaw pasek tytułu na napis Squash oraz prędkość poruszania się Piłki.
Wariant pierwszy - poruszanie paletką za pomocą ruchu palca.
Kolejnym krokiem będzie zaprogramowanie mechanizmu poruszania paletki poprzez przeciągnięcie palcem. Tutaj wykorzystamy funkcję when[Paletka].Dragged.
when[Paletka].Dragged (kiedy Paletka przeciągnięta), to ustaw współrzędną X Paletki na wartość currentX (czyli aktualna współrzędna X - miejsce, gdzie dotkniemy/przeciągniemy palcem ekranu) zmniejszona o połowę szerokości Paletki ([Paletka].[Width] / 2). Musimy więc wewnątrz działania matematycznego odejmowanie zawrzeć kolejne działanie - dzielenie.
Dlaczego zmniejszyliśmy szerokość o połowę? Polecenie set[Paletka].[X] ustawia lewy górny róg Paletki w miejscu X. Z tego powodu musimy odjąć połowę jej szerokości, żeby palec wskazywał środek paletki, a nie jej lewą krawędź.
Przygotowanie procedury reset
Teraz przygotujmy procedurę własną reset. Będzie ona uruchamiana zawsze, gdy piłka dotknie dolnej krawędzi oraz zawsze na początku gry. Będą w niej zawarte wszystkie domyślne dla naszej gry parametry, takie jak kolor tła, czy wymiary boiska. Dzięki temu nasza gra po porażce i przy każdym wznowieniu oraz na początku zawsze będzie wyglądała i działała tak samo. W obszarze Blocks w grupie Procedures znajdźmy to[procedure] do i przeciągnijmy ten element do obszaru Viewer. Następnie zmieńmy jego nazwę na reset i wstawmy poszczególne klocki, jak na poniższej ilustracji.
1. Na początek ustawmy kolor tła naszego Boiska – jeżeli kolor jest szary (czyli jeśli przegraliśmy), to ustawiamy na biały. Dodajmy jeszcze warunek, że jeżeli boisko ma jakikolwiek inny kolor niż szary, to ustawiamy na biały - o tym za chwilę.
2. Następnie ustawmy parametry początkowe Piłki – współrzędne X i Y, kierunek (Heading) oraz prędkość piłki (Speed). Dzięki temu na początku gry piłka zawsze będzie w tej samej pozycji.
3. Na samym dole, wzdłuż dolnej krawędzi Boiska (linia x1) rysujemy linię (w kolorze i szerokości ustawionej w procedurze when[Screen1].Initialize, którą stworzymy za chwilę). Linia ta musi być za każdym razem rysowana ponownie, ponieważ ustawienie tła Boiska (na szare lub białe) powyżej powoduje jej usunięcie (wyczyszczenie całości Boiska).
Przypomnijmy jeszcze raz, że procedura reset będzie uruchamiana za każdym razem, gdy Piłka dotknie dolnej krawędzi Boiska (czerwonej linii) oraz podczas uruchomienia aplikacji.
Instrukcja when[Screen1].Initialize
Została nam już ostatnia instrukcja, która będzie uruchamiana w momencie inicjowania komponentu Screen1, czyli w naszym przypadku po prostu przy każdym starcie aplikacji. W tej instrukcji zdefiniujemy parametry początkowe naszej aplikacji.
1. Szerokość Paletki ustawmy na ¼ szerokości Boiska.
2. Ustalmy parametry rysowania Boiska (kolor czerwony, szerokość/grubość rysowania 9) – to wykorzystamy do rysowania czerwonej linii na dole Boiska.
3. Na sam koniec uruchamiamy jeszcze procedurę reset. I tutaj znajdziemy odpowiedź, dlaczego w procedurze reset sprawdzane są również inne kolory boiska niż tylko szary. Program rozpoczyna od procedury when[Screen1].Initialize i ustawia obrys koloru boiska na czerwony o grubości linii 9. Procedura reset z kolei sprawdza, jaki jest kolor boiska i jeżeli jest szary lub inny niż szary, zmienia kolor na biały, rysując dodatkowo trzy linie - górną oraz boczne. W ten sposób dolna linia w czerwonym kolorze pozostaje na boisku, również po wykonaniu procedury reset. Musieliśmy rozwiązać to w taki sposób, ponieważ porażkę sygnalizujemy zmianą koloru tła, natomiast zamiana koloru tła spowodowałaby usunięcie tej linii.
Nasza aplikacja działa teraz prawidłowo, zaś paletka przemieszcza się, kiedy przesuwamy palcem po ekranie. Korzystając z faktu, że mamy ciekawą, działającą aplikację, poświęćmy teraz chwilę na udostępnienie tej aplikacji dalej po to, by można było zainstalować ją na dowolnym smartfonie. W tym celu kliknijmy w menu Build (1), gdzie znajdziemy dwie funkcje (2):
1.App (Provide QP code for .apk) - wybranie tej opcji spowoduje wyświetlenie kodu QR i da możliwość załadowania przy pomocy tego kodu samodzielnej aplikacji na telefonie, bez użycia MIT AI2 Companion.
2.App (save .apk to my computer) - wybranie tego polecenia spowoduje zapisanie aplikacji na komputerze jako plik .apk. Dzięki temu możemy chociażby przesłać aplikację jako załącznik w e-mailu.
Teraz przejdźmy do zaprogramowania drugiego wariantu, czyli sterowania paletką poprzez obracanie smartfonem czy tabletem. Chcemy oczywiście zachować pierwszy wariant gry, dlatego stworzymy teraz nowy zapis projektu i to na nim wprowadzimy odpowiednie zmiany. Wybierzmy zatem Projects (1) w menu głównym, a następnie Save projects as... (2) i w polu New name: wpiszmy nową nazwę: Squash_przechylanie.
Z grupy Sensors (czujniki) wybierzmy komponent o nazwie AccelerometerSensor (1) i przeciągnijmy go na obszar projektowania interfejsu. Jako że AccelerometerSensor jest obiektem niewidocznym, to nie zajmuje on miejsca na ekranie, ale możemy zobaczyć go poniżej ekranu, w sekcji Non-visible components (2). Komponent AccelerometerSensor będzie przez nas wykorzystany do odczytywania przechylenia telefonu.
Akcelerometr, czyli użyty przez nas komponent jest przyrządem służącym do pomiaru przyspieszeń liniowych lub kątowych. Akcelerometry są coraz częściej instalowane w telefonach komórkowych, umożliwiając automatyczne wykrywanie ułożenia przestrzennego (pochylenie, przekręcenie) urządzenia.
Zanim zaczniemy sterować paletką przy pomocy wychyleń telefonu musimy dezaktywować (lub usunąć całkowicie) sterowanie za pomocą przeciągania palcem, czyli instrukcję when[Paletka].Dragged.
W celu zdezaktywowania tej instrukcji przejdźmy do Blocks, najedźmy kursorem myszy na procedurę sterowania paletką, czyli when[Paletka].Dragged (1) i kliknijmy prawym przyciskiem myszy. W ten sposób wywołamy menu podręczne, z którego musimy wybrać polecenie Disable Block, czyli dezaktywuj (2). Cała nasza instrukcja zmieni kolor na szary, co oznacza, że jest nieaktywna i nie będzie wykonywana podczas działania aplikacji.
Korzystając z okazji, omówmy teraz pozostałe polecenia z menu podręcznego bloków: 1. Duplicate (powiel) - tworzy kopię danego bloku bądź całej instrukcji złożonej z bloczków. 2. Add Comment (dodaj komentarz) - umożliwia dodanie komentarza do bloku bądź całej instrukcji. Komentarz wyświetla się w postaci ikony ze znakiem zapytania w lewym górnym rogu bloku. Kliknięcie na tę ikonę powoduje rozwinięcie pola tekstowego. 3. Collapse Block (złóż klocek) - minimalizuje klocek bądź całą instrukcję poprzez “zwinięcie” do elementu zawierającego tylko tytuł. 4. Delete x Blocks (Skasuj x bloków) - usuwa wszystkie bloczki w instrukcji, gdzie x oznacza liczbę bloków. W naszym przypadku jest to 7. 5. Help (pomoc) - kliknięcie na ten element powoduje przeniesienie nas na stronę, gdzie opisane jest działanie danego bloku
Przejdźmy teraz do ułożenia kompletnej instrukcji, pozwalającej sterować paletką poprzez obracanie telefonem.
UWAGA: Zaprezentowany program został przygotowany na telefon, jednak w przypadku stosowania tabletu koniecznym może być skorzystanie ze zmiennej yAccel (przyspieszenie względem osi y) zamiast xAccel - (przyspieszenie względem osi x). Jest to związane z faktem, iż na części testowanych tabletów oś X była przypisana do szerszej krawędzi (środka) ekranu, co powodowało wychylenia w porządku góra-dół. Natomiast w przypadku telefonów oś X jest przypisana do krótszej krawędzi i prezentuje wychylenia na prawo i lewo.Na początek potrzebujemy blok when[AccelerometerSensor1].AccelerationChanged (czyli wydarzenie: gdy zmieniło się położenie telefonu). Procedura ta posiada trzy parametry, które reprezentują położenie telefonu w trzech wymiarach. Nas interesować będzie tylko xAccel, czyli pochylenie telefonu w prawo lub w lewo. Leżący płasko telefon ma wartość xAccel równą 0. Gdy przechylamy go w prawo, to wartość rośnie, a gdy przechylamy w lewo, to wartość xAccel maleje, przyjmując wartości ujemne.
Następnym krokiem będzie wprowadzenie zmiennej lokalnej (czyli aktywnej w ramach niniejszego zbioru klocków) nachylenieX - nadajmy je wartość równą xAccel (1).
Dodajmy teraz dwa warunki (2):
- jeżeli nachylenieX > 5, to ustaw nachylenieX = 5
- jeżeli nachylenieX < -5, to ustaw nachylenieX = -5
Te dwa warunku służą ograniczeniu zakresu przechylenia telefonu. Chodzi o to, żeby paletka przemieszczała się w kierunku krawędzi telefonu przy nieznacznych przechyleniach urządzenia.
Po wykonaniu obu warunków zmienna reprezentująca nachylenie będzie przyjmować wartości od -5 do 5. Przeliczmy tę zmienną tak, żeby zmieniała wartość od 0 do 1 (a nie od -5 do 5) – to nam ułatwi kolejne obliczenia. W tym celu ustawmy wartość zmiennej poprzez odjęcie od 5 nachylenia X (otrzymujemy liczbę 0 lub 10), a następnie podzielenie tego wyniku przez 10, co ostatecznie da nam wartość z przedziału 0-1 (3).
Alternatywna, skrócona instrukcja przechylania
Zamiast zmiany lokalizacji paletki przy pomocy akcelerometru, możemy wykorzystać akcelerometr do sterowania prędkością (i kierunkiem) poruszania się paletki. Inaczej mówiąc, pochylenie telefonu nie steruje tym, w którym miejscu ma ustawić się paletka, ale tym, z jaką prędkością przesuwa się w stronę krawędzi.
Jeżeli chcemy skorzystać z takiego rozwiązania, musimy usunąć poprzednią wersję procedury when.[AccelerometerSensor1].AccelerationChanged i zamiast niej wprowadzić poniższą wersję (musimy pamiętać, że w przypadku tabletów zamiast xAccel musimy skorzystać z yAccel):