Często aplikacja może być uruchamiana na różnych urządzeniach z różną wielkością ekranu. Samych rozdzielczości wyświetlania jest cała masa, przy czy można wyróżnić kilka formatów (Aspect Ratio), co widać kolorami na rysunku poniżej. Ma to wpływ bezpośrednio na to jak wygląda nasza gra, tu właśnie w libGDX przychodzą klasy Viewport, które określają sposób radzenia sobie z tym problemem. Dwa Elementy które będą nam potrzebne na dziś to camera i viewport. Spróbujmy jakoś to umówić.
Camera
Pierwszym krokiem będzie
zastosowanie kamery. To tak jak w rzeczywistości możemy na obiekty patrzeć albo
na wprost albo spod kąta. I w libGDX mamy do wyboru dwie możliwości PerspectiveCamera
i OrthographicCamera.
Przeszukując Internet udało się znaleźć fajny rysunek który idealnie prezentuje
różnicę w obu podejściach.
Jak widać w kamerze
ortogonalnej, obiekty rzutowane są równolegle do punktu widzenia, zaś w kamerze
perspektywicznej widzenie rozchodzi się z jednego punku i pod różnym kontem
rzutowane są zarysy obiektów na ekranie który je wyświetla. W naszym przypadku
platformówki oczywiste jest zastosowanie kamery ortogonalnej, jako że obiekty
widziane są bezpośrednio tak jakby z boku.
Poniższe linie umieszczamy
w naszym projekcie. Najpierw w naszym ekranie gry czyli PlayScreen
inicjalizujemy obiekt OrtographicCamera który nazywamy przykładowo camera.
private OrthographicCamera camera;
Póki co jest to na razie
tylko miejsce zarezerwowane. To co potrzeba teraz zrobić to w konstruktorze
powiedzieć/przypisać że jest to nowy obiekt klasy OrthographicCamera
następującą linią kodu:
camera = new OrthographicCamera();
Właśnie tak w Javie
wygląda tworzenie nowych obiektów wcześniej już zdefiniowanych klas. Dodatkowo
można pomiędzy nawiasami przesyłać różne parametry, jeżeli dana klasa ma
zdefiniowane różne konstruktory. O konstruktorach było już wcześniej, dlatego
jeżeli istnieje potrzeba to wróć do wcześniejszego wpisu.
Viewport
Viewporty jest to pojęcie
z teorii grafiki komputerowej, ale spokojnie to nie uczelnia ;d. Patrząc przez
kamerkę jaką znamy np. z aparatu naszego telefonu widzimy tylko wycinek tego co
dzieje się wokoło. Viewport to właśnie nic innego jak obszar w postaci
wieloboku, inaczej obszar zainteresowania, to co widzimy. A co w przypadku gdy
obszar wyświetlania się zmienia np. wysokość się zwęża, jak powinny wyglądać
wtedy wyświetlane elementy? libGDX dostarcza różne możliwe na to strategie.
Porównamy dla wyczucia różnic dwie z nich FitViewport
oraz StretchViewport.
Więc dopisujemy stosowne linie kodu, później sprawdzimy różnice i wybierzemy
ten odpowiadający naszym potrzebom.
W PlayScreen dopisujemy:
private Viewport view;
natomiast w konstruktorze
view = new StrechViewport (800, 480, camera);
Sam StrechViewport ma
zdefiniowane dwa konstruktory: dwu i trzy parametrowy. Wykorzystujemy jednak
trzy parametry, czyli szerokość, wysokość okna, oraz z jakiej kamery mamy
patrzeć na te obiekty. Patrzymy na wprost czyli konieczna jest użycie wcześniej
stworzonej OrthographicCamery. StrechViewport przy zmianie wielkości ekranu
rozciąga zawsze tak aby obiekt zajmował tą samą część ekranu, czyli nie trzyma
aspect ratio. Co czyni niestety przy np. wąskich ekranach, że obiekt staje się słabo
widoczny. Takiego efekt raczej nie będzie wyglądał ciekawie. Fitport dla
odmiany utrzymuje aspect ratio przy zmianach szerokości i wysokości. A
miejscach pozostałych dodaje czarne paski. Z reszta na rysunku wyraźnie to
widać. W naszym projekcie zastosujemy Fitport.
HUD
Mamy zrobiony już widok
oraz kamere. Jak w większości gier wyświetlają się w którym miejscu jakieś punkty
życia, magii, zebrane punkty czy czas. Jest dobry moment aby się za to się
zabrać i wyświetlić to na widocznym ekranie. Jednak nie można tego bezpośrednio
tak po prostu wyświetlić w viewport, z prostej przyczyny że nasz świat będzie
się poruszał. W tym celu stosuje się osobny viewport i kamerę, dzięki czemu
będzie mogło być statyczne niezależnie od reszty. Określa się to HUD (Head-Up
Display), jest to przezroczysta szybka która wyświetla informacje. Sam termin
zaczerpnięty z zastosowań militarnych, gdzie służył do prezentacji danych w
samolotach bojowych.
Tworzymy nową klasę Hud,
umieszczając ją w nowym pakiecie Scenes.
Pierwsze co to
inicjalizujemy obiekty jakie będziemy potrzebować. W języku Java który jest
językiem obiektowym, każda element jest obiektem. Przykładowo zwykły tekst
String nazwa = „przykładowy string”
jest również obiektem klasy String. Wracając jak było wcześniej wspomniane potrzeba
stworzyć viewport i kamerę. Ponadto zakładamy że chcemy wyświetlić napis
pokazujące zdobyte punkty i poziom gry.
public Stage stage;
private
Viewport viewport;
private Integer
score;
Stage jest sceną na
której występują aktorzy. Stage jest jakby kontenerem wszystkich obecnych
obiektów. Aktorzy to graficzne elementy z konkretnymi parametrami, które mogą
dodatkowo się zmieniać. Wszystko co widzimy na scenie jest jakby w trakcie
podłączenia do prądu, występuje akcja, mogą na tym występować różne animacje,
czynności np. zderzenia, czy nachodzenie na siebie. Wszystkie obiekty są
nasłuchiwane. Dodatkowo mogą się poruszać i być animowane. Oczekują także na interakcje z użytkownikiem,
który może mieć wpływ na przebieg zdarzenia przez np. sterowanie klawiaturą
Sama zmienna Integer
przechowuje jedynie wartość. Aby możliwe było wyświetlenie tego na ekranie
potrzeba skorzystać z klasy Label.
Label scoreLabel;
Label levelLabel;
Pora na konstruktor, to
co trzeba jeszcze wiedzieć to rysowanie wymaga skorzystania z klasy
SpriteBatch. SpriteBatch jest jakby kontenerem elementów do rysowania, gdzie
wskazuje się indeksy położenia. Przykładowo jeżeli chcemy wyświetlić jakiś
obrazek potrzeba go w takim kontenerze umieścić. Wykonuje się to pomiędzy
batch.begin() i batch.end(). Aby nasz Hud był widoczny potrzeba go umieścić w
batch. Robi się to po przez przesłanie go przez konstruktor. Celem jest podanie
tego przy tworzeniu Stage, tak aby mógł zostać uwzględniony w kontenerze do
wyświetlania, drugie co podajemy to do Stage to jaką strategie wyświetlania
wybraliśmy przez viewport.
public
Hud(SpriteBatch sb) {
score = 0;
viewport =
new FitViewport(800, 480, new OrthographicCamera());
stage = new Stage(viewport, sb);
Teraz potrzebne będzie
jakaś organizacja wyświetlania naszych labeli na ekranie. W libGDX służy do
tego klasa Table. To tak jak dla gości wystawiasz wszystko na stół, gdzie
wszystko jest osobno poukładane. Pozwala nam ustawianie nam elementów w jakąś
siatkę kolumnami, bądź wierszami, w orientacji jakiej chcemy czy to poziomej
czy pionowej. Metodą setFillParent możemy określić aby zajmowała cała
powierzchnię, natomiast top() aby były układane od góry. W tym miejscu można
się domyśleć że wszystko co znajduje się kropce to korzystanie z metod. I tak
bierzemy stworzony obiekt table i po kropce używamy jego metody top(). Co w zależności
jak jest zaimplementowane wewnątrz można spodziewać się różnych rezultatów.
Table table = new
Table();
table.top();
table.setFillParent(true);
Dalej nic wielkiego się
nie dzieje obiektom ustawiamy szereg właściwości. Taki jak format wyświetlania
z przewidywaną ilością znaków, rodzaj domyślnego fontu, czy kolor biały
scoreLabel
= new Label(String.format("%06d", score),
new Label.LabelStyle(new
BitmapFont(), Color.WHITE));
levelLabel =
new Label(String.format("1", score),
new Label.LabelStyle(new
BitmapFont(), Color.WHITE));
W tym miejscu pora dodać je
do naszego stołu metodą add. Metodą expandX() ustawiamy na pełną szerokość.
Jednak gdy wiele przedmiotów znajduje się obok siebie to przyjmują one po równo
przestrzeni w zależności ile jest tych przedmiotów. PadTop(10) ustala wielkość
komórek.
table.add(scoreLabel).expandX().padTop(10);
table.add(levelLabel).expandX().padTop(10);
na końcu dodajemy cały
table do naszej sceny. Hud jest już gotowy, pora go użyć.
stage.addActor(table);
Wracamy do PlayScren inicjalizujemy Hud
Private Hud hud;
W konstruktorze tworzymy
ten obiekt przesyłając obiekt game.batch.
Hud = new Hud(game.batch)
W metodzie render usuwamy
te linie z przykładu gdzie był game.batch. Chcemy teraz widzieć Hud zamiast
przykładowego rysunku.
Musimy wskazać spritebatch
gdzie obecnie jesteśmy, tzn. gdzie patrzy kamera. To co na ekranie powinno być widoczne
to właśnie to na co patrzy kamera. Combined jest połączeniem projekcji i
widoku. Robimy to linią
game.batch.setProjectionMatrix(hud.stage.getCamera().combined);
W końcu zlecamy
wyrysowanie całości
hud.stage.draw();
Efekt na obecny moment
prezentuje się następująco
Przy okazji powstał
pomysł na inny wpis więcej o kamerach i perspektywach w grach. Tyle na dziś do
odbioru.
https://github.com/KrzysztofPawlak/WordCharger/tree/wpis5
Brak komentarzy:
Prześlij komentarz