Android Game Tutorial

Kurs projektowania gier na Androida (repozytorium można znaleźć tutaj) powstał jako alternatywa dla tutorialu z edu4java, używanego podczas zajęć z PANUM na Politechnice Poznańskiej.

W kursie omówiono tworzenie gry polegającej na unikaniu asteroid, która luźno nawiązuje do produktu z 1979 roku o nazwie Asteroids stworzonego przez firmę Atari (więcej można przeczytać na Wikipedii tutaj).

Dlaczego tworzyć alternatywę?

Ponieważ, jeśli wczytać się w kurs z edu4java okaże się, że jest z nim sporo problemów:

  • Przede wszystkim tutorial zawiera błędy i niedomówienia.
  • Poza tym jest po prostu stary. Co prawda ze strony platformy (Androida) niewiele się zmieniło, ale zawsze jest przyjemniej używać wersji środowiska, która jest zbliżona do obecnej.
  • W tutarialu nie omówiono konfiguracji środowiska, która co prawda nie jest trudna, ale jednak lepiej mieć dokładny opis.
  • Nie dołączono kodu źródłowego dla projektu. Można po kolei skopiować listingi, ale w połączeniu ze wspomnianymi brakami opisów konfiguracji środowiska, tworzenie kopii projektu, jest niepotrzebnie długie i męczące.

Tworząc nowy kurs, postarano się nie tylko rozwiązać wymienione problemy, ale dodać jeszcze kilka udogodnień. Poniżej wymieniono kilka spośród podstawowych różnic.

  • Uniknięto błędów z tutorialu z edu4java.
  • Całość kursu stworzono, używając najnowszej wersji Android Studio (wersja 3).
  • W kursie dokładnie omówiono konfiguracje środowiska, nie pomijając żadnych elementów. Ponadto z kursem dostarczono wszystkie wymagane zasoby.
  • Kurs wraz z kodem źródłowym projektu znajduje się w repozytorium na githubie. Wystarczy je pobrać i otworzyć w Android Studio, by uzyskać dostęp do wszystkiego.
  • Ponadto w repozytorium znajduje się kod nie tylko finalnej wersji, ale również kody wynikowych projektów po każdym rozdziale.
  • Jako dodatkowe udogodnienie dla osób wykonujących kurs krok po kroku, na końcu każdego rozdziału znajduje się lista wszystkich plików projektu, które zostały dodane lub zmodyfikowane w danym rozdziale.
  • W kursie omówiono dużo więcej elementów Android API i elementów związanych z tworzeniem gier. Jako wybrane przykłady można przytoczyć: dźwięki, rysowanie grafik przy użyciu macierzy, obsługa SVG, odczytywanie informacji o orientacji urządzenia.
  • W kursie zamieszczono screenshoty i nagrania (w postaci plików GIF i WEBM) wizualizujące postępy, co umożliwia zobaczenie wyników bez ładowania i uruchamiania projektów.
  • Gra tworzona w kolejnych rozdziałach jest dużo bardziej efektowna. Kurs powstał z ideą, by stworzony projekt był aplikacją, którą bez wstydu można umieścić w oficjalnym sklepie z aplikacjami na Androida.
  • Kurs jest dostępny w języku polskim, co może być ułatwieniem dla niektórych osób.

Warto jednak wspomnieć, że dla pewnych osób kurs może być mniej wygodny, niż tutorial z edu4java, a to za sprawą jego długości. Niestety dużo większy projekt wiąże się z większą objętością kursu. Osobom, które chcą bazować na finalnym projekcie i go rozbudowywać, a jednocześnie są zaniepokojone rozmiarem kursu, można doradzić ściągniecie finalnej wersji i przeczytanie lub przejrzenie tekstu. W razie problemów można powrócić do danego fragmentu kursu i poświęcić mu większą uwagę.

Zawartość kursu

Obecnie kurs składa się z 10 rozdziałów. Repozytorium można znaleźć w serwisie GitHub (tutaj). Treść tekstowa kursu w języku polskim znajduje się w katalogu course-pl.

Poniżej znajduje się lista rozdziałów kursu wraz z skróconym opisem wybranej zawartości każdego z nich.

Wstęp [link]

  • krótkie wprowadzenie do kursu

Rozdział 1 – Nowy projekt, klasa View i spółka [link]

  • tworzenia nowego projektu
  • stylowanie aplikacji jako gry
  • wyświetlanie kształtów geometrycznych

