W dzisiejszym wpisie zajmiemy się obiecanym ostatnio bohaterem gracza. Będzie to oczywiście uproszczona sylwetka tego co gra będzie oferowała w kolejnych wersjach, ale wszystko w swoim czasie. Zajmiemy się podstawowymi wskaźnikami bohatera, rysowaniem go na ekranie oraz poruszaniu się po nim. Jednak wcześniej zaczniemy od zmodyfikowania klasy uruchamiającej naszą wersję desktopową, tak aby otwierana aplikacja wyświetlała się na pełnym ekranie a nie w okienku jak było to ustawione domyślnie.
package pl.bugajsky.desktop; import com.badlogic.gdx.backends.lwjgl.LwjglApplication; import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; import pl.bugajsky.UWar; public class DesktopLauncher { public static void main (String[] arg) { LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); config.fullscreen = true; new LwjglApplication(new UWar(), config); } }
Względem poprzedniej wersji jaką pokazywałem w ostatnim wpisie została dodana jedna linijka, której zadaniem jest wyświetlanie naszego okna gry na pełnym ekranie (modyfikacja ta jest zawarta w linijce 10).
Pierwsze linijki kodu bohatera (Player.java)
Teraz już spokojnie możemy przejść do początku naszej przygody z tworzeniem klasy bohatera. Zacznijmy od odejścia od kodu i przedyskutujmy pewne pierwotne kwestie – założenia początkowe. Bohater będzie poruszał się w układzie x i y, co oznacza, że będzie to gra 2D, reprezentowany przez żółty okrąg (jego reprezentacja zostanie zmieniona w późniejszych wersjach, jednak uważam, iż lepiej jest początkowo zająć się samą logiką gry, a na sam koniec dodać piękne tekstury oraz stworzyć ich animacje). Bohater umożliwioną będzie miał również możliwość biegania (szybszego przemieszania się), a także wskaźnik życia oraz będzie przechowywał ogólną sumę zdobytych punktów (przynajmniej chwilowo, tak to rozwiązałem). W ten sposób mamy spisane wszystkie cechy jakie będzie miał bohater. Teraz pozostaje nasze rozmyślanie przelać na kod. Czas start!
public class Player extends Circle{ private int hp; private double speed; private int score; private Texture texture; private Pixmap pixmap; }
Tak wygląda moja klasa wraz z atrybutami. Pierwszym co się rzuca w oko, to dziedziczenie po klasie Circle, przypomnę, że w obecnej wersji postać gracza, będzie reprezentowana za pomocą żółtego, wypełnionego okręgu, umożliwi nam to określenie współrzędnych bez ich deklarowania w tej klasie, ponieważ jest to już dziedziczone z klasy nadrzędnej oraz w późniejszym czasie dzięki temu zabiegowi będziemy mogli wykrywać kolizję (tym zajmiemy się za kilka wpisów).
Kolejne linijki to deklaracja zmiennych wykorzystywanych przez bohatera, hp jest typu int i jest odpowiedzialna za życie naszej postaci. Zmienna zmiennoprzecinkowa speed jak sama nazwa wskazuje, będzie uzależniała prędkość poruszania naszej postaci po mapie. Jak wcześniej wspominałem bohater będzie trzymał punkty zdobyte przez nas podczas gry. Dwie następne zmienne są odpowiedzialne za rysowanie postaci na ekranie. Pixmap tworzy nam rysunek, opisany kodem przypisany do zmiennej klasy Texture, który kolejno jest wyświetlany na ekranie.
Kolejny fragment prezentuje konstruktor naszej klasy:
public Player(float x, float y){ super(x,y,10); hp = 100; score = 0; speed = 1.0; pixmap = new Pixmap(20, 20, Pixmap.Format.RGBA8888); pixmap.setColor(Color.YELLOW); pixmap.fillCircle(10, 10, 10); texture = new Texture(pixmap); pixmap.dispose(); }
Argumenty przekazywane do konstruktora to pozycje początkowe naszej postaci. Metoda super() to wywołanie konstruktora klasy dziedziczącej, w kodzie powyżej przyjmuje 3 argumenty, współrzędne z argumentów konstruktora oraz wartość 10 będąca promieniem naszego okręgu w pixelach. Przypisujemy wartość hp równą 100, a także zerujemy wynik (score). Prędkość początkowa jest równa 1.0 a wynika to z kilku możliwość, które oprogramujemy w przyszłości, będzie to spowolnienie oraz przyśpieszenie ruchu.
Teraz zajmiemy się utworzeniem naszego okręgu reprezentującego bohatera wypełnionego kolorem żółtym. Konstruktor klasy Pixmap przyjmuje dla dwóch pierwszych argumentów szerokość oraz wysokość naszej textury, ostatnim argumentem jest formatowanie w naszym przypadku to 32bity. Następnie ustawiamy kolor jakim wypełnimy nasze koło na kolor żółty. Linijka niżej odpowiada za narysowanie i wypełnienie koła gdzie jego środek to 10×10 (pamiętamy o tym, że nasza pixmapa ma 20px na 20px) oraz promień jest równy 10. Inicjalizujemy zmienną texture podając jako argument nazwę zmiennej klasy Pixmap (pixmap). Od tego momentu narysowane przez nas koło jest zapisane w zmiennej texture, zatem zmienna pixmap możemy już usunąć wywołując metodę dispose().
Teraz abyśmy mogli zobaczyć efekty naszej pracy musimy przejść do klasy w której wyświetlamy elementy na ekranie i wprowadzić poprawki.
private Player player;
Dodajemy zmienną naszej nowej klasy. następnie ją inicjalizujemy w metodzie start(). Podane wartości jako argumenty są przypadkowe (w chwili obecnej nie ma to większego znaczenia)
player = new Player(500, 500);
Teraz już tylko pozostaje wyświetlić efekt naszej wcześniejszej pracy poprzez dodanie do metody render() jednej linijki.
batch.draw(player.getTexture(),player.x, player.y);
Po skompilowaniu ujrzymy taki efekt
Teraz zajmiemy się ruchem naszego bohatera.
Abyśmy mogli generować ruch musimy odświeżać współrzędne przed każdym wyświetleniem jej na ekranie, dlatego tworzymy w klasie UWar.java metodę update(), która będzie odpowiedzialna za obliczenia wykonywane przed odświeżeniem ekranu. Tworząc metodę dodajemy w jej ciele:
private void update() { if(Gdx.input.isKeyPressed(Input.Keys.ESCAPE)){ Gdx.app.exit(); } if(Gdx.input.isKeyPressed(Input.Keys.W)){ player.y += 5; } if(Gdx.input.isKeyPressed(Input.Keys.S)){ player.y -= 5; } if(Gdx.input.isKeyPressed(Input.Keys.A)){ player.x -= 5; } if(Gdx.input.isKeyPressed(Input.Keys.D)) { player.x += 5; } }
Mamy tutaj 5 instrukcji warunkowych, w pierwszym przypadku, kiedy zostanie wciśnięty ESC aplikacja zostanie zamknięta, jest to nam potrzebne, ponieważ jak zauważyliście na poprzednim screenie aplikacja wyświetla się na całym ekranie co zapisaliśmy na początku tego wpisu. Kolejne warunki odpowiadają za zmianę położenia naszego bohatera. Jeśli zostanie wciśnięty klawisz W do atrybutu y zmiennej player zostanie dodanych 5px i tak odpowiednio w każdym przypadku. Jednak gdybyśmy teraz uruchomili aplikację nie zauważylibyśmy żadnych zmian, byłoby to spowodowane tym, że grafika wyświetlana na ekranie nie jest aktualizowana. Zatem aby wszystko działało jak trzeba, należy dodać na samym początku metody render()
update();
W tej chwili mamy już efekt poruszania się naszej postaci.
Podsumowując
Wpis dłuższy od wszystkich wcześniejszych, ale udało nam się już troszeczkę napisać. Mamy wyświetlaną postać na ekranie za pomocą żółtego kołka, możliwość poruszania się, wyjścia z aplikacji za pomocą przycisku ESC oraz przygotowane zmienne w klasie Player.java do dalszej rozbudowy bohatera, czym będziemy zajmować się w kolejnych wpisach.
Życzę wszystkim miłego wieczoru.
sirmarbug