(WIP) Wiedźma – gra co miesiąc: styczeń – update 1

Pora na pierwsza aktualizację projektu „Wiedźma – gra co miesiąc”. Spędziłem nad projektem trochę czasu i muszę przyznać, że gra zaczyna nabierać kształtów. Prawie wszystkie zmiany nastąpiły w głównym stanie gry. Jedyna zmiana poza nim to nowy stan, obsługujący sytuacje, w której gracz ukończy grę z pozytywnym wynikiem. Aby go osiągnąć trzeba sprawić żeby czarownica zebrała 4 magiczne zioła i wróciła z nimi do chatki.

Zioła można znaleźć w lesie. Aby je zioło, czarownica musi po prostu na nie nalecieć. Dodałem też system powiadomień. Kiedy gracz wykona jakąś akcje, która wpłynie na stan gry, na ekranie pojawi się tekst informujący go o tym. Na przykład gdy czarownica wleci do chatki bez wszystkich ziół, pojawi się odpowiednie powiadomienie. Ostatnią nowością, jest to, że wiedźma może teraz ciskać magicznymi pociskami. Aby ją do tego zmusić, wystarczy że gracz naciśnie spację.

Wiedźma - gra co miesiąc

W nową wersję gry można zagrać klikając w obrazek powyżej. Jak zwykle, przygotowałem też paczkę z kodem aktualnej wersji.

Nie będę dokładnie opisywał każdej zmiany. Chcę tylko aby każdy wiedział mniej więcej na jakim etapie jest gra. Kod można dokładnie obejrzeć ściągając sobie paczkę. Jeżeli będą jakieś niejasności, pytajcie w komentarzach, na pewno odpowiem 🙂 .

Przedstawię te aspekty, które według mnie są najważniejsze. Postaram się w miarę zwięźle omówić co miałem na myśli pisząc dany kod 🙂 . Tak naprawdę nie zastosowałem żadnych nowych technik, wszystko co dodałem opiera się na rzeczach, które już wcześniej opisałem. Każdy kto czyta moje wpisy na bieżąco, powinien połapać się we wprowadzonych zmianach 🙂 .

Wiedźma – gra co miesiąc: styczeń – update 1 – kod

Wszystkie nowości wymienione poniżej, znajdują się w obiekcie stanu gameState. Wszelkie instancję this, odnoszą się właśnie do niego.

Pierwsza rzecz, którą chciałbym omówić to system powiadomień. Bazują one na obiekcie message , który dodałem jako pole do stanu gry.

Jest to wzór, na podstawie którego tworzone będą konkretne instancje powiadomień. Zawiera on informacje o tym, gdzie ma zostać wyświetlony tekst, jak długo ma być widoczny, oraz jaka będzie jego treść.

Na razie muszę na tym poprzestać opis systemu wiadomości. Aby zaprezentować jak dokładnie działa, najpierw przejdę do omówienia innej nowości, która z tego systemu korzysta.

Drugim nowym polem w obiekcie gameState. Jest obiekt witchHouse.

Ten prosty obiekt, będzie reprezentował, obszar w grze, traktowany jako domek wiedźmy. Posiada jedynie informacje o rozmiarze oraz lokacji. Nie potrzebuję nic więcej, ponieważ grafika domku wiedźmy jest częścią dużego obrazka tła gry. Ten obiekt to tylko jego abstrakcyjna reprezentacja.

Dzięki niemu, mogę teraz sprawdzać czy wiedźma jest aktualnie w domku czy nie. Sprawdzenie to odbywa się wewnątrz metody update, która odpalana jest co klatkę gry:

Powyższy fragment kodu znajduje się wewnątrz metody update. najpierw wywoływana jest metoda checkCollision (ta sama, którą opisuję tutaj), która sprawdza, czy pomiędzy dwoma obiektami przekazanymi w argumencie, zachodzi kolizja. Jeżeli nie, pole w obiekcie czarownicy inHouse (nowe) ustawiane jest na false. Jeżeli kolizja zachodzi, i pole inHouse równa się false, ustawiane jest na true i odpalana jest metoda checkWitchAtHouse.

Pole inHouse potrzebne mi jest po to aby sprawdzić kiedy czarownica wlatuje i kiedy wylatuje w obszar domku. Chcę aby zdarzenie, wywoływane wleceniem do domku, zostało wywołane tylko raz na jeden wlot, a nie cały czas, gdy wiedźma jest wewnątrz.

Pora na metodę checkWitchAtHouse:

Tutaj pojawia się nowe pole obiektu wiedźmy: herbsCollected. Zawiera ono informację o tym ile ziół zostało już zebranych. Jeżeli jest ich cztery, oznacza to, że gracz zdobył wszystkie. W takim wypadku program zmienia stan gry. Jak to dokładnie działa opisałem wcześniej. Oprócz ustawienia, pól toLeave oraz nextState, resetowane są również tablice z obiektami wyświetlanymi przez stan. Nie muszę czyścić nic innego ponieważ, właściwości obiektów i tak ustawiane są podczas inicjalizowania stanu.