Rozdział 2 – Animacje, obrazy i główna pętla gry [link]

  • dodawanie grafiki bitmapowej
  • bitmapy i ich wyświetlanie
  • wyświetlanie fragmentu bitmapy
  • klasa SurfaceView
  • główna pętla gry i jej wątek
  • animacja składająca się z sekwencji klatek

Rozdział 3 – Wektory i SVG [link]

  • grafiki SVG
  • klasy Vector2D i MutableVector2D
  • animacja programowa

Rozdział 4 – Fasada i czas [link]

  • fasada gry i interfejs jej komponentu
  • komponenty fasady: ImageManager, Random i Timer
  • zarządzanie upływem czasu
  • poprawne kończenie głównej pętli gry
  • animacja z wieloma asteroidami

Rozdział 5 – Świat gry i separacja [link]

  • skalowanie zależnie od rozdzielczości urządzenia użytkownika
  • rysowanie grafik z obrotem, przezroczystością i w zadanej skali
  • warstwa abstrakcji nad klasami Canvas i Bitmap – GameCanvas i Image
  • świat gry jako dedykowana klasa

Rozdział 6 – Ale przecież to miał być kurs o tworzeniu gier – użytkownik i dotyk [link]

  • obsługa dotknięć
  • modyfikacja gry i jej rozbudowa o rakiety i statek gracza

Rozdział 7 – Kolizje i ich detekcja [link]

  • dwuetapowa detekcja kolizji
  • animowanie przezroczystości

Rozdział 8 – Konfiguracja i informacje do debugowania [link]

  • dedykowana klasa z konfiguracją
  • mierzenie i wyświetlanie ilości klatek na sekundę
  • wyświetlanie informacji pomagających wizualizować i usuwać ewentualne błędy z wyświetlaniem

Rozdział 9 – Dźwięk [link]

  • dodawanie zasobów dźwiękowych
  • odtwarzanie krótkich dźwięków
  • odtwarzanie dźwięku w zależności od odległości od gracza

Rozdział 10 – Orientacja urządzenia [link]

  • nasłuchiwanie na zdarzenia zmiany orientacji urządzenia użytkownika i ich zapisywanie
  • zablokowanie kamery na ruchomym statku gracza
  • rozbudowa gry o automatyczne naprowadzane rakiety na punkt

Dalsza rozbudowa finalnego projektu

Poniżej znajduje się lista przykładowych elementów, o które można rozbudować finalny projekt.

Zliczanie uzyskanych punktów – można wprowadzić modyfikację polegającą na tym, że gracz będzie dostawać punkty za swoje akcje, np. za zestrzelone asteroidy lub za czas przeżycia (lub za jedno i drugie). Opcji jest wiele.

Nowe obiekty w grze – w finalnym projekcie w gracza mogą uderzyć jedynie asteroidy. Można dodać nowe rodzaje obiektów z ich własnym dźwiękiem kolizji.

Ograniczenie paliwa – można ograniczyć ilość paliwa, którą posiadać będzie statek gracza. Jego ilość może być prostym paskiem w rogu ekranu. Po jego wyczerpaniu gracz automatycznie przegrywa (jak przy zderzeniu z asteroidą). Paliwo może być uzupełniane po zestrzeleniu asteroidy lub po zebraniu specjalnego obiektu w grze.

Muzyka w grze – w aplikacji możemy znaleźć krótkie dźwięki. Brakuje jednak muzyki w tle. Dobre wykonanie tego zadania prawdopodobnie powinno się wiązać z dodaniem nowego komponentu do fasady.

Kody do oszukiwania w grze – można wprowadzić funkcjonalność, która użytkownikowi znającemu specjalną sekwencję da dodatkowe możliwości (jak np. nieśmiertelność). Ową sekwencją, może być np. układ klawiszy telefonu, które należy przycisnąć lub ciąg dotknięć rogów ekranu. Można rozbudować to rozwiązanie o dynamiczne uruchamianie i wyłączanie informacji debugowania odpowiednim kodem.

Nowy typ broni – w tej chwili gracz dysponuje jedynie rakietami. Można wprowadzić nowy rodzaj broni (jak np. laser działający na krótki dystans). Korzystanie z niego może wymagać zmodyfikowania sposobu odczytywania dotknięć, np. długie dotknięcia oznaczać będą użycie jednego rodzaju broni, a krótkie innego.

Powtórna gra – w finalnym projekcie po przegranej nic się nie da zrobić – by grać dalej, trzeba ponownie uruchomić grę. Można to zmienić, dodając jakiś rodzaj informacji sygnalizujący, że gra się skończyła i sposób potwierdzenia, że gracz chce spróbować ponownie. Dobre rozwiązanie powinno brać pod uwagę fakt, że gracz prawdopodobnie będzie dotykał ekranu w momencie przegranej. Powoduje to, że rozwiązanie w postaci prostego przycisk nie będzie dobre, bo gracz często będzie przez przypadek zaczynać grę od nowa.

Animacja zderzeń – w tej chwili obiekty w grze po zderzeniu po prostu znikają. Można to zmodyfikować, wprowadzając specjalne animacje. Mogą być one zrealizowane całkowicie programowo, tj. bez specjalnych grafik.

Odtwarzanie dźwięku zależnie od miejsca – obecnie w grze dźwięk jest odtwarzany wyłącznie w zależności od odległości i jest on odtwarzany z taką samą głośnością dla każdego z głośników (lewego i prawego). Można rozbudować to zachowanie tak, by głośność dla danego głośnika była zależna (również) od kąta, tworząc wrażenie przestrzennego dźwięku.

Symulacja poruszania się dźwięku – jeśli rozbudujemy aplikację o animację zderzeń, to następnie można dodać zanikającą animacje fali uderzeniowej i odtwarzać dźwięk z odpowiednim opóźnieniem, symulując opóźnienie wynikające z wolniejszego poruszania się dźwięku.

Zapisywanie stanu gry – można serializować świat gry i go zapisywać w momencie wyjścia z aplikacji. Cały proces trzeba odwrócić tak, by wczytać stan gry włączając aplikację.

Rozszerzenie architektury i rozbudowa gry o menu – obecnie po uruchomieniu aplikacji od razu uruchamia się gra. Można wprowadzić rozwiązanie, w którym użytkownik będzie lądować w menu gry. Dobre rozwiązanie wprowadzi menu w sposób taki jak w grach dostępnych na rynku (czyli nie poprzez dodanie dodatkowej aktywności przed uruchomieniem tej z grą). Ten pomysł rozbudowy może spodobać się osobom, które szczególnie lubią pracować nad architekturą, ponieważ będzie wymagać zmian w strukturze logicznej projektu.

Firebase Realtime Database

W dzisiejszych czasach tworząc jakąkolwiek aplikację często stawiamy na rozwiązania oparte na chmurze. W szczególności wygodnym dla programisty są udostępniane w ten sposób bazy danych. Zamiast tworzyć własne, drogie serwery, które wymagają mnóstwo konfiguracji lepiej skorzystać z gotowego, wygodnego API, a konfigurację i zarządzanie zostawić innym. A jakby tak jeszcze do tych wszystkich zalet baz danych w chmurze dodać fakt, że baza danych sama będzie informować aplikację, że dane, które widzi użytkownik są nieaktualne? Okazuję się, że takie połączenie jest jak najbardziej możliwe dzięki Firebase Realtime Database! Ale po kolei.

Czytaj dalej

Android Oreo – Notification channel

Wstęp

Wraz z nową wersją Androida Oreo pojawiła się wiele nowych funkcjonalności. Jedną z nich są kanały powiadomień (Notification Channels). Pozwalają one na publikacje powiadomień w kanałach (kategoriach), którymi można w prosty sposób zarządzać z poziomu menedżera aplikacji. Jeśli aplikacja ma wiele kanałów programista ma możliwość pogrupowania ich ze względu na np. tematykę.

Zarządzanie kanałami

Screenshot_1517864569Screenshot_1517864585Screenshot_1517864622.png

Na zdjęciu powyżej widzimy trzy okna prezentujące poziomy zarządzanie kanałami w przykładowej aplikacji. Na lewym ekranie widzimy ogólny poziom zarządzania powiadomieniami, którego ustawienia wpływają na wszystkie kanały:

  • Wł. – pozwala on włączyć/wyłączyć wysłanie powiadomień z aplikacji.
  • Pokaż plakietkę
  • Lista kanałów – Lista zawiera wszystkie kanały jakie są używane w aplikacji.  Po kliknięciu na jeden z nich przechodzimy do drugiego ekranu, na którym możemy podejrzeć szczegóły kanału.

