INSTRUKCJA DO ĆWICZENIA 13. Animacja wielowątkowa w

Transkrypt

INSTRUKCJA DO ĆWICZENIA 13. Animacja wielowątkowa w
WT PW Informatyka II. Laboratorium komputerowe. Rok akademicki 2016/17 semestr 3 . Autor: A. Czerepicki
INSTRUKCJA DO ĆWICZENIA 13.
Animacja wielowątkowa w aplikacjach JME. Gra logistyczna.
I.
UTWORZENIE SZKIELETU APLIKACJI
1. Uruchom środowisko programowania NetBeans. Utwórz aplikację typu JME zakładając projekt o nazwie
JME_Gra
2. Dodaj do projektu klasę typu Midlet o nazwie Gra
3. Dodaj do projektu klasę Java o nazwie Plansza dziedziczącą z klasy Canvas umieszczając ją w osobnym
pliku
4. Zaimportuj klasę Canvas oraz utwórz automatycznie metodę paint. Usuń domyślne wygenerowaną
zawartość metody paint.
5. Zaimplementuj w klasie Plansza interfejs CommandListener oraz utwórz automatycznie metodę
commandAction. Usuń z metody commandAction zbędne instrukcje.
class Plansza extends Canvas implements CommandListener {
}
6. Zadeklaruj w klasie Plansza zmienne W, H typu całkowitego w celu przechowania wymiarów planszy,
oraz generator liczb losowych Random o nazwie zamiennej r
Random r = new Random();
int W, H;
7. Utwórz konstruktor klasy Plansza bez parametrów
8. W konstruktorze klasy Plansza zainicjuj zmienne W i H pobierając odpowiednio szerokość oraz wysokość
planszy
W = getWidth();
H = getHeight();
9. Zadeklaruj w klasie Plansza zmienną typu Command o nazwie start do uruchomienia gry
Command start = new Command("Start", Command.OK, 0);
10. W konstruktorze dodaj obiekt start do menu ekranu za pomocą metody addCommand, oraz włącz
nasłuchiwanie zdarzeń za pomocą metody setCommandListener
addCommand(start);
setCommandListener(this);
11. W metodzie paint klasy Plansza umieść instrukcje czyszczenia ekranu
g.setColor(0, 0, 0);
g.fillRect(0, 0, W, H);
12. Otwórz plik z klasa Gra. Umieść pod nagłówkiem klasy deklarację zmiennej display typu Display, oraz
zmiennej plansza typu Plansza
Display display;
Plansza plansza;
13. Wygeneruj pusty konstruktor klasy Gra i umieść w nim instrukcję tworzenia obiektu typu Plansza
public Gra() {
plansza = new Plansza();
}
WT PW Informatyka II. Laboratorium komputerowe. Rok akademicki 2016/17 semestr 3 . Autor: A. Czerepicki
14. W metodzie startApp klasy Gra zainicjuj zmienną display za pomocą metody Display.getDisplay oraz
ustaw ekran plansza jako startowy
display = Display.getDisplay(this);
display.setCurrent(plansza);
15. Uruchom aplikację i sprawdź czy nie ma błędów.
II. PROJEKTOWANIE ABSTRAKCYJNEJ KLASY FIGURA PRZECHOWUJĄCEJ WSPÓLNE CECHY OBIEKTÓW
GRAFICZNYCH
Klasa będzie stanowiła podstawę do rysowania obiektów graficznych na ekranie Planszy. Będzie ona
przechowywała wspólne cechy obiektów takie jak położenie na ekranie, liczba uzbieranych punktów, czas
animacji, a także odpowiadała za realizację wątków.
1. Utwórz w projekcie abstrakcyjną klasę o nazwie Figura umieszczając ją w osobnym pliku
abstract class Figura {
}
2. Zadeklaruj w klasie Figura współrzędne X, Y, liczbę punktów punkty oraz interwał zmiany stanu obiektu
podczas animacji delay
public int X, Y, punkty;
protected int delay;
3. Wygeneruj automatycznie konstruktor klasy Figura, za pomocą którego można będzie nadać początkowe
wartości zmiennym X, Y
public Figura(int X, int Y) {
this.X = X;
this.Y = Y;
}
4. Zadeklaruj w klasie Figura abstrakcyjną metodę rysuj , która powinna zostać zdefiniowana w każdej klasie
dziedziczącej z Figura, w celu rysowania pochodnych obiektów
abstract void rysuj(Graphics g);
5. Zadeklaruj w klasie Figura abstrakcyjną metodę zmienStan(), za pomocą której każda klasa pochodna
będzie mogła zmieniać swoja pozycję, kolor, rozmiary etc – w zależności od potrzeb animacji
abstract void zmienStan();
6. Zaimplementuj w klasie Figura interfejs Runnable. Pozwoli to na uruchomienie obiektów klas
pochodnych w niezależnych równoległych wątkach bez konieczności ponownego zdefiniowania
interfejsu Runnable. Zwróć uwagę, iż środowisko NetBeans nie proponuje automatycznego stworzenia
metody run(). Zastanów się dlaczego tak się dzieje.
7. Utwórz metodę run() w klasie Figura. Wewnątrz metody umieść pętlę nieskończoną while(true).
Następnie wewnątrz pętli wywołaj metodę zmienStan() oraz instrukcję oczekiwania Thread.sleep(delay).
Dodaj obsługę wyjątków. Zwróć uwagę na to, że mimo iż zawartość metody zmienStan() nie jest jeszcze
zdefiniowana, kompilator nie zgłasza błędu. Metoda zmienStan() zostanie zdefiniowana w każdej z
pochodnych klas, w zależności od jej specyfiki. Wszystkie one przy tym będą korzystały z możliwości
uruchomienia procesu (wątku).
public void run() {
while (true) {
zmienStan();
try {
Thread.sleep(delay);
WT PW Informatyka II. Laboratorium komputerowe. Rok akademicki 2016/17 semestr 3 . Autor: A. Czerepicki
} catch (InterruptedException ex) {
}
}
}
8. Sprawdzamy czy aplikacja nadal się kompiluje. Jeśli nie, naprawiamy błędy. Nie uruchamiamy aplikacji
ponieważ nie zostały wprowadzone żadne zmiany mające wpływ na jej wygląd.
III. PROJEKTOWANIE KLASY PACMAN – OBIEKTU RUCHOMEGO DZIEDZICZĄCEGO Z KLASY FIGURA
W poprzednim rozdziale została stworzona klasa abstrakcyjna Figura, zawierająca uniwersalne
rozwiązania wspólne dla wszystkich obiektów graficznych w programie. Część metod przy tym nie została
zdefiniowana. W bieżącym rozdziale utworzymy klasę Pacman dziedziczącą z klasy Figura, i zrealizujemy
brakujące elementy wyglądu oraz zachowania obiektu.
1. Dodaj do projektu nową klasę o nazwie Pacman w postaci osobnego pliku. Klasa powinna dziedziczyć z
klasy Figura.
2. Wygeneruj automatycznie metody abstrakcyjne rysuj oraz zmienStan. Usuń ich domyślną zawartość.
3. Zadeklaruj zmienne klasy Pacman o nazwie dx, dy typu całkowitego. Będą one przechowywać kierunek
ruchu obiektu (dx – w poziomie, dy – w pionie)
int dx, dy;
4. Dodaj ręcznie konstruktor klasy Pacman o parametrach X, Y. Będzie on służył do ustawienia
początkowych współrzędnych obiektu na ekranie, oraz czasu animacji. Na samym początku konstruktora
wywołaj konstruktor klasy bazowej Figura za pomocą instrukcji super(X, Y). To pozwoli nie dublować w
kodzie klasy Pacman instrukcje inicjowania zmiennych X, Y.
public Pacman(int X, int Y) {
super(X, Y);
dx = 0;
dy = 0;
delay = 10;
}
5. W metodzie rysuj klasy Pacman umieść instrukcje do rysowania obiektu animowanego oraz liczby
zgromadzonych przez niego punktów. Metoda fillArc rysuje wycinek koła ze środkiem (X,Y) oraz kącie
270 st. Liczba punktów jest wyświetlana za pomocą metody drawString. Jej argumenty
Graphics.HCENTER oraz Graphics.BOTTOM wzkazują metodę ulokowania tekstu względem
współrzędnych (X,Y)
g.setColor(255, 255, 0);
g.fillArc(X-15, Y-15, 30, 30, 45, 270);
g.setColor(255, 255, 255);
g.drawString(punkty + "", X, Y-15, Graphics.HCENTER | Graphics.BOTTOM);
6. Dodaj w klasie Pacman metodę o nazwie kierunek(int dx, int dy) do ustawienia kierunków ruchu obiektu
public void kierunek(int dx, int dy) {
this.dx = dx;
this.dy = dy;
}
7. W treści metody zmienStan() umieść instrukcje do zmiany współrzędnych (X,Y) obiektu o wartości
przyrostowe dx, dy.
X += dx;
Y += dy;
WT PW Informatyka II. Laboratorium komputerowe. Rok akademicki 2016/17 semestr 3 . Autor: A. Czerepicki
8. Przejdź do klasy Plansza. Pod jej nagłówkiem umieść deklarację obiektu pacman klasy Pacman
Pacman pacman;
9. W konstruktorze klasy Plansza umieść instrukcję tworzenia obiektu klasy Pacman w pozycji (30, 40)
pacman = new Pacman(30, 40);
10. W metodzie paint klasy Plansza umieść instrukcję rysowania obiektu Pacman
pacman.rysuj(g);
11. Uruchom program i sprawdź czy figurka się wyświetla na ekranie
IV. ANIMACJA. OBSŁUGA KLAWIATURY
W tym rozdziale zdefiniujemy metodę obsługi zdarzeń klawiatury w celu umożliwienia zmiany pozycji
obiektu graficznego na ekranie.
1. Zadeklaruj w klasie Plansza metodę keyPressed, która zostanie automatycznie wywołana przy każdym
naciśnięciu klawisza na telefonie
protected void keyPressed(int keyCode) {
}
2. W treści metody keyPressed umieść instrukcje zmieniające kierunek ruchu pacmana zgodnie z kodem
wciśniętego klawisza: -1 UP, -2 DOWN, -3 LEFT, -4 RIGHT, -5 CENTER
if
if
if
if
if
(keyCode
(keyCode
(keyCode
(keyCode
(keyCode
==
==
==
==
==
-1)
-2)
-3)
-4)
-5)
pacman.kierunek(0, -1);
pacman.kierunek(0, 1);
pacman.kierunek(-1, 0);
pacman.kierunek(1, 0);
pacman.kierunek(0, 0);
//
//
//
//
//
w górę
w dół
w lewo
w prawo
stop
3. W metodzie paint klasy Plansza umieść instrukcję zatrzymania wątku na czas 10 msek.
Thread.sleep(10);
4. Wygeneruj automatycznie instrukcje try .. catch niezbędne do poprawnej obsługi metody Thread.sleep
5. Za nawiasem kończącym konstrukcję try … catch umieść instrukcję repaint() w celu odświeżenia ekranu
repaint();
6. W metodzie commandAction klasy Plansza rozpoznaj polecenie start i umieść w odpowiadającym mu
kodzie instrukcję tworzenia i uruchomiania wątku pacmana
if (c == start) {
new Thread(pacman).start();
}
7. Sprawdź działanie programu. Po uruchomieniu aplikacji oraz kliknięciu [Start] można sterować ruchem
obiektu po ekranie za pomocą strzałek na klawiaturze telefonu (oraz komputera)
WT PW Informatyka II. Laboratorium komputerowe. Rok akademicki 2016/17 semestr 3 . Autor: A. Czerepicki
V. DEFINIOWANIE „PREZENTÓW”
W tym rozdziale stworzymy kolejną klasę obiektów graficznych – Prezent. Umożliwi ona zdobywanie
punktów przez pacmana w sytuacji, kiedy sterowany przez użytkownika obiekt zbliży się do „celu” na
odpowiednią liczbę pikseli.
1. Dodaj do projektu nową klasę Prezent w osobnym pliku
2. Odziedzicz klasę Prezent z klasy Figura
3. Zaimplementuj wszystkie metody abstrakcyjne w klasie Prezent i usuń ich domyślnie wygenerowaną
zawartość
4. Dodaj konstruktor klasy Prezent za pomocą którego można będzie ustawić współrzędne obiektu na
ekranie oraz liczbę punktów za jego zdobycie
public Prezent(int X, int Y, int punkty) {
super(X, Y);
this.delay = 1000;
this.punkty = punkty;
}
5. W metodzie rysuj klasy Prezent umieść instrukcje rysowania obiektu w postaci kółka oraz instrukcję
wyświetlającą liczbę punktów w postaci tekstu
g.setColor(255 - 5*punkty, 5*punkty, 0);
g.fillArc(X-10, Y-10, 20, 20, 0, 360);
g.setColor(255, 255, 255);
g.drawString(punkty + "", X, Y+5, Graphics.HCENTER | Graphics.BASELINE);
6. Metodę zmienStan na razie pozostaw pustą.
7. W klasie Plansza dodaj deklarację 10-elementowej tablicy obiektów typu Prezent
Prezent[] prezenty = new Prezent[10];
8. W konstruktorze klasy Plansza utwórz wszystkie obiekty Prezent w tablicy
for (int i = 0; i < 10; i++) {
prezenty[i] = new Prezent(
r.nextInt(W - 20), r.nextInt(H - 20), r.nextInt(25) + 25);
}
9. W treści metody paint klasy Plansza przed instrukcja rysowania Pacmana, dodaj instrukcje rysujące
wszystkie obiekty typu Prezent z tablicy
for (int i = 0; i < 10; i++) {
if (prezenty[i] == null) continue;
prezenty[i].rysuj(g);
}
10. Sprawdź działanie programu. Na ekranie powinny się ukazać 10 obiektów graficznych typu Prezent.
VI. INTERAKCJA POMIĘDZY OBIEKTAMI NA EKRANIE. ZBIERANIE „PREZENTÓW”
1. Zadeklaruj w klasie Pacman metodę złap za pomocą której można będzie sprawdzić odległość
pomiędzy wskazanym obiektem graficznym a pacmanem
boolean złap(Prezent p) {
return Math.sqrt((X - p.X)*(X - p.X) + (Y - p.Y) * (Y - p.Y)) < 5;
}
2. W metodzie paint klasy Plansza po instrukcji rysowania obiektu prezenty[i].rysuj(g) umieść
sprawdzenie czy pacman w danym momencie zbliżył się do tego obiektu na dystans nie
przekraczający 5 pikseli (wartość przybliżona, można ją oczywiście zmienić). Jeśli tak, prezent
zostanie usunięty z listy zaś użytkownikowi zostaną doliczone odpowiednie punkty.
WT PW Informatyka II. Laboratorium komputerowe. Rok akademicki 2016/17 semestr 3 . Autor: A. Czerepicki
if (pacman.złap(prezenty[i])) {
pacman.punkty += prezenty[i].punkty;
prezenty[i] = null;
}
3. Sprawdź działanie programu
4. Dopracuj metodę wyświetlająca pacmana tak, by można było jednoznacznie określić kierunek jego
poruszania się. W tym celu wystarczy na podstawie wartości zmiennych dx, dy określić wartość
początkową kąta alfa w metodzie fillArc. Zmień w metodzie rysuj klasy Pacman linijkę z kodem
metody fillArc na
int alfa = 45;
if (dx < 0) alfa = 180 + 45;
if (dx > 0) alfa = 45;
if (dy < 0) alfa = 90 + 45;
if (dy > 0) alfa = 270 + 45;
g.fillArc(X-15, Y-15, 30, 30, alfa, 270);
5. Sprawdź działanie programu
VII. GRA NA CZAS
Zmodyfikujemy czas życia „prezentów” na ekranie w taki sposób, aby liczba punktów stopniowo malała z
upływem czasu.
1. W klasie Prezent uzupełnij treść metody zmienStan o zmniejszenie liczby punktów
if (punkty > 0) {
punkty--;
}
2. W metodzie commandAction klasy Plansza w sekcji obsługi polecenia start dopisz instrukcje
uruchamiające dla każdego z prezentów własny wątek
if (c == start) {
for (int i = 0; i < 10; i++) {
new Thread(prezenty[i]).start();
}
new Thread(pacman).start();
}
3. Uruchom program i postaraj się pozyskać maksymalną liczbę punktów ;)
VIII.
ZADANIA DO SAMODZIELNEGO WYKONANIA
1. Zaprogramuj wyjście z programu. Zwróć uwagę na to że ekran klasy Canvas nie posiada
możliwości wywołania metody notifyDestroyed() klasy MIDLet. W tym celu można przekazać
wskaźnik na klasę główną midleta w konstruktorze Plansza. Drugie rozwiązanie polega na
wprowadzeniu ekranu startowego typu Form, z którego rozpoczyna się gra, i do którego wraca
się po jej ukończeniu. Przyciski [start] oraz [koniec] byłyby wówczas osadzone w Form.
2. Zaprogramuj zatrzymanie się gry w momencie, kiedy wszystkie prezenty zostaną zebrane.
Wyświetl okno z wynikami gry i propozycją rozpoczęcia nowej gry.
3. Zastanów się jak w oknie Plansza zrealizować mechanizm tymczasowego zatrzymania gry
(pauza).
4. Dopracuj rozmieszczanie prezentów na ekranie tak by się nie pokrywały