- W ostatnim wpisie zajmowaliśmy się poprawieniem kodu odpowiedzialnego za wyświetlanie grafiki bohatera na ekranie. Wzorując się na napisanym przez nas, ostatnio kodzie, stworzymy grafikę prezentującą wrogie jednostki. Na początku każdy przeciwnik będzie reprezentowany przez taką samą grafikę. Zatem dla oka wszyscy wrogowie będą tacy sami, z czasem wprowadzimy kilka tekstur, aby gra jeszcze lepiej się prezentowała.
Przygotowanie grafiki
Podobnie jak ostatnio, przygotowałem wcześniej grafikę za pomocą programu GDX TexturePacker GUI, który omówiłem w jednym z wcześniejszych wpisów.
W efekcie pracy z programem GDX TexturePacker GUI, uzyskałem mapę, składającą się z trzech grafik, które będą nam służyć do rysowania postaci wrogów na ekranie.
Kodujemy
Dotychczas wrogowie byli przedstawiani na ekranie jako niebieskie kwadraty, czas to zmienić.
Zatem przechodzimy do klasy Monster.java, gdzie dodajemy nowe pola, które umożliwią nam wyświetlanie grafiki oraz utworzenie animacji ruchu.
private float moveTime; private int step; private Sprite sprite;
moveTime będzie odpowiedzialne za przechowywanie czasu między zmianą kroku wroga, dokładnie tak samo jak miało to miejsce w przypadku postaci gracza.
step pole, które przechowuje obecny krok, wykorzystamy je do wyświetlania interesującej nas grafiki z mapy.
sprite przechowuje wczytaną grafikę do wyświetlenia.
Do każdego nowego pola generujemy gettery i settery.
W konstruktorze dodajemy wartości podstawowe, jakie mają zostać załadowane przy utworzeniu nowego wroga.
moveTime = 0; step = 1; sprite = new Sprite();
Czas zerujemy, krok ustawiamy na wartość 1, która oznacza postać w spoczynku, bezruchu oraz inicjalizujemy pole przechowujące grafikę.
public void stepAnimation(float time){ setMoveTime(getMoveTime() + time); if(getMoveTime() > 0.15) { setStep(getStep() + 1); setMoveTime(0); if(getStep() > 2) setStep(0); } }
Teraz przyszedł czas na stworzenie metody, odpowiedzialnej za animowanie rysowanej postaci. Metoda jest zbliżona do tej, która umożliwia nam animowanie postaci gracza.
W pierwszej linijce metody stepAnimation() dodajemy różnice czasu miedzy klatki gry. Następnie sprawdzamy warunek czy czas od ostatniej zmiany kroku jest większy od 0.15 sekundy, jeśli warunek jest spełniony następuje zmiana kroku poprzez inkrementację pola step, korzystając z metody setStep() oraz wyzerowanie czasu przy pomocy metody SetMoveTime().
Pozostaje jeszcze sprawdzić nam czy zinkrementowane pole step nie jest większe niż 2, jeśli tak się stanie należy wartość tą zamienić na 0.
public void draw (SpriteBatch batch, TextureAtlas region, float angle) { sprite.set(region.createSprite("" + getStep())); sprite.setPosition(x, y); sprite.rotate(angle); sprite.draw(batch); }
Do poprawnego wyświetlania naszych nowych grafik postanowiłem napisać metodę draw(), która jak sama nazwa wskazuje, będzie za to odpowiedzialna.
Jako argumenty przyjmuje obszar na którym ma zostać narysowany obiekt, czyli w naszym wypadku batch, mapę grafik – region, która zawiera wyświetlane grafiki oraz kąt o jaki ma zostać obrócony sprite angle, ponieważ posiadamy tylko 3 grafiki, musimy je obracać, aby postać wyświetlana była zgodnie z kierunkiem ruchu.
W pierwszej kolejności ustawiamy sprite, grafikę jaka będzie wyświetlana. Korzystamy przy tym z pola step, odczytując z niego, która grafika ma zostać załadowana.
Następnie, określamy pozycję w jakiej ma zostać wyświetlony obiekt, korzystając z metody setPosition(), gdzie jako parametry przekazujemy wartość x i y danego obiektu.
Przed wyświetleniem pozostaje nam jeszcze obrócić załadowaną grafikę, o kąt przekazany przez argument.
Teraz możemy już narysować obiekt na ekranie, poprzez wywołanie metody draw(), przekazując argument batch, czyli nasz obszar na którym wyświetlamy wszystkie elmenty gry.
Tak zmodyfikowana klasa Monster.java, pozwala nam przejść teraz do klasy Game.java, aby wykorzystać nowy kod.
private TextureAtlas textureAtlasEnemy;
Tworzymy nowe pole, które będzie przechowywało wygenerowaną wcześniej mapę grafik. Następnie, inicjalizujemy je poprzez określenie pliku, zawierającego informacje o obszarach z jakich składa się mapa.
textureAtlasEnemy = new TextureAtlas(Gdx.files.internal("enemy.pack"));
W metodzie redner() zastępujemy wcześniejszy kod, który wyświetlał nam niebieski kwadracik na kod wyświetlający nową grafikę.
Wcześniejszy kod
batch.draw(m.getTexture(), m.x, m.y);
Obecny kod
if(m.getMoveDirection() == 0){ m.draw(batch, textureAtlasEnemy, 180); // left }else if(m.getMoveDirection() == 2){ m.draw(batch, textureAtlasEnemy, 0); // right }else if(m.getMoveDirection() == 1){ m.draw(batch, textureAtlasEnemy, 90); // down }else{ m.draw(batch, textureAtlasEnemy, 280); // up }
Kod wygląda dokładnie tak samo jak przy rysowaniu postaci bohatera, można przeczytać o tym co dokładnie dzieje się w tej części kodu tutaj.
Teraz pozostało nam jeszcze, stworzyć animację ruchów przeciwników. Wystarczy dodać dwie linijki kodu i mamy gotowe. W częsci odpowiedzialnej za poruszanie przeciwników musimy dodać naszą nową metodę stepAnimation().
Wcześniejszy kod
for (Monster m : potwory) { if (m.getMoveQuantity() > 0) { m.moveToBottom(); m.moveToLeft(); m.moveToRight(); m.moveToTop(); m.setMoveQuantity(m.getMoveQuantity() - 1); } else { m.generateMove(player); m.moveToBottom(); m.moveToLeft(); m.moveToRight(); m.moveToTop(); m.setMoveQuantity(m.getMoveQuantity() - 1); } }
Obecny kod
for (Monster m : potwory) { if (m.getMoveQuantity() > 0) { m.moveToBottom(); m.moveToLeft(); m.moveToRight(); m.moveToTop(); m.setMoveQuantity(m.getMoveQuantity() - 1); m.stepAnimation(Gdx.graphics.getDeltaTime()); } else { m.generateMove(player); m.moveToBottom(); m.moveToLeft(); m.moveToRight(); m.moveToTop(); m.setMoveQuantity(m.getMoveQuantity() - 1); m.stepAnimation(Gdx.graphics.getDeltaTime()); } }
Jak pamiętamy nasza metoda stepAnimation(), przyjmuje tylko jeden parametr i jest nim różnica czasu pomiędzy ostatnią, a obecną klatką. Ta jednak linijka wstawiona w dwóch miejscach, pozwala nam na wyświetlanie poprawnej animacji.
Efekt działania
Podsumowanie
Udało się nam zrobić, kolejny krok w drodze do zakończenia projektu. Tym razem zajęliśmy się wyświetlaniem grafiki prezentującej wrogie postacie. Dużo kodu było wzorowane na tym, który napisaliśmy przy tworzeniu grafiki wyświetlającej naszego bohatera, dlatego jeśli nie zrobiłeś tego wcześniej, warto zapoznać się z poprzednim wpisem, aby jeszcze bardziej zrozumieć, jak działa ten mechanizm w naszej grze. Już wkrótce zajmiemy się rysowaniem strzałów na ekranie.
Pozdrawiam,
sirmarbug