Na drugim oraz trzecim ekranie widzimy podgląd szczegółowy wybranego kanału. Na tym poziomie użytkownik ma możliwość personalizowania kanału poprzez zmianę ustawień parametrów:

  • Ważność – ustawiamy jeden z czterech poziomów Urgent/High/Medium/Low
  • Dźwięk – wybieramy dźwięk informujący o nowym powiadomieniu
  • Wibracja [ON/OFF] – kiedy wystąpi nowe powiadomienie urządzenie będzie wibrować
  • Na ekranie blokady [ON/OFF] – powiadomienia z kanału będą widoczne na zablokowanym ekranie.
  • Zastąp Nie przeszkadzać – powiadomienia z kanału będą wyświetlane w trybie nie przeszkadzać

Programowanie kanału

Do utworzenia kanału użyjemy metody createNotificationChannel() z instancji klasy NotificationManager. Funkcja ta przyjmuje jeden parametr, którym jest tworzony obiekt (typu NotificationChannel) nowo tworzonego kanału. Inicjując nowy obiekt musimy podać trzy parametry:

  • ID kanału – unikalne ID kanału
  • Nazwa kanału
  • Poziom ważności – jeden z czterech poziomów Urgent/High/Medium/Low


Jak już wcześniej się dowiedzieliśmy, użytkownik może sam zarządzać kanałami w aplikacji. Aby odczytać aktualne ustawienia kanału, możemy użyć dwóch metod:

  • getNotificationChannel() jako parametr wejściowy funkcja przyjmuje ID kanału a zwraca nam obiekt wyszukiwanego kanału
  • getNotificationChannels() funkcja na wyjściu zwraca listę wszystkich kanałów

Następnie możemy użyć dostępnych geterów do porania informacji o specyficznych ustawieniach użytkownika np:

  • getImportance() zwraca ustawiony poziom ważności kanału, jeśli kanał jest wyłączony metoda zwróci IMPORTANCE_NONE
  • getSound() zwraca URI wybranego dźwięku powiadomień

Aby usunąć kanał należy wywołać metodę deleteNotificationChannel() z ID kanału jako parametr.

Grupy kanałów

Na początku artykułu wspominałem o możliwości grupowania kanałów. Jest to przydatne rozwiązanie np. w przypadku gdy w aplikacji mamy kilka typów kont użytkowników a nazwy kanałów są takie same możemy je umieścić w grupach, które odpowiadają typom kont. Aby utworzyć grupę musimy pobrać instancję klasy NotificationManager, następnie tworzymy obiekt NotificationChannelGroup z parametrami:

  • ID grupy – unikalne ID dla grupy
  • Nazwa grupy

Tak utworzony obiekt jest parametrem wejściowym funkcji createNotificationChannelGroup(). Aby przypisać kanał do grupy należy wywołać metodę setGroup() a jako parametr podać obiekt grupy.

Podsumowanie

Dodanie kanałów powiadomień było bardzo dobrym pomysłem. Pozwalają one usprawnić pracę z urządzeniem, szczególnie w przypadku kiedy mamy zainstalowanych wiele aplikacji, które informują nas o różnych aktywnościach tą drogą.  Powiadomienia, które są nie istotne dla nas możemy dezaktywować. Niestety aplikacje, które nie wspierają kanałów, a są uruchamiane na urządzeniach z Android Oreo będą zachowywać się jak na wersjach niższych androida.

Tworzenie raportów w środowisku APEX z wykorzystaniem… MS Word

Podczas budowy do aplikacji webowych w przypadku wielu różnych platform programowych pojawia się problem wyboru rozwiązań pozwalających na generowanie wydruków. Często rozważane i wykorzystywane są takie rozwiązania jak: BIRT, JasperReports, Pentaho Business Analytics, ReportServer.

Wykorzystanie zewnętrznych produktów ma swoje plusy i minusy. Często do minusów zaliczyć można potrzebę integracji dwóch produktów,  problemy z bezpieczeństwem danych itp. Czasami problemem jest po prostu czas i skomplikowanie rozwiązania.

Tymczasem wiele platform do budowy aplikacji webowych udostępnia proste mechanizmy wydruku oparte o XSL-FO, które po prostu wystarczy wykorzystać. Tak dla przykładu jest w przypadku platformy APEX (Oracle Application Express).

Ktoś powie: „XSL-FO? Przecież to jest dopiero horror!”. Na przykładzie poniższego przykładu/tutorialu postaram się pokazać, że wcale tak być nie musi.

Zakładam, że czytelnik zna:

  • platformę APEX,
  • arkusze stylów XSLT oraz
  • format XSL-FO.

Niestety, bez znajomości tych zagadnień zrozumienie czy też wykonanie tego tutorialu może być niemożliwe lub niezrozumiałe.
Czytaj dalej

Integracja aplikacji Android z Firebase Cloud Messaging

Czym jest FCM?

Firebase Cloud Messaging jest darmową usługą Google, która pozwala przesyłać wiadomości między dowolną aplikacją serwerową, a aplikacjami mobilnymi. Dostarcza wsparcie dla Androida, iOS oraz aplikacji internetowych Chrome. FCM jest następcą Google Cloud Messaging (GCM).

firebase_diagram

Firebase Cloud Messaging działa jako pośrednik między serwerem lub konsolą Firebase, a aplikacją mobilną. Powiadomienia wysyłane do chmury Google następnie są kolejkowane i przekierowywane do konkretnych urządzeń. Usługa Google pozwala na przesyłkę wiadomości do konkretnego urządzenia, do wszystkich urządzeń (broadcast) lub do urządzeń subskrybujących dany temat (grupy).

Integracja FCM polega na trzech prostych krokach:

  1. Utworzenie projektu Firebase i powiązanie go z aplikacją klienta
  2. Subskrybowanie do danego kanału oraz obsługa komunikatów w aplikacji mobilnej
  3. Implementacja części serwerowej

W tym artykule skupimy się na dwóch pierwszych punktach, a za aplikację serwerową posłuży nam konsola Firebase, z poziomu której wyślemy wiadomości do klienta.

Czytaj dalej

Podstawy współpracy aplikacji z beaconami

Wstęp

Beacon – to małe i niepozorne urządzenie wysyłające sygnał do wszystkich urządzeń bluetooth w pobliżu. Beacony mimo braku własnej nazwy w języku polskim są w naszym kraju coraz szerzej stosowane i przede wszystkim produkowane. Najpopularniejsze na świecie beacony są pochodzą z polskich firm Estimote i Kontakt, a jedną z większych firm oferujących kompleksowe rozwiązania z beaconami w roli głównej jest -również polska- firma Infinity.

Jak działają beacony można się z łatwością samemu przekonać, wiele muzeów w Polsce ma na nich opartą nawigację po wystawach i wirtualnego przewodnika, który opowiada nam w kontekście miejsca w koło którego jesteśmy  (m. in. Brama Poznania). Można również pobrać na swój telefon np. aplikację Everytap – to startup, który pozwala na zbieranie bonusów za odwiedzanie partnerskich lokali, wysyła również powiadomienia push jak znajdziemy się blisko jakiegoś miejsca (w Poznaniu jest wiele miejsc z współpracujących z tą aplikacją)

Czytaj dalej

Tworzenie aplikacji na Androida w języku Kotlin

O Kotlinie

Idąc za definicją z Wikipedii, Kotlin to statycznie typowany język programowania działający na maszynie wirtualnej Javy (JVM) i zaprojektowany z myślą o pełnej interoperacyjności z językiem Java. Dla nas oznacza to przede wszystkim tyle, że możemy użyć Kotlina wszędzie tam, gdzie dotychczas króluje Java, a to otwiera całkiem dużo możliwości, wliczając tworzenie aplikacji na system Android.
Kotlin jest stosunkowo nowym i ciągle intensywnie rozwijanym językiem – ukazał się w 2011, ale wersja 1.0 jest dostępna dopiero od lutego 2016. Za stworzenie i rozwój Kotlina odpowiada firma JetBrains – twórcy m.in IntellIJ IDE – środowiska, na którym oparte jest Android Studio.

Czytaj dalej

Wi-Fi Direct

Każdy spotkał się z technologią Wi-Fi. Wielu z nas korzysta z niej na co dzień — zazwyczaj w celu uzyskania dostępu do Internetu. Nie zawsze jednak potrzebny jest nam Internet, aby wykonać określoną czynność. Czasem chcemy po prostu połączyć się z innym urządzeniem i przesłać jakieś dane — wysłać plik, wyświetlić coś na telewizorze Smart TV, zagrać w grę z lokalnym multiplayerem, podesłać dokument do druku w drukarce bezprzewodowej.

Podłączanie routera i konfigurowanie sieci nie jest zbyt poręczne i nie zawsze jest możliwe. Na myśl przychodzi technologia Bluetooth, jednak korzystając z niej, ograniczeni jesteśmy do powolnych połączeń i bardzo małego zasięgu.

Na szczęście istnieje alternatywna technologia do użycia właśnie w takich przypadkach. Jest nią Wi-Fi Direct.

Czytaj dalej