Sieciowe Technologie Mobilne Laboratorium 4 Tworzenie wieloplatformowych aplikacji mobilnych przy użyciu biblioteki PhoneGap. Łukasz Kamiński
Laboratorium 4 Urozmaicone zostaną animacje potworów, aby odpowiadały kierunkowi ich ruchu (nowa klasa Actor). Porównamy wydajność aplikacji na telefonie i na komputerze stacjonarnym. Podjęte zostaną próby optymalizacji. 1.1. Klasa Actor Wprowadź nową klasę Actor, wywiedzioną z klasy AnimatedSprite. Klasa ta ma reprezentować szczególny przypadek animowanych obiektów, tj. postaci, które powinny być rysowane w inny sposób, w zależności od kierunku, w którym się poruszają. Obiektom tej klasy towarzyszą z reguły pliki graficzne, które pozwalają zdefiniować wiele różnorodnych sekwencji klatek animacji (patrz przykładowy rysunek poniżej).
Wzbogać klasę Actor o pola, które definiują sekwencje animacji dla czterech kierunków głównych (góra, prawo, dół, lewo) ruchu obiektu. Nadpisz metodę update() klasy Actor, aby: 1. ustalała kierunek ruchu obiektu, w sposób dyskretny, z dokładnością do wspomnianych czterech kierunków głównych (góra, prawo, dół, lewo), 2. ustawiała sekwencję animacji stosownie do ustalonego kierunku ruchu obiektu (np. z użyciem metody setanimationframesseq() przedstawionej w instrukcji nr 2). Zmodyfikuj dotychczasowe obiekty reprezentujące potwory, aby korzystały z nowo powstałej klasy Actor. Oczekiwany efekt został pokazany na poniższym rysunku każdy z 3 potworów (szkieletów) jest zwrócony zgodnie z kierunkiem, w którym się porusza. 1.2. Ustalenie FPS Obliczaj FPS i wyświetlaj jego wartość w dowolnym rogu ekranu gry. Porównaj wydajność gry na komputerze stacjonarnym oraz na urządzeniu mobilnym. 1.3. Wykorzystanie całego ekranu Spraw, aby canvas z grą zajmował całą dostępną przestrzeń. Najprostszym sposobem, aby to osiągnąć, jest nadpisanie atrybutów width i height canvas'a. this.kanwa = document.getelementbyid(canvasid); this.kanwa.width = window.innerwidth; this.kanwa.height = window.innerheight; Dla pewności warto też pozbyć się marginesów z dokumentu, najlepiej korzystająć z CSS: html, body { width: 100%; height: 100%; margin: 0px; 1.4. Optymalizacja Niektóre wyświetlane elementy gry mają charakter statyczny (bohater, tło). Ich wielokrotne
rysowanie w każdym obiegu pętli ma negatywny wpływ na wydajność aplikacji, zwłaszcza w sytuacji, gdy próbujemy dokonywać zmiany rozmiaru obiektu (np. korzystając z przedstawionej w instrukcji nr 2 metody Sprite.resize()). Dużo lepszym rozwiązaniem jest użycie dodatkowego obiektu canvas (tzw. off-screen canvas ), na którym tylko raz narysowane zostaną obiekty statyczne, wraz z wszelkimi niezbędnymi zmianami rozmiaru. Zawartość tego obiektu będzie przenoszona do właściwego canvas'a w każdym obiegu pętli. Funkcjonalność tę możesz zaimplementować z wykorzystaniem poniższej, prostej klasy. kamyk.offscreencanvas = Class.$extend({ init : function(game) { this. renderables = []; //tworzenie "off-screen canvas" o odpowiednim rozmiarze this. offscreencanvas = document.createelement("canvas"); this. offscreencanvas.width = game.width; this. offscreencanvas.height = game.height; //zapamiętanie dwóch kontekstów graficznych this. ctx = this. offscreencanvas.getcontext("2d"); this. maincanvascontext = game.context;, /**Dodanie obiektu, który ma być rysowany za pośrednictwem "off-screen canvas". Należy wykonać na wszystkich obiektach przed wywołaniem renderyourself()*/ addrenderable : function(r) { this. renderables.push(r);, /**Do wykonania na początku metody Game.render()*/ rendertomaincanvas : function() { this. maincanvascontext.drawimage(this. offscreencanvas,0,0);, /**Do wykonania tylko raz, na początku.*/ renderyourself : function() { for(var i = 0; i < this. renderables.length ; i++) { this. renderables[i].render(this. ctx); ); Pamiętaj, że metoda renderyourself() powinna zostać wywołana, gdy załadowane zostaną wszystkie obrazki. Porównaj liczbę FPS po zmianach z liczbą FPS sprzed wprowadzenia off-screen canvas. Z reguły wykorzystywanie wielu elementów typu canvas pozwala osiągnąć w sposób najszybszy znaczny wzrost wydajności aplikacji. Możesz próbować dalszych optymalizacji (nia na ocenę, lecz dla własnej satysfakcji). Najlepiej poprzedzić je profilowaniem gry (narzędzia do profilowania są dostępne w każdej sensownej przeglądarce). Jeśli zajdzie taka konieczność, możesz próbować: 1. Zastępować wywołanie Math.floor(liczba) wywołaniem liczba>>0. Przy rysowaniu należy przekształcać liczby zmiennoprzecinkowe na całkowite (w przeciwnym wypadku może się pojawiać efekt rozmycia ), więc wywołania tego typu są wykorzystywane dosyć intensywnie. 2. Ograniczać tworzenie nowych obiektów, starać się wykorzystywać ponownie istniejące. Takie podejście pozwoli na płynniejsze działanie mechanizmów odśmiecania pamięci języka JavaScript. Pamiętaj, że funkcja też jest obiektem unikaj tworzenia funkcji anonimowych w kluczowych dla wydajności aplikacji miejscach.
3. Jeśli jeszcze tego nie zrobiłeś, pętlę gry oprzyj na metodzie requestanimationframe(). ZADANIE Zadanie do wykonania zostały opisane w poprzedniej części instrukcji. Punktacja: 2 pkt. - zaimplementowano klasę Actor, potwory są animowane w sposób odpowiadający ich kierunkowi ruchu 1 pkt. - wyświetlany jest licznik FPS 1 pkt. - gra zajmuje cały ekran urządzenia 1 pkt. - dokonano optymalizacji z użyciem mechanizmu off-screen canvas, licznik FPS wskazuje wartość większą niż 15 na Samsungu Galaxy SI ;)