Gdy wiedźma wleci do domku, a zebrana liczba ziół wynosi 4, gra wyświetla powiadomienie. I tutaj mogę wrócić do obiektu w polu message stanu gry. Tworzona jest nowa instancja tego obiektu, i przypisywana do tymczasowej zmiennej. Tekst nowej instancji powiadomienia ustawiany jest na informacje o tym ile jeszcze ziół musi zebrać grać. Gdy taka wiadomość jest gotowa, zostaje wrzucona do tablicy messages.

Wiadomości znajdujące się w tablicy messages są następnie aktualizowane w metodzie update i wypisywane w metodzie draw.

Fragment metody update odpowiedzialny za aktualizacje wiadomości:

Tutaj sprawa jest bardzo prost. Dla każdego elementu tablicy update, program zwiększa wartość jego pola displayedFor. Jeżeli wartość tego pola jest większa lub równa wartości z pola dispTime, ta wiadomość jest usuwana z tablicy messgaes. Domyślna wartość dispTime dla każdego powiadomienia to 160. W efekcie ten mechanizm sprawia, że każda wiadomości widnieje na ekranie nie całe 3 sekundy.

Teraz wystarczy jeszcze wpisać wiadomości na ekranie. Zajmuje się tym ten fragment metody draw:

I tutaj wszystko powinno być jasne. Ustawiam kolor, styl oraz rozmiar czcionki. Tekst wyrównany będzie do środka. Oznacza to, że podana współrzędna x będzie znajdować się dokładnie w środku tekstu. Ponieważ, wyznaczony x każdej wiadomości to środek płótna, powiadomienia będą idealnie wyśrodkowane.

Następnie każda wiadomość jest wypisywana na ekranie za pomocą metody fillText. Pierwsze powiadomienie z tablicy messages pojawi się na ustalonej we współrzędnej y wysokości, a każda następna o 25 pixeli niżej. Dzięki temu, mogę wyświetlać wiele powiadomień na raz.

Wiadomo już jak działają powiadomienia oraz jak sprawdzam czy wiedźma zebrała wszystkie ziółka. Teraz czas na omówienie samych ziół.

Zioła tworzone są podczas inicjalizacji stanu gry. Tak wygląda odpowiedzialny za to fragment metody init.

Tworzę nową klasę herb bazującą na obiekcie spriteObject. Dodaje pola potrzebne do obsługi animacji, ponieważ każde zioło będzie reprezentowane animacją składająca się z czterech klatek. Kolejna nowe pole to active, będzie ono równe true, do momentu aż zioło zostanie zebrane przez wiedźmę. Kolejne cztery pola klasy herb, to rozmiar zioła, oraz rozmiar obrazka, który będzie je reprezentował. Na końcu ustawiam wartość współrzędnej y, ponieważ dla każdego zioła będzie taka sama. Chcę aby wyświetlały się zaraz nad ‚ziemią’ w widoku gry.

Kolejny krok to stworzenie 4 instancji klasy herb, są to obiekty reprezentujące cztery zioła, które gracz musi zebrać: mniszek, tarczyca, paproć oraz kocimiętka.

Dla każdej instancji ustawiam osobno wartość jej współrzędnej x. Są one rozmieszczone mniej więcej co 1/4 długości mapy gry. Każde zioło otrzymuje też pole name o unikatowej wartości równej nazwie rośliny. Będę wykorzystywał to pole do wyświetlenia wiadomości, że dane zioło zostało zebrane. Ostatnie pole ustawione osobno dla każdego zioła to pionowa lokacja reprezentującego go obrazka w arkuszu obrazków.

Gdy wszystkie zioła są już gotowe, lądują w tablicy herbs. Teraz wystarczy zmienić metody update oraz draw, tak aby aktualizowały i rysowały zioła.

Oto odpowiedni fragment metody update:

Oraz odpowiedni fragment metody draw:

Te fragmenty, nie powinny wymagać tłumaczenia. Metoda update, po prostu sprawdza, czy czas wyświetlić kolejną klatkę dla każdego zioła w tablicy, jeżeli tak robi to i aktualizuje po drodze wszystko co trzeba. Metoda draw rysuję odpowiednią obrazek w odpowiednim miejscu jeżeli dane zioło jest aktywne.

Teraz wystarczy jeszcze sprawdzić, czy czarownica zebrała któreś z ziół. Robię to w metodzie update. Oto odpowiedzialny za to kod:

Dla każdego elementu tablicy herbs, sprawdzam przy pomocy metody checkCollision czy nie nastąpiła kolizja pomiędzy nim a wiedźmą. Jeżeli tak i dane zioło jest aktywne, zmieniam pole zioła active na false i odpalam metodę collectHerb, która jako argument otrzymuje dane zioło.

Metoda collectHerb wygląda tak:

Przede wszystkim, w tej metodzie, zwiększam wartość pola obiektu czarownicy herbsCollected o jeden. Następnie tworzone są dwa powiadomienia. Pierwsze informuje gracza, które z ziół udało mu się zdobyć. Treść drugiego, zależy od ilości zebranych już ziół i informuje ile jeszcze należy zebrać. Jeżeli gracz ma już wszystkie zioła, druga wiadomość mówi, że czas wracać do chatki.

Ostatnia z nowości w tej aktualizacji to możliwość strzelania przez wiedźmę magicznymi pociskami. Aby to zrobić, wystarczy nacisnąć spację.

Pierwszą rzeczą jaką potrzebuję to klasa magicznego pocisku. Definiuję ją w metodzie init:

Jak wszystkie obiekty, które mają być rysowane w grze, magiczny pocisk tworzę na bazie klasy spriteObject. Dla pocisku ustawiam wszystkie informacje potrzebne do poprawnego narysowania go, łącznie z informacjami potrzebnymi do animacji (animacja pocisku składa się z czterech klatek). Definuję również szybkość poruszania się pocisku (pole speed) oraz jego kierunek (pole velocity).

Teraz potrzebuję sposoby na wypuszczenie pocisku. Aby go uzyskać, w metodzie update dodaję poniższy fragment.

Jeśli gracz nacisnął spację i pole obiektu czarownicy missileFired równe jest false, program ustawia to pole na true oraz odpalana jest metoda fireMissile. Jeżeli spacja nie jest naciśnięta, missileFired ustawiane jest na false. Dzięki temu, nie ograniczam gracza do konkretnej liczby pocisków na sekundę, ale zarazem unikam sytuacji, w której gracz wypuszcza ciągłą serię pocisków trzymając spację. Będzie musiał stukać w spację ile sił w palcach 🙂 .

A oto jak wygląda metoda fireMissile:

Chyba nikt nie będzie zaskoczony jej działaniem. Tworzona jest nowa instancja obiektu, magicMissile, która otrzymuję odpowiednie wartości współrzędnych x oraz y. przy określeniu początkowego x oraz velocity, biorę pod uwagę w którą stronę, zwrócona jest czarownica (Pole facing równe 0, czarownica zwrócona w lewo. Pole facing równe 1, czarownica zwrócona w prawo). Na końcu dodaję nowo utworzony pocisk do tablicy magicMissiles.

Co dalej? Oczywiście, aktualizacja i narysowanie pocisku. Jak we wcześniejszych przypadkach, dodaję nowe fragmenty kodu do metod update oraz draw. Oto te fragmenty:

Nowy kod w metodzie update:

Nowy kod w metodzie draw:

Przedstawiony fragment metody update, to pętla for, która wykonuje kod dla każdego elementu tablicy magicMissiles. Kod ten można podzielić na trzy części. Pierwsza najobszerniejsza część, obsługuje wyświetlanie animacji pocisku. Kolejna część, to właściwie tylko jedna linijka. Tutaj zmieniana jest wartość współrzędnej x danego pocisku. Wartość ta zwiększa się o prędkość pocisku przemnożoną przez wartość velocity (która jest równa -1, jeśli pocisk leci w prawo i 1, jeśli pocisk leci w lewo). Na końcu przedstawionego fragmentu metody update znajduje się wyrażenie warunkowe, sprawdzające czy dany pocisk nie wyleciał sto pikseli poza którąś z krawędzi płótna. Jeżeli tak, jest usuwany z tablicy.

Nowy kod metody draw, jest dość oczywisty. Każdy z pocisków jest rysowany na ekranie zgodnie z jego współrzędnymi, wielkością oraz aktualną klatką.

Tak jak wspominałem, nie będę opisywał nowego stanu gameWon. I tak jest to tylko placeholder. Pojawia się, gdy gracz zbierze wszystkie zioła i wróci do chatki. Jeśli w tym stanie, użytkownik wciśnie spację, gra wczyta stan menuState, z którego można zacząć zabawę od nowa.

I to wszystkie nowości w tej aktualizacji. Wbrew pozorom nie ma tego wcale dużo 🙂 Kod się rozrasta a co za tym idzie, robi się mały bałagan. Spróbuję zrobić porządki ale nie obiecuję że się uda.

Kolejnym krokiem będzie na pewno dodanie potworów, które znacznie utrudnią graczowi stojące przed nim zadanie 🙂 . To będzie przedostatnia aktualizacja. W ostatniej czeka mnie uzupełnienie stanów, które teraz są tylko placeholderami.

Następna aktualizacja powinna pojawić się dość szybko, najpóźniej na początku przyszłego tygodnia. Muszę przyśpieszyć prace, jeśli mam zdążyć przed końcem stycznia 🙂 Jeżeli chcesz być na bieżąco z aktualizacjami tej gry, zachęcam do polubienia mojej strony na facebooku. Regularnie zamieszczam tam informacje o wszystkich nowościach na blogu.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *