Grafika libGDX to temat jaki jeszcze nie był poruszany w kontekście gry UWar. Dziś jednak to zmienimy i dodamy do naszej gry pierwszą teksturę, która będzie reprezentowała postać naszego bohatera. Dodatkowo bohater będzie miał animowane kroki, aby gra ładniej się prezentowała. To wszystko zrealizujemy w dzisiejszym wpisie, dzięki temu będziemy mieć dobre podstawy, aby przystąpić do kolejnych etapów związanych z grafiką.
Tekstura
Aby móc wyświetlić grafikę, zamiast naszego dotychczasowego żółtego kółeczka, będziemy potrzebować grafiki. Na szczęście w internecie pełno jest serwisów, oferujących darmowe tekstury do gier. Dzięki jednej z takich stron udało się znaleźć postacie jakie wykorzystamy, nie tylko do utworzenia postaci gracza, ale także do wyświetlania wrogów.
Grafika jaką wykorzystamy
Na tej grafice zostało zaprezentowanych 8 postaci, każda z nich w czterech płaszczyznach (lewo, prawo, góra i dół), a także postaci robiące krok lewą lub prawą nogą. Dzięki temu będziemy mogli stworzyć również animację stawiania kroków przez naszego bohatera.
Wyświetlenie grafiki
Teraz zajmiemy się już implementacją wyświetlania grafiki. Zacznijmy od utworzenia zmiennych w pliku Game.java
private Texture texturePlayer; private TextureRegion[] playerRegionLeft; private TextureRegion[] playerRegionRight; private TextureRegion[] playerRegionUp; private TextureRegion[] playerRegionDown;
Te zmienne będziemy wykorzystywać do rysowania na ekranie postaci bohatera oraz animowania jego kroków. Widzimy tutaj nową klasę TextureRegion[], to nic innego jak wycinek tekstury (obiektu klasy Texture), a dokładniej tablica takich fragmentów.
texturePlayer = new Texture("player.png"); playerRegionLeft = new TextureRegion[3]; playerRegionRight = new TextureRegion[3]; playerRegionDown = new TextureRegion[3]; playerRegionUp = new TextureRegion[3];
Powyższe linijki to inicjalizacja wcześniej zadeklarowanych pól. Z pierwszej wynika, że ładujemy plik graficzny player.png. A następnie inicjalizujemy nasze tablice, które będą przechowywały po 3 elementy. Nazwy tablic wskazują na kierunek poruszania się przechowywanych w nich grafik.
Warto zaznaczyć, że rozmiar jednej postaci to 52px na 72px. Będzie nam to potrzebne, do określenia z którego miejsca ma zostać wycięta postać.
playerRegionLeft[1] = new TextureRegion(texturePlayer, 52, 72*5, 52, 72); playerRegionLeft[0] = new TextureRegion(texturePlayer, 0, 72*5, 52, 72); playerRegionLeft[2] = new TextureRegion(texturePlayer, 104, 72*5, 52, 72); playerRegionRight[1] = new TextureRegion(texturePlayer, 52, 72*6, 52, 72); playerRegionRight[0] = new TextureRegion(texturePlayer, 0, 72*6, 52, 72); playerRegionRight[2] = new TextureRegion(texturePlayer, 104, 72*6, 52, 72); playerRegionUp[1] = new TextureRegion(texturePlayer, 52, 72*4, 52, 72); playerRegionUp[0] = new TextureRegion(texturePlayer, 0, 72*4, 52, 72); playerRegionUp[2] = new TextureRegion(texturePlayer, 104, 72*4, 52, 72); playerRegionDown[1] = new TextureRegion(texturePlayer, 52, 72*7, 52, 72); playerRegionDown[0] = new TextureRegion(texturePlayer, 0, 72*7, 52, 72); playerRegionDown[2] = new TextureRegion(texturePlayer, 104, 72*7, 52, 72);
Teraz zajmujemy się przypisaniem do każdego indeksu tablicy odpowiedniego fragmentu, wczytanego wcześniej pliku graficznego do zmiennej texturePlayer. Konstruktor TextureRegion przyjmuje 5 parametrów. Pierwszym z nich jest tekstura z jakiej to ma zostać pobrany fragment. Kolejne dwa odpowiadają odpowiednio za szerokość i wysokość, od jakiej ma zacząć się wycinek. Ostatnie dwa parametry określają szerokość i wysokość jaką ma mieć interesujący nas obszar.
Indeks zerowy to grafika z krokiem lewej nogi. Indeks pierwszy to postać w spoczynku, zaś ostatni z indeksów to krok prawej nogi. Będzie to nam potrzebne do utworzenia animacji, ale to za chwilę.
Dodajemy do klasy Player.java dwa nowe pola, które będą odpowiadać za ustawienie kroku oraz odliczanie czasu do zmiany kroku. Ustawienie kroku, czyli wybranie odpowiedniej grafiki z naszych nowo utworzonych tablic.
private float moveTime; private int step;
Do konstruktora dodajemy nowe pola, przypisując im moveTime = 0 oraz step = 1 (step jest równy 1, ze względu, że nasze grafiki w stanie spoczynku znajdują się w tablicach pod indeksem 1). Dodatkowo generujemy gettery i settery dla naszych nowych pól.
Następnie w miejsce
batch.draw(player.getTexture(),player.x, player.y);
wstawiamy
if(player.getDirection() == 0){ batch.draw(playerRegionLeft[player.getStep()],player.x, player.y); //left }else if(player.getDirection() == 2){ batch.draw(playerRegionRight[player.getStep()],player.x, player.y); //right }else if(player.getDirection() == 1){ batch.draw(playerRegionDown[player.getStep()],player.x, player.y); //down }else{ batch.draw(playerRegionUp[player.getStep()],player.x, player.y); //up }
W momencie kiedy postać porusza się w lewo, zostaje z tekstura załadowana z tablicy playerRegionLeft z pobranym krokiem. Kolejne dwa parametry wywołania to pozycja bohatera. W podobny sposób utworzone zostają pozostałe trzy kierunki, w które może poruszać się nasz bohater.
Mamy zrobiony mechanizm wyświetlania grafiki w stanie spoczynku. Przyszedł więc czas stworzenie animacji poruszania się naszego bohatera.
Animacja
Teraz do klasy Player.java dodajemy kod odpowiedzialny za zmienianie wartości pola step.
public void stepAnimation(float time){ setMoveTime(getMoveTime() + time); if(getMoveTime() > 0.15) { setStep(getStep() + 1); setMoveTime(0); if(getStep() > 2) setStep(0); } }
Zatem tworzymy nową metodę, która będzie odpowiedzialna za animację poruszania. Jako parametr przekazujemy różnicę miedzy ostatnią, a obecną klatką obrazu (czas).
Na początku dodajemy do obecnego już czasu zapisanego w polu moveTime wartość przekazaną przez parametr.
Następnie sprawdzamy czy suma od ostatniej zmiany korku jest większa od 0.15 sekundy, jeśli warunek jest spełniony następuje inkrementacja (zwiększenie o jeden) pola step oraz wyzerowanie czasu moveTime.
Ostatnim krokiem jest sprawdzenie czy pole step nie jest większe od 2. Sprawdzamy ten warunek, ponieważ nasza tablica grafik zawiera jedynie 3 elementy, zatem jej ostatnim indeksem jest dwójka. W sytuacji, kiedy step jest większe od 2, następuje wyzerowanie tego pola.
Teraz pozostaje dodać do warunków odpowiedzialnych za ruch naszą nową metodę.
if(Gdx.input.isKeyPressed(Input.Keys.ESCAPE)){ Gdx.app.exit(); } if(Gdx.input.isKeyPressed(Input.Keys.W) && player.y < 5000-2*player.radius){ player.goMoveToTop(Gdx.graphics.getDeltaTime()); player.stepAnimation(Gdx.graphics.getDeltaTime()); } if(Gdx.input.isKeyPressed(Input.Keys.S) && player.y > 0){ player.goMoveToBottom(Gdx.graphics.getDeltaTime()); player.stepAnimation(Gdx.graphics.getDeltaTime()); } if(Gdx.input.isKeyPressed(Input.Keys.A) && player.x > 0){ player.goMoveToLeft(Gdx.graphics.getDeltaTime()); player.stepAnimation(Gdx.graphics.getDeltaTime()); } if(Gdx.input.isKeyPressed(Input.Keys.D) && player.x < 5000-2*player.radius) { player.goMoveToRight(Gdx.graphics.getDeltaTime()); player.stepAnimation(Gdx.graphics.getDeltaTime()); }
Efekt pracy
Podsumowanie
Dziś dodaliśmy pierwszą teksturę do naszej gry oraz stworzyliśmy jej animację w czasie ruchu. Podobne zabiegi będziemy robić w kolejnych etapach naszej pracy. Dlatego dzisiejszy wpis jest tak istotny dla najbliższych tygodni. Na chwilę obecną została jedynie dodana grafika, bez zmiany obszaru kolizji, którym będziemy się bawić w kolejnym już wpisie.
Pozdrawiam,
sirmarbug
Coś media nie działają chyba, bo efektów pracy nie widać 😉