System prezentów…

bugajsky.pl 7 lat temu

W ostatnim wpisie omówiliśmy całą logikę naszej gry. Jedną z jej części był system prezentów. Pojawiają się one co 1,5 minuty lub wtedy, gdy dwie zmienne, zainicjalizowane losowymi liczbami z przedziału 1000 są takie same. W chwili gdy długo nie został spełniony warunek z losowaniem liczb po upływie 1,5h zostaje dodany nowy prezent, a czas wyzerowany. Prezenty mają jedną szczególną cechę, przed zebraniem go, nie wiemy czy bonus jaki otrzymamy zadziała na naszą korzyść, czy wręcz przeciwnie.

Obecna lista bonusów

  • +10 pkt życia dla bohatera
  • -10 pkt życia dla bohatera
  • zwiększyć szybkość poruszania się gracza
  • zmniejszyć szybkość poruszania się gracza
  • zwiększyć szybkość poruszania się wrogów
  • zmniejszyć szybkość poruszania się wrogów
  • usunięcie wszystkich strzałów wrogów

Kodujemy

Po wstępie teoretycznym przyszedł czas na napisanie kilku nowych linijek w naszym projekcie. Zabawę zaczniemy od utworzenia nowej klasy Gift.

public class Gift extends Rectangle{ private int type; private Pixmap pixmap; private Texture texture; private Sprite sprite; private float time; public Gift(int x, int y) { super(x,y,32,32); pixmap = new Pixmap(32, 32, Pixmap.Format.RGBA8888); pixmap.setColor(Color.PURPLE); pixmap.fillRectangle(0,0, 32, 32); texture = new Texture(pixmap); sprite = new Sprite(texture); pixmap.dispose(); Random r = new Random(); type = r.nextInt(7); time = 20; sprite.setX(x); sprite.setY(y); } public int getType() { return type; } public void setType(int type) { this.type = type; } public Pixmap getPixmap() { return pixmap; } public void setPixmap(Pixmap pixmap) { this.pixmap = pixmap; } public Texture getTexture() { return texture; } public void setTexture(Texture texture) { this.texture = texture; } public Sprite getSprite() { return sprite; } public void setSprite(Sprite sprite) { this.sprite = sprite; } public float getTime() { return time; } public void setTime(float time) { this.time = time; } }

Pole type jest wykorzystywane do rozróżniania jaki bonus ma zastać przyznany. pixmap, texture oraz sprite (o którym jeszcze nie było mowy) odpowiedzialne są za rysowanie na ekranie naszego prezentu. Ostatnim z pól jakie zostały dodane do naszej nowej klasy jest time, który odpowiada za obliczenie czasu przez jaki wyświetlany jest prezent po wyświetleniu go na ekranie.

Chciałbym teraz wspomnieć kilka słów o klasie Sprite, po co i dlaczego znajduję się w naszym kodzie. Klaas ta ma zaimplementowane metody służące do modyfikacji wczytanej tekstury, np. obracania, powiększania czy pomniejszania.

Dziś zrobimy aby nasz prezent był kwadracikiem o kolorze różowym oraz aby obracał się zgodnie ze wskazówkami zegara. Jednak teraz przejdźmy do omówienia konstruktora.

Pierwsze pięć linijek to już dobrze nam znane z wcześniejszych wpisów tworzenie obrazka na ekranie. W kolejnej linijce następuje załadowanie textury do sprite. Następnie usuwamy z pamięci dane załadowane do zmiennej pixmap. Kolejna linijka to utworzenie zmiennej klasy Random, którą niżej wykorzystujemy do wylosowania jednego z siedmiu typów nagród. Wiersz niżej ustawiamy czas w jakim będziemy mogli zebrać prezent, czas ten jest równy 20 sekund. Ostatnie dwie linijki konstruktora są odpowiedzialne za ustawienie położenia sprite, którego będziemy rysować na ekranie.

private String info; private String gift; private BitmapFont infoFont; private BitmapFont giftFont;

Teraz do klasy Interfejs.java dodajemy nowe zmienne, które posłużą nam do wyświetlania informacji jaki bonus został zebrany oraz w przypadku nagród czasowych do wyświetlania pozostałego czasu.

infoFont.draw(batch, info, 150, 20); giftFont.draw(batch, gift, 500, 425);

Pozostało jeszcze dodać nam dwie linijki do nadpisywanej metody draw(), które odpowiadają za wyświetlanie danych w określonym miejscu.

Teraz możemy dodać dwie metody do naszej, dziś utworzonej klasy Gift.java

public void animation(){ getSprite().rotate(-2); } public void getGift(Player player, LinkedList<Monster> monsters, LinkedList<Shoot> shootsPlayer, LinkedList<Shoot> shootsMonster, Interface myInterface){ if(getType() == 0){ player.setHp(player.getHp() + 10); myInterface.setInfo("Dodano 10pkt zycia"); }else if(getType() == 1){ player.setHp(player.getHp() - 10); myInterface.setInfo("Odjeto 10pkt zycia"); }else if(getType() == 2){ player.setSpeed(player.getSpeed() + 50); myInterface.setInfo("Zwiekszono szybkosc gracza"); }else if(getType() == 3){ player.setSpeed(player.getSpeed() - 50); myInterface.setInfo("Zmniejszono szybkosc gracza"); }else if(getType() == 4){ for(Iterator<Shoot> it = shootsMonster.iterator(); it.hasNext();) { Shoot shoot = it.next(); it.remove(); myInterface.setInfo("Usunieto wszystkie strzaly wrogow"); } }else if(getType() == 5){ for (Monster monster : monsters) { monster.setSpeed(monster.getSpeed() + 1); myInterface.setInfo("Zwiekszono szybkosc wrogow"); } }else if(getType() == 6){ for (Monster monster : monsters) { monster.setSpeed(monster.getSpeed() - 1); myInterface.setInfo("Zmniejszono szybkosc wroga"); } } }

Pierwsza metoda animation(), odpowiada za obracanie naszego prezentu. Na pobranym sprite wykonujemy metodę rotate(), a jako parametr podajemy stopień o jaki ma zostać obrócona nasza tekstura.

Druga metoda jest już bardziej skomplikowana. To w tej metodzie zostaje rozpoznany typ prezentu, wykonana odpowiednia operacja oraz wyświetlony komunikat na ekranie o rodzaju przyznanego bonusu. Lista parametrów jest długa, ale zawiera wszystkie niezbędne rzeczy do wykonywania na nich operacji. W kolejności przesyłamy, postać bohatera, listę przeciwników, strzały gracza, strzały wrogów oraz interfejs do wyświetlania komunikatów.

Następnie dzięki ifów sprawdzamy typu. Dla równego 0 dodajemy 10 punktów życia oraz wyświetlamy komunikat Dodano 10pkt życia, gdy typ jest równy 1 wykonujemy podobne operację tylko zamiast dodania punktów życia odejmujemy je.

Dla typu 2 i 3 wykonujemy kolejne podobne operacje. Tym razem będziemy przyśpieszać i zwalniać tempo poruszania się bohatera. Ustawiamy nową prędkość odpowiednio zwiększoną lub zmniejszoną o 50 jednostek. Na koniec dajemy graczowi informację o typie prezentu.

Kolejną grupową operacją jest typ 5 i 6. Wykonywany jest na wszystkich obecnych przeciwnikach, gdzie będziemy zwiększać lub zmniejszać szybkość naszych przeciwników. Tworzymy iterator dzięki fora i ustawiamy nową prędkość wrogów zwiększoną lub zmniejszoną o 1 oraz podobnie jak wcześniej wyświetlamy komunikat dla gracza o typie zebranego prezentu.

Ostatnim prezentem jaki gracz może otrzymać jest wyczyszczenie wszystkich wrogich strzałów z obszaru gry. Znów dzięki fora tworzymy iterator i przechodząc przez całą listę usuwamy każdy z jej elementów.

Teraz pozostaje dodać całą logikę obsługującą naszą nową funkcję w czasie rozgrywki. Oczywiście na początku dodajemy nową listę typu LinkedList, która przetrzymuje obiekty naszej klasą, którą dziś utworzyliśmy, następnie ją inicjujemy. Koniecznym do działania naszych prezentów jest dodanie timerGift, który będzie odpowiedzialny za odmierzanie czasu między ostatnim dodanym na ekran prezentem.

// Obsługa prezentu // Rotaja if(giftLinkedList != null){ for (Gift g : giftLinkedList) { g.animation(); g.setX(g.getSprite().getX()); g.setY(g.getSprite().getY()); } } // Dodanie czasu od ostatniego prezentu timerGift += Gdx.graphics.getDeltaTime(); // Dodanie prezentu na mapę int g1 = r.nextInt(1000); int g2 = r.nextInt(1000); if(g1 == g2 || timerGift > 100){ giftLinkedList.add(new Gift(r.nextInt(5000), r.nextInt(5000))); timerGift = 0; } // sprawdzenie czasu obecnego prezentu if(player.getGiftTime() < 10 && player.getGiftType() != -1){ myinterface.setInfo(""); } // Show bonus time if(player.getGiftType() != -1){ player.setGiftTime(player.getGiftTime() - Gdx.graphics.getDeltaTime()); if(player.getGiftType() == 2 || player.getGiftType() == 3 || player.getGiftType() == 5 || player.getGiftType() == 6){ myinterface.setGift("Bonus: " + player.getGiftTime()); } } // Sprawdzenie czasu obencego prezentu if(player.getGiftTime() < 0 && player.getGiftType() != -1){ if(player.getGiftType() == 2){ player.setSpeed(player.getSpeed() - 50); myinterface.setGift(""); }else if(player.getGiftType() == 3){ player.setSpeed(player.getSpeed() + 50); myinterface.setGift(""); }else if(player.getGiftType() == 5){ for (Monster monster : potwory) { monster.setSpeed(monster.getSpeed() - 1); myinterface.setGift(""); } }else if(player.getGiftType() == 6){ for (Monster monster : potwory) { monster.setSpeed(monster.getSpeed() + 1); myinterface.setGift(""); } } System.out.println("Usuń bonus"); player.setGiftType(-1); player.setGiftTime(1); } // Kolizje Z PREZENTEM // Bohater - prezent for(Iterator<Gift> it = giftLinkedList.iterator(); it.hasNext();) { Gift gift = it.next(); Rectangle rec = new Rectangle(player.x - player.radius, player.y - player.radius, player.radius * 2,player.radius * 2); if(gift.overlaps(rec)){ if(player.getGiftType() == -1){ // if(gift.getType() == 2 || gift.getType() == 3 || gift.getType() == 5 || gift.getType() == 6){ player.setGiftTime(15); player.setGiftType(gift.getType()); // } it.remove(); gift.getGift(player, potwory, strzaly,strzalyPotworow, myinterface); } } } // Kolizja potworek - prezent for(Iterator<Gift> giftIterator = giftLinkedList.iterator(); giftIterator.hasNext();) { Gift gift = giftIterator.next(); for(Iterator<Monster> monsterIterator = potwory.iterator(); monsterIterator.hasNext();) { Monster monster = monsterIterator.next(); if(gift.overlaps(monster)){ giftIterator.remove(); monster.setHp(monster.getHp() - 1); } } } // Kolizja strzał Potworów - prezent for(Iterator<Gift> giftIterator = giftLinkedList.iterator(); giftIterator.hasNext();) { Gift gift = giftIterator.next(); for(Iterator<Shoot> shootIterator = strzalyPotworow.iterator(); shootIterator.hasNext();) { Shoot shoot = shootIterator.next(); if(gift.overlaps(shoot)){ giftIterator.remove(); shootIterator.remove(); } } } // Kolizja strzał - prezent for(Iterator<Gift> giftIterator = giftLinkedList.iterator(); giftIterator.hasNext();) { Gift gift = giftIterator.next(); for(Iterator<Shoot> shootIterator = strzaly.iterator(); shootIterator.hasNext();) { Shoot shoot = shootIterator.next(); if(gift.overlaps(shoot)){ giftIterator.remove(); shootIterator.remove(); } } } // czas po którym prezent znika for(Iterator<Gift> giftIterator = giftLinkedList.iterator(); giftIterator.hasNext();) { Gift gift = giftIterator.next(); gift.setTime(gift.getTime() - Gdx.graphics.getDeltaTime()); if(gift.getTime() < 0){ giftIterator.remove(); } }

Na samym początku powyższego kodu tworzymy animację obracania się naszych prezentów poprzez wywołanie wcześniej napisanej metody animation(), w klasie Gift. Sprawdzamy czy lista z prezentami nie jest pusta, jeżeli znajduję się w niej jakiś prezent, następnie tworzony jest iterator (za pomocą iteratora przechodzimy przez kolejne elementy naszej listy prezentów) w którym wywołujemy metodę odpowiedzialną za obrót tekstury oraz ustawiamy obecne nowe współrzędne pobrane ze sprite.

Następnie zwiększamy czas (zmienna timerGift) od ostatnio dodanego prezentu poprzez wywołanie metody getDeltaTime().

Losujemy dwie liczby (g1 i g2) z przedziału od 0 do 999 i sprawdzamy warunek. jeżeli wylosowane liczby są równe lub czas od ostatniego dodania prezentu jest większy niż 1,5 minuty, wtedy dodaj nowy prezent z wylosowanymi współrzędnymi startowymi i wyzeruj timerGift.

Kolejny warunek jaki rozpatrujemy to, gdy czas obecnego prezentu jest mniejszy niż 10 oraz typ różny od -1, wtedy należy usunąć komunikat o prezencie. Usunąć w tym wypadku oznacza, zmienić go na obiekt klasy String będący pusty.

Teraz zajmiemy się wyświetlaniem pozostałego czasu w przypadku prezentów typu 2, 3, 5 i 6. Sprawdzamy czy typ prezentu w obiekcie klasy Player jest różny od -1, czyli czy przez ostatnie 15 sekund gracz zebrał prezent. To taki rodzaj blokady, aby nie było możliwości zbierania więcej niż 1 prezentu jednocześnie. Zmieniany zostaje czas od ostatniego zebranego prezentu. Następnie sprawdzany jest warunek, czy prezent nie był jednego z typów, które wymagają wyświetlenia pozostałego czasu działania prezentu. jeżeli był to prezentu typu 2, 3, 5 lub 6 wtedy wyświetl w prawym rogu ekranu informację o pozostałym czasie.

Po wyświetleniu informacji o pozostałym czasie, przez jaki bonus będzie działał, należy usunąć tą informację, kiedy wartość zejdzie poniżej 0. dlatego kolejne linijki służ właśnie temu, aby napis Bonus -0.12345678 został zastąpiony pustym napisem, w taki sam sposób jak miało to miejsce z wyświetleniem informacji o typie zebranego prezentu. Sprawdzamy zatem warunek czy czas jest mniejszy od 0 i czy typ jest różny od -1, jeżeli warunek jest spełniony, przywracamy poprzedni stan oraz tworzymy pusty napis. Na koniec ustawiamy giftType na -1 oraz giftTime na 1.

Teraz pozostaje nam zrobić obsługę kolizji prezentu z bohaterem, wrogiem, strzałem bohatera oraz strzałami wrogów. Opiszę kolizję bohatera z prezentem. Tworzymy iterator, gracz ponieważ jest kołem zostaje mu stworzony obszar kwadratowy, aby w prosty sposób móc zrealizować kolizję. Następnie sprawdzany jest warunek czy jeden obiekt nachodzi na drugi, jeżeli warunek jest spełniony czas gracza zostaje ustawiony na 15 sekund oraz typ ustawiony zgodnie z typem zebranego prezentu. W kolejnym kroku usuwany jest prezent z listy oraz wywołana wcześniej opisana metoda getGift().

Pozostałe kolizje będą powodować głownie usunięcie prezentu. Jednak w przypadku kolizji prezentu z wrogiem dodatkowo zostaje odjęty 1 punkt życia wroga. Natomiast w przypadku strzałów usuwane są także strzały, które uderzyły w dany prezent.

Ostatnią rzeczą jaką chce zaimplementować do naszej gry jest czas przez jaki od pojawienia się prezentu może on zostać zebrany. jeżeli minie 20 sekund, a prezent nie zostanie zebrany, podarunek od losu zniknie. Tworzymy iterator, następnie ustawiamy nowy czas w obiekcie Gift, poprzez odjęcie różnicy klatek (getDeltaTime()). Sprawdzamy warunek, czy po odjęciu czas nie jest mniejszy od 0, jeżeli tak się stało następuje usunięcie obiektu z listy.

Efekt naszego kodu

Podsumowanie

Dziś udało nam się stworzyć system prezentów, jakie gracz może zbierać podczas rozgrywki. Jest to bardzo istotny element gry, ponieważ zbierając prezenty, można wiele zyskać lub stracić. Niekiedy -10 punktów życia oznacza koniec rozgrywki lub zwolnienie ruchów gracza powoduje, iż wrogowie stają się zbyt silni.

Pozdrawiam,

sirmarbug

Idź do oryginalnego materiału