Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00315 005000 14833400 na godz. na dobę w sumie
Tworzenie gier na platformę Android 4 - książka
Tworzenie gier na platformę Android 4 - książka
Autor: Liczba stron: 288
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-5087-3 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie mobilne >> android
Porównaj ceny (książka, ebook, audiobook).

Stwórz wciągającą grę na platformę Android!

System operacyjny Android podbił rynek smartfonów, a obecnie uczestniczy w walce o panowanie na tabletach. Swoją pozycję zawdzięcza niezwykle intuicyjnemu interfejsowi użytkownika, szerokim możliwościom dostosowania do własnych potrzeb, genialnej wręcz integracji z usługami firmy Google oraz niewyobrażalnej ilości dostępnych aplikacji. Te wszystkie możliwości czynią z niego idealną platformę dla wszystkich programistów chcących stworzyć nową grę i zdobyć popularność. Jak się do tego zabrać?

Odpowiedzi dostarcza ta książka. W trakcie lektury poznasz cały proces tworzenia gry działającej zarówno na smartfonie, jak i na tablecie. Już tylko mały krok dzieli Cię od stworzenia pierwszej strzelanki 2D z tłem przewijanym z góry do dołu, a następnie czegoś bardziej zaawansowanego w trójwymiarze. Grafika 3D, sztuczna inteligencja przeciwników, zaawansowane efekty graficzne - to wszystko masz na wyciągnięcie ręki. Ponadto dowiesz się stąd, jak wykrywać kolizje, sterować postaciami oraz zapewnić najwyższą wydajność Twojej grze. Książka ta poprowadzi Cię krok po kroku poprzez rozwój dwóch różnych gier komórkowych, począwszy od pomysłu, a na kodzie skończywszy. Sięgnij po nią i opublikuj swoją pierwszą grę w Google Play!

Wykorzystaj potencjał platformy Android i:

Doskonałe źródło informacji dla pasjonatów platformy Android!

 

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Tytuł oryginału: Practical Android 4 Games Development Tłumaczenie: Szymon Pietrzak ISBN: 978-83-246-5087-3 Original edition copyright © 2011 by J. F. DiMarzio. All rights reserved. Polish edition copyright © 2013 by Helion S.A. All rights reserved. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/twgian Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/twgian.zip Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis treĂci Przedmowa .................................................................................................11 O autorze ....................................................................................................13 O recenzentach ...........................................................................................14 O twórcy grafiki do gier ..............................................................................15 PodziÚkowania ...........................................................................................16 WstÚp .........................................................................................................17 CzÚĂÊ I Planowanie i tworzenie gier 2D ..............................................19 Rozdziaï 1 Witaj w Ăwiecie gier na platformÚ Android ................................................21 Programowanie gier na platformę Android ...................................................................... 21 Rozpocznij od dobrej historii ............................................................................................... 22 Dlaczego historia jest ważna ......................................................................................... 23 Pisanie własnej historii ................................................................................................... 25 Droga przed Tobą .................................................................................................................. 27 Przygotowanie narzędzi do programowania na platformę Android ............................. 27 Instalacja OpenGL ES .................................................................................................... 29 Wybór wersji platformy Android ........................................................................................ 30 Podsumowanie ....................................................................................................................... 30 Rozdziaï 2 Star Fighter — strzelanka 2D .....................................................................31 Historia gry Star Fighter ....................................................................................................... 31 Z czego składa się gra? .......................................................................................................... 33 Czym jest silnik gry? ....................................................................................................... 34 Czym jest kod specyficzny dla gry? .............................................................................. 35 Silnik gry Star Fighter ..................................................................................................... 38 SPIS TRE¥CI Utworzenie projektu gry Star Fighter ................................................................................. 38 Podsumowanie ....................................................................................................................... 40 Rozdziaï 3 NaciĂnij Start: tworzenie menu ...................................................................41 Tworzenie ekranu powitalnego ........................................................................................... 41 Tworzenie czynności ...................................................................................................... 42 Tworzenie obrazu ekranu powitalnego ....................................................................... 47 Praca z plikiem R.java .................................................................................................... 49 Tworzenie pliku szablonu .............................................................................................. 50 Tworzenie efektów rozmycia ........................................................................................ 55 Zarządzanie wątkami gry ............................................................................................... 58 Tworzenie głównego menu .................................................................................................. 63 Dodawanie obrazów przycisków .................................................................................. 63 Ustawianie szablonów .................................................................................................... 65 Podpinanie przycisków .................................................................................................. 67 Dodawanie listenerów onClickListeners ..................................................................... 69 Dodawanie muzyki ................................................................................................................ 70 Tworzenie usługi muzycznej ......................................................................................... 72 Odtwarzanie swojej muzyki .......................................................................................... 77 Podsumowanie ....................................................................................................................... 79 Rozdziaï 4 WyĂwietlanie Ărodowiska ...........................................................................81 Renderowanie tła ................................................................................................................... 81 Tworzenie czynności gry ............................................................................................... 82 Tworzenie renderera ...................................................................................................... 86 Wczytywanie obrazka w OpenGL ................................................................................ 92 Przewijanie tła ............................................................................................................... 101 Dodawanie drugiej warstwy ............................................................................................... 108 Wczytywanie drugiej tekstury .................................................................................... 110 Przewijanie drugiej warstwy ....................................................................................... 111 Praca z macierzami ....................................................................................................... 112 Kończenie metody scrollBackground2() ................................................................... 113 Wyświetlanie gry z szybkością 60 klatek na sekundę ..................................................... 115 Zatrzymywanie pętli gry .............................................................................................. 116 Czyszczenie buforów OpenGL ................................................................................... 118 Modyfikowanie głównego menu ....................................................................................... 119 Podsumowanie ..................................................................................................................... 120 Rozdziaï 5 Tworzenie postaci gracza .........................................................................121 Animowanie sprite’ów ........................................................................................................ 121 Wczytywanie postaci gracza ............................................................................................... 123 Tworzenie tablic mapujących tekstury ...................................................................... 124 Nakładanie tekstury na postać gracza ........................................................................ 128 Dostosowanie pętli gry ................................................................................................. 131 6 SPIS TRE¥CI Poruszanie postacią ............................................................................................................. 132 Rysowanie domyślnego stanu postaci ........................................................................ 133 Oprogramowanie akcji PLAYER_RELEASE ............................................................ 135 Przesuwanie postaci w lewo ........................................................................................ 137 Wczytywanie odpowiedniego sprite’a ....................................................................... 138 Wczytywanie drugiej ramki animacji ........................................................................ 141 Przesuwanie postaci w prawo ..................................................................................... 144 Wczytywanie animacji przechyłu w prawo ............................................................... 145 Poruszanie postacią gracza przy pomocy zdarzenia dotykowego ................................ 148 Przetwarzanie zdarzenia MotionEvent ...................................................................... 148 Przechwytywanie akcji ACTION_UP i ACTION_DOWN ................................... 151 Dostosowanie opóźnienia FPS ........................................................................................... 153 Podsumowanie ..................................................................................................................... 154 Dodawanie przeciwników ........................................................................155 Porządkowanie kodu gry .................................................................................................... 155 Tworzenie klasy tekstury .................................................................................................... 156 Tworzenie klasy postaci przeciwnika ................................................................................ 160 Dodawanie nowego arkusza sprite’ów ...................................................................... 160 Tworzenie klasy SFEnemy ........................................................................................... 161 Krzywa Béziera .............................................................................................................. 165 Podsumowanie ..................................................................................................................... 170 Rozdziaï 6 Rozdziaï 7 Wyposaĝenie przeciwników w podstawowÈ sztucznÈ inteligencjÚ ..........171 Przygotowanie przeciwników na wprowadzenie sztucznej inteligencji ...................... 171 Logika tworzenia przeciwników ................................................................................. 173 Inicjalizacja przeciwników .......................................................................................... 175 Wczytywanie arkusza sprite’ów .................................................................................. 177 Przegląd sztucznej inteligencji ........................................................................................... 177 Tworzenie metody moveEnemy() .............................................................................. 178 Tworzenie pętli iterującej po tablicy enemies[ ] ....................................................... 178 Poruszanie każdym z przeciwników przy wykorzystaniu ich logiki ..................... 179 Tworzenie sztucznej inteligencji statku przechwytującego ........................................... 180 Dostosowywanie wierzchołków .................................................................................. 181 Namierzanie pozycji gracza ......................................................................................... 182 Implementowanie ruchu po prostej pochyłej ........................................................... 184 Tworzenie sztucznej inteligencji statku zwiadowczego ................................................. 189 Ustalanie losowego punktu docelowego dla statku zwiadowczego ....................... 190 Ruch po krzywej Béziera .............................................................................................. 191 Tworzenie sztucznej inteligencji statku wojennego ....................................................... 194 Podsumowanie ..................................................................................................................... 195 7 SPIS TRE¥CI Rozdziaï 8 Rozdziaï 9 Broñ siÚ! ...................................................................................................197 Tworzenie arkusza sprite’ów uzbrojenia .......................................................................... 197 Tworzenie klasy dla uzbrojenia .................................................................................. 198 Nadawanie trajektorii pociskom ....................................................................................... 201 Tworzenie tablicy uzbrojenia ...................................................................................... 201 Dodanie drugiego arkusza sprite’ów .......................................................................... 201 Inicjalizowanie uzbrojenia ........................................................................................... 202 Ruch pocisków .............................................................................................................. 203 Wykrywanie krawędzi ekranu .................................................................................... 204 Wywoływanie metody firePlayerWeapons() ............................................................ 206 Implementacja wykrywania kolizji ................................................................................... 207 Odnoszenie obrażeń w wyniku kolizji ....................................................................... 207 Tworzenie metody detectCollisions() ........................................................................ 208 Wykrywanie typów kolizji ........................................................................................... 209 Usuwanie wystrzelonych poza ekran pocisków ....................................................... 210 Dalsze poszerzanie zdobytej wiedzy ................................................................................. 211 Podsumowanie ..................................................................................................................... 212 Przegląd kluczowych fragmentów kodu gry 2D ............................................................. 212 Publikowanie swojej gry ..........................................................................229 Przygotowanie pliku AndroidManifest ............................................................................ 229 Przygotowanie do podpisania, ułożenia i wydania ......................................................... 230 Sprawdzenie gotowości pliku AndroidManifest ...................................................... 232 Tworzenie magazynu kluczy ....................................................................................... 233 Podsumowanie ..................................................................................................................... 235 CzÚĂÊ II Tworzenie gier 3D .................................................................237 Rozdziaï 10 Blob Hunter — tworzenie gier 3D ............................................................239 Porównanie gier 2D i 3D .................................................................................................... 239 Tworzenie własnego projektu 3D ...................................................................................... 240 BlobhunterActivity.java ............................................................................................... 240 BHGameView.java ........................................................................................................ 241 BHGameRenderer.java ................................................................................................ 241 BHEngine.java ............................................................................................................... 242 Tworzenie testu obiektu 3D ............................................................................................... 243 Tworzenie stałej ............................................................................................................ 243 Tworzenie klasy BHWalls ........................................................................................... 244 Tworzenie nowej instancji klasy BHWalls ................................................................ 246 Mapowanie obrazka ..................................................................................................... 247 Korzystanie z gluPerspective() .................................................................................... 248 Tworzenie metody drawBackground() ..................................................................... 250 Końcowe poprawki ....................................................................................................... 251 Podsumowanie ..................................................................................................................... 253 8 SPIS TRE¥CI Rozdziaï 11 Tworzenie realistycznego Ărodowiska ......................................................255 Używanie klasy BHWalls .................................................................................................... 255 Tworzenie korytarza z wielu instancji klasy BHWalls ............................................ 256 Używanie klasy BHCorridor .............................................................................................. 257 Tworzenie klasy BHCorridor ...................................................................................... 257 Budowanie wielu ścian przy pomocy tablicy vertices[] .......................................... 258 Tworzenie tablicy texture[] ......................................................................................... 260 Tworzenie metody draw() ........................................................................................... 263 Dodawanie tekstury ściany .......................................................................................... 266 Wywoływanie klasy BHCorridor ...................................................................................... 267 Podsumowanie ..................................................................................................................... 268 Rozdziaï 12 Poruszanie siÚ w trójwymiarowym Ărodowisku .......................................269 Tworzenie interfejsu sterowania ....................................................................................... 269 Modyfikowanie klasy BHEngine ................................................................................ 270 Modyfikowanie klasy BlobhunterActivity ................................................................ 271 Pozwalanie graczowi na ruch do przodu ................................................................... 272 Poruszanie się po korytarzu ............................................................................................... 273 Dostosowywanie widoku gracza ................................................................................. 275 Podsumowanie ..................................................................................................................... 276 Przegląd kluczowych fragmentów kodu gry 3D ............................................................. 276 Skorowidz .................................................................................................283 9 R O Z D Z I A ’ 5 „ „ „ Tworzenie postaci gracza Jak do dej pory zdążyłeś już wykonać całkiem sporo programowania i nauczyłeś się wiele o środowiskach OpenGL i Android — na tyle dużo, że powinieneś teraz dobrze znać drobne różnice pomiędzy OpenGL a innymi API, których mogłeś używać w przeszłości. Nie napisałeś jeszcze powalającej liczby linii kodu, jednak to, co już stworzyłeś, stanowi dobre podwaliny Twojej gry i daje całkiem niezły efekt wizualny. Udało Ci się zaprogramować tło o dwóch przewijających się z różną szybkością warstwach, tło muzyczne, ekran powitalny i główne menu gry. Wszystkie te rzeczy mają jednak, w kontekście grywalności gry, jedną wspólną cechę — są straszliwie nudne. Oznacza to, że gracz nie kupi Twojej gry tylko po to, by oglądać „odpicowane”, dwuwarstwowe tło przewijające się z góry na dół. Gracz potrzebuje odrobiny akcji i kontroli. Właśnie o tym wszystkim będzie traktował ten rozdział. Stworzysz w nim swoją postać gracza. Pod koniec rozdziału będziesz miał wyświetloną na ekranie animowaną postać, którą gracz będzie mógł sterować. W pierwszym podrozdziale poznasz podstawowy element programowania gier 2D — animację sprite’ów. Następnie, przy pomocy OpenGL ES, wczytasz różne sprite’y z pełnego ich arkusza, by stworzyć złudzenie animacji postaci. Nauczysz się wczytywać różnorodne sprite’y w kluczowych momentach akcji, aby sprawić, że Twoja postać będzie wyglądała tak, jakby przechylała się podczas lotu. Animowanie sprite’ów Jednym z najstarszych narzędzi w warsztacie programisty gier 2D jest animacja sprite’ów. Wróć na chwilę pamięcią do którejkolwiek ze swoich ulubionych gier 2D — istnieje spore prawdopodobieństwo, że animacja dowolnych postaci została w nich wykonana przy pomocy animacji sprite’ów. Technicznie rzecz biorąc, sprite to dowolny element graficzny gry 2D. Zgodnie z tą definicją Twoja postać gracza jest spritem. Sprite’y same w sobie są statycznymi obrazkami, wyświetlanymi na ekranie i niezmieniającymi się. Animacja sprite’ów to proces, którego użyjesz do „ożywienia” postaci głównego bohatera, nawet jeśli jest nim statek kosmiczny. „ Ostrzeĝenie: Nie myl animacji z poruszaniem. Poruszanie sprite’a (obrazu, tekstury, wierzchoïka czy modelu) po ekranie jest czymĂ zgoïa innym niĝ jego animacja; te dwa pojÚcia i umiejÚtnoĂci sÈ caïkowicie rozïÈczne. CZ}¥m I „ PLANOWANIE I TWORZENIE GIER 2D Animacja sprite’a przeprowadzana jest przy pomocy efektu przypominającego przewracanie kartek skoroszytu. Pomyśl o dowolnej dwuwymiarowej grze, np. Mario Brothers, który jest jednym z najlepszych przykładów platformówek 2D wykorzystujących animację sprite’ów. W tej grze sterujesz postacią Maria, by poruszała się w prawo albo w lewo po przewijającym się w bok środowisku. Mario chodzi, a czasem biegnie, w kierunku, w którym każesz mu się poruszać. Jego nogi w oczywisty sposób są animowane sekwencją kroków. Ta animacja kroków składa się w rzeczywistości z serii nieruchomych obrazków. Każdy z nich przedstawia inny moment wykonywania kroku. Kiedy gracz steruje postacią w lewo lub w prawo, różne obrazki są podmieniane, dając złudzenie, że Mario chodzi. W grze Star Fighter wykorzystasz tę samą metodę do stworzenia kilku animacji dla swojego głównego bohatera. Głównym bohaterem, a zarazem postacią gracza jest statek kosmiczny, nie będzie on więc potrzebował animacji chodzenia. Statki kosmiczne wymagają jednak innych animacji. W tym rozdziale stworzysz animację przechyłu lecącego statku w prawo i w lewo, a w kolejnych — animacje wybuchów i kolizji. Wspaniałą zaletą animacji sprite’ów jest to, że wszystkie umiejętności potrzebne do jej zaimplementowania zdobyłeś już w poprzednim rozdziale. Posiadłeś już bowiem umiejętność wczytywania tekstury do środowiska OpenGL i, co ważniejsze, nauczyłeś się mapować teksturę na zbiór wierzchołków. Klucz do animacji sprite’ów stanowi sposób, w jaki tekstura jest mapowana na wierzchołki. Tekstury używane w implementacji animacji sprite’a nie są oddzielnymi obrazkami. Czas i moc obliczeniowa wymagane do wczytywania i zmapowania nowej tekstury 60 razy na sekundę — gdyby udało Ci się osiągnąć taką szybkość — przekraczałyby znacznie możliwości urządzenia z systemem Android. Zamiast tego użyjesz więc arkusza sprite’ów. Arkusz sprite’ów to pojedynczy obrazek zawierający wszystkie odrębne obrazki wymagane do realizacji animacji sprite’a. Rysunek 5.1 przedstawia arkusz sprite’ów statku głównego bohatera gry. Rysunek 5.1. Arkusz sprite’ów postaci głównego bohatera „ Uwaga: Rysunek 5.1 nie przedstawia arkusza sprite’ów w caïoĂci. Rzeczywisty rozmiar wczytywanego do Ărodowiska OpenGL obrazu to 512×512 pikseli. Dolna czÚĂÊ obrazka, bÚdÈca jedynie przezroczystym obszarem, zostaïa przyciÚta, aby lepiej prezentowaï siÚ on w ksiÈĝce. W jaki sposób można więc animować obrazek składający się z mniejszych obrazków? W gruncie rzeczy to łatwiejsze, niż się spodziewasz. Wczytasz obrazek jako jedną teksturę, będziesz jednak wyświetlać jedynie ten jej fragment, który zawiera pokazywany graczowi obrazek. Kiedy będziesz chciał animować obrazek, użyjesz po prostu metody glTranslateF(), by przesunąć się do tej części tekstury, którą będziesz chciał wyświetlić. Nie martw się, jeśli nie rozumiesz jeszcze w pełni tego sposobu animacji — pojmiesz go, składając go w całość w kolejnych częściach tego rozdziału. Pierwszym krokiem jest stworzenie klasy, która będzie obsługiwała wczytywanie i rysowanie postaci gracza. 122 ROZDZIA’ 5. „ TWORZENIE POSTACI GRACZA „ Uwaga: ByÊ moĝe siÚ zastanawiasz, dlaczego statki w arkuszu sprite’ów sÈ skierowane w dóï, a nie w górÚ, tym bardziej ĝe postaÊ gracza ma siÚ znajdowaÊ na dole ekranu i lecieÊ w kierunku jego górnej krawÚdzi. Odwrotna orientacja sprite’ów wystÚpuje ze wzglÚdu na fakt, iĝ OpenGL renderuje wszystkie bitmapy od ostatniej linii do pierwszej. Dlatego teĝ kiedy OpenGL wyrenderuje ten arkusz sprite’ów, na ekranie pojawi siÚ on w formie ukazanej na rysunku 5.2. Rysunek 5.2. Wygląd arkusza sprite’ów na ekranie Oczywiście mógłbyś narysować arkusz sprite’ów poprawnie, a następnie użyć środowiska OpenGL do odwrócenia tekstury w prawidłowy sposób. Odwrócenie arkusza sprite’ów przy pomocy dowolnego narzędzia do obróbki obrazów jest jednak dość proste, a dzięki temu oszczędzasz środowisku OpenGL dodatkowej pracy potrzebnej do odwrócenia za Ciebie tekstury. Wczytywanie postaci gracza W poprzednim rozdziale stworzyłeś klasę, która wczytywała obraz tła jako teksturę, a następnie rysowała ten obraz na żądanie. Mechanizmy, których użyłeś do stworzenia tej klasy, są tymi samymi mechanizmami, których będziesz potrzebował, by wczytać i narysować swojego głównego bohatera. Dokonasz w nich drobnych zmian pozwalających Ci na zastosowanie arkusza sprite’ów, poza tym jednak kod powinien Ci wyglądać znajomo. Rozpocznij od stworzenia w bazowym pakiecie projektu nowej klasy o nazwie SFGoodGuy: package com.proandroidgames; public class SFGoodGuy { } W klasie tej umieść zalążki konstruktora, metody draw() i metody loadTexture(). „ Wskazówka: PamiÚtaj, ĝe pracujÈc w Ărodowisku Eclipse, moĝesz uĝyÊ skrótu Alt+Shift+O, by wykryÊ wszystkie pominiÚte przez siebie, a potrzebne do dziaïania importy. package com.proandroidgames; import javax.microedition.khronos.opengles.GL10; import android.content.Context; public class SFGoodGuy { 123 CZ}¥m I „ PLANOWANIE I TWORZENIE GIER 2D public SFGoodGuy() { } public void draw(GL10 gl) { } public void loadTexture(GL10 gl, int texture, Context context) { } } Następnie stwórz bufory, których będziesz używał wewnątrz klasy. Powinny one wyglądać identycznie jak te, które w poprzednim rozdziale stosowałeś do wczytywania tła. Możesz także dodać kod tworzący tablicę vertices[]. Tablica ta będzie identyczna z tą używaną w klasie obsługującej tło. package com.proandroidgames; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; import android.content.Context; public class SFGoodGuy { private FloatBuffer vertexBuffer; private FloatBuffer textureBuffer; private ByteBuffer indexBuffer; private int[] textures = new int[1]; private float vertices[] = { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, }; public SFGoodGuy() { } public void draw(GL10 gl) { } public void loadTexture(GL10 gl, int texture, Context context) { } } Możesz teraz stworzyć tablicę mapującą teksturę. Tworzenie tablic mapujących tekstury Mapowanie tekstur to miejsce, w którym klasa SFGoodGuy będzie się różniła od klasy wczytującej tło. Tekstura, którą wczytasz do klasy, jest dużym arkuszem sprite’ów zawierającym pięć obrazów reprezentujących głównego bohatera. Twoim zadaniem jest wyświetlenie w danej chwili tylko jednego z tych obrazów. 124 ROZDZIA’ 5. „ TWORZENIE POSTACI GRACZA Kluczem do zrozumienia, w jaki sposób należy przekazać środowisku OpenGL lokalizację obrazka, który chcesz wyświetlić, jest rozmieszczenie obrazków w arkuszu sprite’ów. Przyjrzyj się raz jeszcze arkuszowi sprite’ów przedstawionemu na rysunku 5.1. Zauważ, że obrazki rozmieszczone są równomiernie, z czterema obrazkami w pierwszym rzędzie i jednym obrazkiem w drugim. Mając jedynie 4 obrazki w pierwszym rzędzie tekstury i zakładając, że cała tekstura ma długość i wysokość 1 jednostki, możesz łatwo wywnioskować, że będziesz musiał wyświetlić jedynie szesnastą część całej tekstury, by wyświetlić jeden obrazek z pierwszego rzędu. Oznacza to, że zamiast mapować całą teksturę, od (0, 0) do (1, 1), jak to zrobiłeś w przypadku tła, będziesz mapował jedynie jej szesnastą część, od (0, 0) do (0,25, 0,25). Będziesz mapował, a co za tym idzie, wyświetlał, jedynie pierwszy obrazek statku, używając zaledwie 0,25×0,25, czyli 1/16 tekstury. Stwórz swoją tablicę tekstury, jak przedstawiono to poniżej: package com.proandroidgames; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; import android.content.Context; public class SFGoodGuy { private FloatBuffer vertexBuffer; private FloatBuffer textureBuffer; private ByteBuffer indexBuffer; private int[] textures = new int[1]; private float vertices[] = { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, }; private float texture[] = { 0.0f, 0.0f, 0.25f, 0.0f, 0.25f, 0.25f, 0.0f, 0.25f, }; public SFGoodGuy() { } public void draw(GL10 gl) { } public void loadTexture(GL10 gl, int texture, Context context) { } } Tablica krawędzi, metoda draw() oraz konstruktor są identyczne z tymi użytymi w klasie SFBackground: package com.proandroidgames; import java.nio.ByteBuffer; import java.nio.ByteOrder; 125 CZ}¥m I „ PLANOWANIE I TWORZENIE GIER 2D import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; import android.content.Context; public class SFGoodGuy { private FloatBuffer vertexBuffer; private FloatBuffer textureBuffer; private ByteBuffer indexBuffer; private int[] textures = new int[1]; private float vertices[] = { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, }; private float texture[] = { 0.0f, 0.0f, 0.25f, 0.0f, 0.25f, 0.25f, 0.0f, 0.25f, }; private byte indices[] = { 0, 1, 2, 0, 2, 3, }; public SFGoodGuy() { ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4); byteBuf.order(ByteOrder.nativeOrder()); vertexBuffer = byteBuf.asFloatBuffer(); vertexBuffer.put(vertices); vertexBuffer.position(0); byteBuf = ByteBuffer.allocateDirect(texture.length * 4); byteBuf.order(ByteOrder.nativeOrder()); textureBuffer = byteBuf.asFloatBuffer(); textureBuffer.put(texture); textureBuffer.position(0); indexBuffer = ByteBuffer.allocateDirect(indices.length); indexBuffer.put(indices); indexBuffer.position(0); } public void draw(GL10 gl) { gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]); gl.glFrontFace(GL10.GL_CCW); gl.glEnable(GL10.GL_CULL_FACE); gl.glCullFace(GL10.GL_BACK); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 126 ROZDZIA’ 5. „ TWORZENIE POSTACI GRACZA gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer); gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_BYTE, indexBuffer); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); gl.glDisable(GL10.GL_CULL_FACE); } public void loadTexture(GL10 gl, int texture, Context context) { } } Zanim zakończysz pracę nad klasą SFGoodGuy, musisz dokonać w niej jeszcze jednej zmiany. W klasie SFBackground w metodzie loadTexture() podawałeś do metody glTexParameterf() parametr GL_REPEAT, by uruchomić powtarzanie tekstury w miarę przesuwania wierzchołków. Nie jest to jednak potrzebne w przypadku postaci głównego bohatera, dlatego też zmienisz ten parametr na GL_CLAMP_TO_EDGE. Dokończ swoją implementację klasy SFGoodGuy, umieszczając w metodzie loadTexture() następujący kod: ... public void loadTexture(GL10 gl, int texture, Context context) { InputStream imagestream = context.getResources().openRawResource(texture); Bitmap bitmap = null; try { bitmap = BitmapFactory.decodeStream(imagestream); } catch (Exception e) { } finally { try { imagestream.close(); imagestream = null; } catch (IOException e) { } } gl.glGenTextures(1, textures, 0); gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); bitmap.recycle(); } } Jesteś teraz w posiadaniu w pełni funkcjonalnej klasy, która wczyta teksturę postaci gracza jako arkusz sprite’ów, wyświetli pierwszego sprite’a z arkusza i nie będzie zawijać tekstury w momencie, gdy postać ta będzie się poruszała. 127 CZ}¥m I „ PLANOWANIE I TWORZENIE GIER 2D Nakładanie tekstury na postać gracza Kolejnym krokiem na drodze do wczytania postaci gracza jest utworzenie nowej instancji klasy SFGoodGuy i wczytanie do niej tekstury. Zapisz i zamknij plik klasy SFGoodGuy — na razie nie będziesz musiał dodawać do niego więcej kodu. Dodaj teraz do klasy SFEngine kilka prostych zmiennych i stałych. Będziesz z nich korzystał w pętli gry. W pierwszej kolejności dodasz zmienną o nazwie playerFlightAction. Będziesz jej używał do śledzenia akcji, które gracz wykonał, aby odpowiedzieć na nie odpowiednio w pętli gry. package com.proandroidgames; import android.content.Context; import android.content.Intent; import android.view.View; public class SFEngine { ... public static int playerFlightAction = 0; /* Zamknij wątki gry i wyjdź z niej */ public boolean onExit(View v) { try { Intent bgmusic = new Intent(context, SFMusic.class); context.stopService(bgmusic); musicThread.stop(); return true; } catch (Exception e) { return false; } } } Następnie dodaj do projektu plik opisanego na początku tego podrozdziału arkusza sprite’ów (good_sprite.png) i utwórz w klasie silnika gry stałą wskazującą na odpowiadający mu zasób. package com.proandroidgames; import android.content.Context; import android.content.Intent; import android.view.View; public class SFEngine { ... public static int playerFlightAction = 0; public static final int PLAYER_SHIP = R.drawable.good_sprite; /* Zamknij wątki gry i wyjdź z niej */ public boolean onExit(View v) { try { Intent bgmusic = new Intent(context, SFMusic.class); context.stopService(bgmusic); musicThread.stop(); return true; } catch (Exception e) { return false; } } } 128 Kolejne trzy stałe będą opisywały akcje, które może wykonać gracz. Ich wartości będą przypisywane do zmiennej playerFlightAction, kiedy gracz będzie próbował sterować postacią. ROZDZIA’ 5. „ TWORZENIE POSTACI GRACZA package com.proandroidgames; import android.content.Context; import android.content.Intent; import android.view.View; public class SFEngine { ... public static int playerFlightAction = 0; public static final int PLAYER_SHIP = R.drawable.good_sprite; public static final int PLAYER_BANK_LEFT_1 = 1; public static final int PLAYER_RELEASE = 3; public static final int PLAYER_BANK_RIGHT_1 = 4; /* Zamknij wątki gry i wyjdź z niej */ public boolean onExit(View v) { try { Intent bgmusic = new Intent(context, SFMusic.class); context.stopService(bgmusic); musicThread.stop(); return true; } catch (Exception e) { return false; } } } W zależności od tego, jak spostrzegawczy jesteś, jeśli chodzi o stałe dodane przed chwilą do klasy SFEngine, być może już się zastanawiasz, dlaczego PLAYER_BANK_LEFT_1 ma wartość 1, a PLAYER_RELEASE wartość 3. Wartości te będą reprezentowały etapy animacji Twojego sprite’a. W arkuszu sprite’ów znajdują się dwa etapy w animacji przechyłu w lewo i dwa etapy w animacji przechyłu w prawo. W kodzie pętli jednakże zauważysz, że pomiędzy stałymi PLAYER_BANK_LEFT_1 a stałymi PLAYER_RELEASE znajduje się PLAYER_BANK_LEFT_2 o wartości 2, stała ta nie będzie jednak obecna w klasie SFEngine. Rozwiązanie to z pewnością wyda Ci się sensowniejsze, kiedy zobaczysz je w akcji w dalszych częściach książki. Kolejna stała, której będziesz potrzebował, będzie wskazywała, ile przebiegów pętli będzie odpowiadało jednej klatce animacji sprite’a. Pamiętaj, że wielką różnicę pomiędzy postacią gracza a tłem stanowi fakt, iż animacja postaci zachodzi w momencie jej poruszania się po ekranie. Śledzenie tej animacji jest niełatwym zadaniem. Główna pętla gry działa z szybkością 60 przebiegów na sekundę. Gdybyś uruchamiał nową klatkę animacji sprite’a w każdym przebiegu pętli, Twoja animacja zakończyłaby się, zanim gracz miałby szansę się nią nacieszyć. Stała PLAYER_FRAMES_BETWEEN_ANI przyjmie wartość 9, co oznacza, że jedna klatka animacji sprite’a będzie rysowana co dziewięć iteracji głównej pętli gry. package com.proandroidgames; import android.content.Context; import android.content.Intent; import android.view.View; public class SFEngine { ... public static int playerFlightAction = 0; public static final int PLAYER_SHIP = R.drawable.good_sprite; public static final int PLAYER_BANK_LEFT_1 = 1; 129 CZ}¥m I „ PLANOWANIE I TWORZENIE GIER 2D public static final int PLAYER_RELEASE = 3; public static final int PLAYER_BANK_RIGHT_1 = 4; public static final int PLAYER_FRAMES_BETWEEN_ANI = 9; /* Zamknij wątki gry i wyjdź z niej */ public boolean onExit(View v) { try { Intent bgmusic = new Intent(context, SFMusic.class); context.stopService(bgmusic); musicThread.stop(); return true; } catch (Exception e) { return false; } } } Na koniec dodaj jeszcze jedną stałą i jedną zmienną. Będą one reprezentowały prędkość, z jaką statek gracza będzie się poruszał od lewej do prawej, oraz aktualną pozycję statku na osi x. package com.proandroidgames; import android.content.Context; import android.content.Intent; import android.view.View; public class SFEngine { ... public static int playerFlightAction = 0; public static final int PLAYER_SHIP = R.drawable.good_sprite; public static final int PLAYER_BANK_LEFT_1 = 1; public static final int PLAYER_RELEASE = 3; public static final int PLAYER_BANK_RIGHT_1 = 4; public static final int PLAYER_FRAMES_BETWEEN_ANI = 9; public static final float PLAYER_BANK_SPEED = .1f; public static float playerBankPosX = 1.75f; /* Zamknij wątki gry i wyjdź z niej */ public boolean onExit(View v) { try { Intent bgmusic = new Intent(context, SFMusic.class); context.stopService(bgmusic); musicThread.stop(); return true; } catch (Exception e) { return false; } } } Plik klasy SFEngine zawiera teraz cały kod potrzebny Ci do zaimplementowania postaci gracza. Zapisz go i zamknij. Otwórz plik SFGameRenderer.java. Zawiera on kod głównej pętli Twojej gry. W poprzednim rozdziale stworzyłeś pętlę gry i dodałeś dwie metody rysujące i przewijające dwie niezależne warstwy tła. Teraz dodasz do pętli gry kod rysujący postać gracza i poruszający nią. 130 Dostosowanie pętli gry Pierwszym krokiem jest stworzenie zmiennej player1, przechowującej nową instancję klasy SFGoodGuy: ROZDZIA’ 5. „ TWORZENIE POSTACI GRACZA ... public class SFGameRenderer implements Renderer { private SFBackground background = new SFBackground(); private SFBackground background2 = new SFBackground(); private SFGoodGuy player1 = new SFGoodGuy(); private float bgScroll1; private float bgScroll2; ... } Zmienna player1 będzie używana w taki sam sposób jak zmienne background i background2. Wywołasz jej metody loadTexture() i draw(), by wczytać do gry postać gracza. Musisz także utworzyć zmienną, która będzie śledziła, ile iteracji pętli gry zostało wykonanych, tak abyś wiedział, kiedy przerzucać ramki w swojej animacji sprite’a. ... public class SFGameRenderer implements Renderer { private SFBackground background = new SFBackground(); private SFBackground background2 = new SFBackground(); private SFGoodGuy player1 = new SFGoodGuy(); private int goodGuyBankFrames = 0; private float bgScroll1; private float bgScroll2; ... } Następnie znajdź w klasie renderera SFGameRenderer metodę onSurfaceCreated(). Obsługuje ona wczytywanie tekstur gry. W poprzednim rozdziale wywołałeś w tej metodzie metody wczytujące tekstury do obiektów background i background2. Teraz musisz dodać do niej wywołanie metody loadTexture() zmiennej player1. package com.proandroidgames; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class SFGameRenderer implements Renderer { private SFBackground background = new SFBackground(); private SFBackground background2 = new SFBackground(); private SFGoodGuy player1 = new SFGoodGuy(); private int goodGuyBankFrames = 0; ... @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { gl.glEnable(GL10.GL_TEXTURE_2D); gl.glClearDepthf(1.0f); gl.glEnable(GL10.GL_DEPTH_TEST); 131 CZ}¥m I „ PLANOWANIE I TWORZENIE GIER 2D gl.glDepthFunc(GL10.GL_LEQUAL); gl.glEnable(GL10.GL_BLEND); gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE); background.loadTexture(gl, SFEngine.BACKGROUND_LAYER_ONE, SFEngine.context); background2.loadTexture(gl, SFEngine.BACKGROUND_LAYER_TWO, SFEngine.context); player1.loadTexture(gl, SFEngine.PLAYER_SHIP, SFEngine.context); } } Jak dotąd cały kod był dość podstawowy — tworzył i wczytywał teksturę. Czas teraz na bardziej treściwą część rozdziału — napisanie metody, która będzie kontrolowała sterowanie postacią gracza. Poruszanie postaciÈ Ten podrozdział pomoże Ci stworzyć kod potrzebny do poruszania postacią gracza na ekranie. W tym celu stworzysz nową metodę, wykonującą zadania związane z poruszaniem postacią gracza, którą następnie będziesz wywoływał w głównej pętli swej gry. W klasie SFGameRenderer stwórz nową metodę przyjmującą jako parametr referencję do instancji klasy GL10. package com.proandroidgames; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class SFGameRenderer implements Renderer { … private void movePlayer1(GL10 gl) { } … } Wewnątrz metody movePlayer1() użyjesz instrukcji switch sprawdzającej wartość zmiennej całkowitoliczbowej playerFlightAction, którą wcześniej w tym rozdziale dodałeś do klasy SFEngine. Jeżeli nigdy wcześniej nie używałeś tej instrukcji, switch sprawdzi wartość podanego do niego obiektu (playerFlightAction) i wykona odpowiedni kod w zależności od wartości tego obiektu. Przypadki obsługiwane w tej instrukcji switch to PLAYER_BANK_LEFT_1, PLAYER_RELEASE, PLAYER_BANK_RIGHT_1 oraz default (domyślny). package com.proandroidgames; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class SFGameRenderer implements Renderer { … 132 ROZDZIA’ 5. „ TWORZENIE POSTACI GRACZA private void movePlayer1(GL10 gl) { switch (SFEngine.playerFlightAction) { case SFEngine.PLAYER_BANK_LEFT_1: break; case SFEngine.PLAYER_BANK_RIGHT_1: break; case SFEngine.PLAYER_RELEASE: break; default: break; } } … } Rozpocznijmy od przypadku domyślnego (default). Zostanie on wywołany, gdy gracz nie wykonał swoją postacią żadnej akcji. Rysowanie domyślnego stanu postaci W tej chwili wierzchołki mają taki sam rozmiar jak cały ekran. Gdybyś więc teraz narysował postać gracza, zajmowałaby ona cały ekran. Aby postać ta dobrze wyglądała w grze, będziesz ją musiał przeskalować o około 75 . Aby to zrobić, użyjesz metody glScalef(). Przemnożenie skali przez 0,25 zmniejszy rozmiar statku do jednej czwartej jego oryginalnego rozmiaru. Pociąga to za sobą istotne konsekwencje, których musisz być świadomy. W poprzednim rozdziale miałeś okazję zauważyć, że aby przeskalować wierzchołki lub dokonać ich translacji, musisz pracować w trybie macierzy modelu. Dowolna operacja wykonywana w dowolnym trybie macierzy wpływa na wszystkie elementy, które obejmuje ten tryb. Dlatego też jeśli przeskalujesz statek gracza przez 0,25, przeskalujesz także całe osie x i y. Innymi słowy, jeżeli przy domyślnej skali 0 (pełen ekran) osie x i y rozpoczynały się w 0, a kończyły w 1, po przemnożeniu skali przez 0,25 osie te będą rozpoczynały się w 0, a kończyły w 4. To ważna dla Ciebie informacja, ponieważ próbując śledzić położenie gracza, będziesz musiał pamiętać, że choć tło może się przewijać od 0 do 1, gracz może się poruszać od 0 do 4. Wczytaj teraz widok macierzy modelu i przeskaluj postać gracza o 0,25 na osiach x i y. package com.proandroidgames; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class SFGameRenderer implements Renderer { … private void movePlayer1(GL10 gl) { switch (SFEngine.playerFlightAction) { case SFEngine.PLAYER_BANK_LEFT_1: break; case SFEngine.PLAYER_BANK_RIGHT_1: break; case SFEngine.PLAYER_RELEASE: break; default: gl.glMatrixMode(GL10.GL_MODELVIEW); 133 CZ}¥m I „ PLANOWANIE I TWORZENIE GIER 2D gl.glLoadIdentity(); gl.glPushMatrix(); gl.glScalef(.25f, .25f, 1f); break; } } … } Następnie dokonaj translacji macierzy modelu na osi x o wartość zmiennej playerBankPosX. Zmienna ta będzie przechowywała aktualną pozycję postaci gracza na osi x. Dlatego też za każdym razem, gdy gracz nie podejmie żadnej akcji, jego postać pozostanie w miejscu, w którym znajdowała się ostatnio. package com.proandroidgames; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class SFGameRenderer implements Renderer { … private void movePlayer1(GL10 gl) { switch (SFEngine.playerFlightAction) { case SFEngine.PLAYER_BANK_LEFT_1: break; case SFEngine.PLAYER_BANK_RIGHT_1: break; case SFEngine.PLAYER_RELEASE: break; default: gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); gl.glPushMatrix(); gl.glScalef(.25f, .25f, 1f); gl.glTranslatef(SFEngine.playerBankPosX, 0f, 0f); break; } } … } Kiedy postać gracza jest w spoczynku, nie ma potrzeby wykonywania dodatkowych akcji, wczytaj więc macierz tekstur i upewnij się, że jest ona w położeniu domyślnym, czyli na pierwszym obrazku w arkuszu sprite’ów. Pamiętaj, iż to właśnie tryb macierzy tekstur będzie przez Ciebie wykorzystywany do zmieniania pozycji tekstury w arkuszu sprite’ów, a co za tym idzie, do „przerzucania” kolejnych klatek animacji. Jeśli gracz nie porusza swoją postacią, nie powinna być ona animowana, dlatego macierz tekstur powinna się znajdować w swojej pierwszej, domyślnej pozycji. package com.proandroidgames; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; 134 ROZDZIA’ 5. „ TWORZENIE POSTACI GRACZA import android.opengl.GLSurfaceView.Renderer; public class SFGameRenderer implements Renderer { … private void movePlayer1(GL10 gl) { switch (SFEngine.playerFlightAction) { case SFEngine.PLAYER_BANK_LEFT_1: break; case SFEngine.PLAYER_BANK_RIGHT_1: break; case SFEngine.PLAYER_RELEASE: break; default: gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); gl.glPushMatrix(); gl.glScalef(.25f, .25f, 1f); gl.glTranslatef(SFEngine.playerBankPosX, 0f, 0f); gl.glMatrixMode(GL10.GL_TEXTURE); gl.glLoadIdentity(); gl.glTranslatef(0.0f, 0.0f, 0.0f); player1.draw(gl); gl.glPopMatrix(); gl.glLoadIdentity(); break; } } … } Kolejnym oprogramowywanym przez Ciebie przypadkiem w instrukcji switch będzie PLAYER_RELEASE. Akcja PLAYER_RELEASE będzie wywoływana, kiedy gracz zwolni sterowanie po przesunięciu postaci. Choć nie stworzyłeś jeszcze faktycznych mechanizmów sterowania grą, gracz będzie dotykał elementu sterującego, aby przesunąć swoją postać. Kiedy gracz puści ten element, przerywając w ten sposób ruch postaci, wywołana zostanie akcja PLAYER_RELEASE. Oprogramowanie akcji PLAYER_RELEASE Na tę chwilę przypadek PLAYER_RELEASE będzie wykonywał te same czynności co przypadek domyślny — postać gracza pozostanie tam, gdzie ją pozostawiono na ekranie, i niezależnie od tego, która z tekstur z arkusza sprite’ów była wyświetlana, nastąpi powrót do pierwszej tekstury w arkuszu. Skopiuj i wklej cały blok kodu z przypadku default do PLAYER_RELEASE. package com.proandroidgames; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class SFGameRenderer implements Renderer { … private void movePlayer1(GL10 gl) { switch (SFEngine.playerFlightAction) { 135 CZ}¥m I „ PLANOWANIE I TWORZENIE GIER 2D case SFEngine.PLAYER_BANK_LEFT_1: break; case SFEngine.PLAYER_BANK_RIGHT_1: break; case SFEngine.PLAYER_RELEASE: gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); gl.glPushMatrix(); gl.glScalef(.25f, .25f, 1f); gl.glTranslatef(SFEngine.playerBankPosX, 0f, 0f); gl.glMatrixMode(GL10.GL_TEXTURE); gl.glLoadIdentity(); gl.glTranslatef(0.0f, 0.0f, 0.0f); player1.draw(gl); gl.glPopMatrix(); gl.glLoadIdentity(); break; … } } … } Zanim skończysz pracę nad przypadkiem PLAYER_RELEASE, musisz dodać jeszcze jedną linię kodu. Wcześniej w tym rozdziale dowiedziałeś się, że nie możesz zmieniać klatek animacji swojego sprite’a z taką samą szybkością, jaką ma główna pętla gry (60 klatek na sekundę), zawierając bowiem jedynie dwie ramki animacji sprite’a, Twoja animacja skończyłaby się, zanim gracz by ją w ogóle zauważył. Potrzebujesz więc zmiennej przechowującej liczbę przebiegów głównej pętli gry, które miały już miejsce. Wiedząc, ile razy pętla została już wykonana, możesz tę liczbę porównać z wartością stałej PLAYER_FRAMES_BETWEEN_ANI, by określić, kiedy przerzucać klatki animacji sprite’a. Utworzona przez Ciebie wcześniej w tym rozdziale zmienna goodGuyBankFrames będzie przez Ciebie używana do śledzenia liczby wykonanych iteracji głównej pętli gry. Wewnątrz kodu obsługującego przypadek PLAYER_RELEASE dodaj wyróżnioną poniżej linię kodu, aby zwiększyć o jeden wartość zmiennej goodGuyBankFrames w każdej iteracji głównej pętli. package com.proandroidgames; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class SFGameRenderer implements Renderer { … private void movePlayer1(GL10 gl) { switch (SFEngine.playerFlightAction) { case SFEngine.PLAYER_BANK_LEFT_1: break; case SFEngine.PLAYER_BANK_RIGHT_1: break; case SFEngine.PLAYER_RELEASE: gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); gl.glPushMatrix(); gl.glScalef(.25f, .25f, 1f); gl.glTranslatef(SFEngine.playerBankPosX, 0f, 0f); 136 ROZDZIA’ 5. „ TWORZENIE POSTACI GRACZA gl.glMatrixMode(GL10.GL_TEXTURE); gl.glLoadIdentity(); gl.glTranslatef(0.0f, 0.0f, 0.0f); player1.draw(gl); gl.glPopMatrix(); gl.glLoadIdentity(); goodGuyBankFrames += 1; break; … } } … } Przypadki PLAYER_RELEASE i default były najłatwiejszymi z czterech możliwych przypadków w Twojej metodzie movePlayer1(). Musisz teraz stworzyć kod obsługujący wywołanie akcji PLAYER_BANK_LEFT_1. Akcja PLAYER_BANK_LEFT_1 jest wywoływana, kiedy gracz użyje elementów interfejsu sterowania, by przechylić statek głównego bohatera w lewo. Oznacza to nie tylko, że musisz przesunąć postać gracza w lewo na osi x, lecz także, że musisz stworzyć animację postaci, używając dwóch reprezentujących przechył w lewo obrazków z arkusza sprite’ów. Przesuwanie postaci w lewo W środowisku OpenGL operacje przemieszczania postaci wzdłuż osi x i zmiana pozycji w arkuszu sprite’ów wykorzystują dwa różne tryby macierzy. Do przesunięcia postaci wzdłuż osi x będziesz musiał użyć trybu macierzy modelu; przesunięcie tekstury w arkuszu sprite’ów, a co za tym idzie, stworzenie animacji przechyłu, będzie wykorzystywało tryb macierzy tekstur. Rozpocznijmy od trybu macierzy modelu. Pierwszym krokiem jest wczytanie trybu macierzy modelu i ustawienie jego skali na 0,25 na osiach x i y. package com.proandroidgames; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class SFGameRenderer implements Renderer { … private void movePlayer1(GL10 gl) { switch (SFEngine.playerFlightAction) { case SFEngine.PLAYER_BANK_LEFT_1: gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); gl.glPushMatrix(); gl.glScalef(.25f, .25f, 1f); break; … } } … } 137 CZ}¥m I „ PLANOWANIE I TWORZENIE GIER 2D Następnie, używając metody glTranslatef(), przesuniesz wierzchołki wzdłuż osi x. Odejmiesz wartość PLAYER_BANK_SPEED od aktualnej pozycji postaci gracza na osi x, przechowywanej w zmiennej playerBankPosX. (Ponieważ chcesz przesunąć postać w lewo wzdłuż osi x, wykonujesz operację odejmowania w celu uzyskania docelowej pozycji postaci. Gdybyś poruszał postać w prawo, użyłbyś operacji dodawania). Następnie zastosujesz metodę glTranslatef(), by przesunąć wierzchołki na pozycję określoną przez playerBankPosX. package com.proandroidgames; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class SFGameRenderer implements Renderer { … private void movePlayer1(GL10 gl) { switch (SFEngine.playerFlightAction) { case SFEngine.PLAYER_BANK_LEFT_1: gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); gl.glPushMatrix(); gl.glScalef(.25f, .25f, 1f); SFEngine.playerBankPosX -= SFEngine.PLAYER_BANK_SPEED; gl.glTranslatef(SFEngine.playerBankPosX, 0f, 0f); break; … } } … } Skoro przemieszczasz już postać w lewo wzdłuż osi x, musisz jeszcze wyświetlić kolejną ramkę animacji sprite’a. Wczytywanie odpowiedniego sprite’a Przypatrz się raz jeszcze arkuszowi sprite’ów przedstawionemu na rysunku 5.1. Zauważ, że dwie klatki animacji odpowiadające przechyłowi na lewą stronę to czwarta klatka w pierwszym rzędzie i pierwsza w drugim (pamiętaj, że choć wydaje Ci się, iż arkusz sugeruje odwrotny kierunek przechyłu, jest on odwracany w pionie tak, że klatki, które sprawiają wrażenie zawierania ruchu w prawo, będą w rezultacie wyrenderowane jako ruch w lewo). Wczytaj tryb macierzy tekstury i dokonaj translacji tekstury, aby wyświetlić czwarty obrazek w pierwszym rzędzie. Ponieważ translacja tekstury jest dokonywana w oparciu o wartości procentowe, będziesz musiał wykonać trochę obliczeń. Ze względu na to, iż w rzędzie umieszczono tylko 4 obrazki, obliczenia te będą dość proste. Oś x arkusza sprite’ów ma zakres od 0 do 1. Kiedy podzielisz ten zakres na 4 części, każdy z obrazków zajmie 0,25 osi x. Dlatego też aby przesunąć arkusz stylów na czwarty obrazek w linii, musisz dokonać translacji o 0,75. (Pierwszy z obrazków zajmuje wartości od 0 do 0,24, drugi od 0,25 do 0,49, trzeci od 0,5 do 0,74, a czwarty od 0,75 do 1). 138 ROZDZIA’ 5. „ TWORZENIE POSTACI GRACZA package com.proandroidgames; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class SFGameRenderer implements Renderer { … private void movePlayer1(GL10 gl) { switch (SFEngine.playerFlightAction) { case SFEngine.PLAYER_BANK_LEFT_1: gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); gl.glPushMatrix(); gl.glScalef(.25f, .25f, 1f); SFEngine.playerBankPosX -= SFEngine.PLAYER_BANK_SPEED; gl.glTranslatef(SFEngine.playerBankPosX, 0f, 0f); gl.glMatrixMode(GL10.GL_TEXTURE); gl.glLoadIdentity(); gl.glTranslatef(0.75f, 0.0f, 0.0f); break; … } } … } Ostatnim krokiem, który musisz uczynić, zanim zlecisz narysowanie statku, jest zwiększenie licznika goodGuyBankFrames, byś mógł rozpocząć wyłapywanie momentów, w których należy zmienić ramkę na kolejną z arkusza sprite’ów. package com.proandroidgames; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class SFGameRenderer implements Renderer { … private void movePlayer1(GL10 gl) { switch (SFEngine.playerFlightAction) { case SFEngine.PLAYER_BANK_LEFT_1: gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); gl.glPushMatrix(); gl.glScalef(.25f, .25f, 1f); SFEngine.playerBankPosX -= SFEngine.PLAYER_BANK_SPEED; gl.glTranslatef(SFEngine.playerBankPosX, 0f, 0f); gl.glMatrixMode(GL10.GL_TEXTURE); gl.glLoadIdentity(); gl.glTranslatef(0.75f, 0.0f, 0.0f); goodGuyBankFrames += 1; 139 CZ}¥m I „ PLANOWANIE I TWORZENIE GIER 2D break; … } } … } Rozwiązanie to ma jednak jedną istotną wadę. Gracz może teraz przesuwać postać w lewo wzdłuż osi x, co spowoduje, że sprite statku zmieni się na pierwszy ze sprite’ów animacji przechyłu na lewo. Problem w tym, że kod w przedstawionej powyżej formie pozwala przesuwać postać gracza w lewo w nieskończoność. Musisz owinąć blok kodu poruszający postacią w instrukcję if…else, sprawdzającą, czy postać nie osiągnęła pozycji 0 na osi x. Jeśli postać znajduje się na pozycji 0, czyli przy lewej krawędzi ekranu, należy wstrzymać ruch i przywrócić animację do domyślnego sprite’a. package com.proandroidgames; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class SFGameRenderer implements Renderer { … private void movePlayer1(GL10 gl) { switch (SFEngine.playerFlightAction) { case SFEngine.PLAYER_BANK_LEFT_1: gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); gl.glPushMatrix(); gl.glScalef(.25f, .25f, 1f);
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Tworzenie gier na platformę Android 4
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: