Piszemy RPGo-Platformówkę (14) – Fireball!

Dodajemy system umiejętności

Hej, w dzisiejszej części zajmiemy się napisaniem podwalin pod system umiejętności oraz zaimplementujemy umiejętność leczenia.

Tradycyjnie zachęcam do zagrania w [demo] oraz samodzielnego zapoznania się z [napisanym kodem].

Umiejętności – teoretycznie


System umiejętności (choćby w najprostszej formie) jest dostępny w wielu grach – nie tylko RPG. Dzięki niemu graczowi jest łatwiej się wczuć w grę i odczuwać rozwój zarówno postaci (jest coraz silniejszy) – co przekłada się na satysfakcję z grania – jak i przyczynie się do lepszego poznawania świata gry (bo np. do przejścia w konkretne miejsce wymagana jest umiejętność przechodzenia przez ściany). Dla lepszego zobrazowania systemu umiejętności w grach spójrzmy na przykłady.

Systemy umiejętności w grach

Prosty

Pierwszym (bardziej prymitywnym / niewidocznym dla gracza) jest ten zastosowany w grze Assassin’s Creed: Brotherhood gdzie od pewnego momentu gry jesteśmy w stanie wezwać swoich rekrutów, aby ci zlikwidowali za nas cele.

Assassin Creed: Brotherhood

Niewątpliwie mamy tutaj swego rodzaju umiejętność: ta funkcjonalność była do pewnego momentu zablokowana (odblokowuje ją przejście przez zadanie), przy czym do jej wykonania wymagane jest posiadanie zasobów (wolnych rekrutów, czyli takich niewysłanych na misje) oraz odczekanie odpowiedniej ilości czasu (cooldown). Można też ją ulepszać przez zwiększenie liczby posiadanie rekrutów oraz wysyłanie ich na misje tak aby zwiększyli swoją umiejętność walki.

Zaawansowany

Drugim systemem umiejętności, tym „zaawansowanym” można nazwać każdy widoczny dla gracza system posiadający drzewko rozwoju. Tutaj wszystko zależy od twórców, zazwyczaj polegają one na ulepszaniu / odblokowywaniu konkretnych umiejętności przy użyciu punktów umiejętności (te najczęściej się zbiera przez awans postaci na wyższy poziom). Im wyższy poziom umiejętności – tym lepsza jego skuteczność.

Same umiejętności też mogą działać pasywnie / aktywnie, t.j. odpowiednio: zawsze / z koniecznością manualnej aktywacji. Bardzo często też do odblokowania jednej umiejętności wymagane jest odblokowanie innej.

Dla przykładu spójrzmy na kilka drzewek z gier:

Ori and the Blind Forest

Ori and the Blind Forest przedstawia najprostszy z możliwych drzewek: rozwijamy 3 predefiniowane umiejętności. Każdą z nich możemy ulepszać jedynie w sposób liniowy (tzn aby ulepszyć jedno ulepszenie należy zebrać odpowiednią ilość punktów umiejętności oraz odblokować wszystkie poprzednie ulepszenia).

Wiedźmin 3

Dużo ciekawiej sprawa przedstawia się w rodzimym Wiedźminie 3,  tutaj mamy wiele poddrzew (ścieżek) rozwoju, gdzie do odblokowania danej umiejętności należy wcześniej zainwestować odpowiednią ilość punktów w tej samej gałęzi rozwoju. Co ciekawe aby z samej umiejętności móc skorzystać, to oprócz jej odblokowania należy uaktywnić ją przez przeciągnięcie jej do drzewa aktywnych umiejętności widocznego po prawej stronie ekranu (pomijam możliwość zwiększania efektu umiejętności przez łączenie ich w grupy jednego rodzaju i nakładanie specjalnych przedmiotów – mutagenów).

Wiedźmin 2

„Najciekawsze”, a co za tym idzie: najtrudniejsze w implementacji są drzewa umiejętności, które wyglądają jak grafy. Tj. do jednej umiejętności prowadzi wiele ścieżek i wymagane jest odblokowane wszystkich (lub przynajmniej jednego) dochodzących węzłów umiejętności, aby odblokować jedną wymarzoną umiejętność. Przykładem takiego drzewa jest to z Wiedźmina 2.

Same drzewa umiejętności potrafią być jeszcze bardziej rozbudowane, te gigantyczne zazwyczaj spotyka się w grach MMORPG. Jeżeli ktoś jest ciekawy jak duże potrafią to być to zachęcam do rzucenia okiem na drzewko z Path of Exile.

Fireball! Heal!


Skoro już wiemy „z czym się je” system umiejętności, to czas zabrać się do pracy. Tradycyjnie zabierzmy się za wyznaczenie celów:

  • zajmujemy się umiejętnościami „aktywnymi”,
  • do odblokowania / ulepszenia umiejętności będą nam służyły punkty umiejętności,
  • do odblokowania umiejętności należy spełnić wymagania:
    1. gracz musi posiadać odpowiednią ilość punktów umiejętności.
    2. do odblokowania umiejętności  może być wymagane posiadanie innej umiejętności na odpowiednim poziomie.

Kilka uwag odnośnie powyższych punktów:

  • zaimplementujemy możliwość posiadania tylko jednej umiejętności aktywnej (tj. jeżeli mamy odblokowane umiejętności: „FIreball”, „Heal” to musimy wybrać w menu którą umiejętność chcemy móc użyć po wciśnięciu klawisza);
  • umiejętności mają swoje poziomy, które wpływają na ich statystyki;
  • trzecia kropka implikuje to, że nasze drzewo będzie miało wygląd grafu (drzewa) w sensie matematycznym (chociaż implementacja wizualna / UI na to nie będzie bezpośrednio wskazywała).

Skill

Zacznijmy od najbardziej podstawowego elementu jakim jest pojedyncza umiejętność (Skill).

Tradycyjnie zachęcam do samodzielnej analizy, po czym zajmiemy się analizą konkretnych fragmentów.

Oczywistym faktem jest to, że ta klasa jest dopiero podstawą pod właściwe kody, więc do pewnego stopnia jest wirtualna.

Na powyższym listingu widzimy kolejno implementację wymagań dotyczących umiejętności (SkillRequirement), parametry wyjściowe potrzebne w innych modułach (typu: informacja czy umiejętność jest odblokowana, poziom umiejętności, jej nazwa) oraz parametry pomocnicze (resztę parametrów omówimy za chwilę).

Każdą umiejętność można użyć (w jakiś sposób), jej użycie może być zależne od celu ( GameObject target) np. możemy założyć, że umiejętność leczenia można użyć na sobie lub sojusznikach, tutaj ilość uzdrowionych punktów życia może być zależna od tego czy użyliśmy jej na sobie (leczymy mniej PŻ), czy na sojuszniku (leczymy więcej PŻ). Tego typu mechanika bardzo często używana jest w grach MMO, wymusza ona poniekąd granie w grupie, a nie „solo”.

Warto zauważyć, że powyżej mamy zaimplementowany jedynie prolog metody Use będący wspólny dla większości umiejętności. Poprawny sposób implementacji z użyciem powyższego prologu będzie pokazany poniżej.

W prologu najpierw sprawdzamy czy możemy użyć danej umiejętności, a więc: czy umiejętność jest odblokowana oraz czy cooldown już minął. Następnie uruchamiamy czas cooldownu. Dalsza część (a więc samo użycie) jest implementowane przez klasy nadrzędne – dziedziczące po Skill.

Sprawdzenie tego czy umiejętność możemy odblokować wymaga od nas odwołania się do drzewka umiejętności, w którym to przechowujemy punkty umiejętności. Na początku oczywiście sprawdzamy, czy posiadamy ich dostateczną ilość, po czym sprawdzamy czy wszystkie wymagania związane z umiejętnością są spełnione (a więc odblokowanie innych umiejętności na dany poziom):

Po wykonaniu tego kroku aktualizujemy samą umiejętności oraz koszt odblokowania następnego poziomu umiejętności.

Resztę metod z tej klasy pozostawiam do samodzielnej analizy (są raczej proste i w moim odczuciu nie wymagają dodatkowego komentarza).

SkillHeal

W tym momencie chciałbym wyjaśnić nazwę bieżącego „dużego” paragrafu (Fireball! Heal!). Otóż, nie zaimplementujemy umiejętności kuli ognia (tytułowego bohatera tej lekcji), a zajmiemy się umiejętnością leczenia ;) (wynika to z faktu, że przy leczeniu nie potrzeba żądnych dodatkowych „fajerwerków” graficznych, których i tak nie pokazuję w poradniku).

Powyższa klasa jest niezwykle prosta. Widzimy na niej poprawne użycie predefiniowanego prologu ( base.Use(taget)) oraz zwiększenie PŻ właściciela umiejętności o bazową ilość uzdrawiania życia wraz z bonusem wynikającym z posiadanego poziomu. To tyle w temacie :P

SkillTree

Przejdźmy teraz do „logicznej” części związanej z drzewkiem umiejętności. Gorąco zachęcam do samodzielnego zapoznania się z poniższym listingiem:

„Logiczne” drzewko umiejętności posiada m.in. ilość dostępnych punktów umiejętności, bazową pulę umiejętności których gracz może się nauczyć, właściciela oraz aktywną umiejętność.

Uwaga! Obecnie sama gra nie nagradza gracza punktami umiejętności: te obecnie są nadane „z góry” jako „hack” z poziomu sceny Unity. Sam system wymaga dodania tego feater’a co zostawiam jako zadanie domowe.

Po uruchomieniu skryptu pula aktywnych umiejętności dzielona jest na 2 części: znanych umiejętności oraz tych do nauczenia. Dla lepszego wizualnego efektu znane umiejętności i nieznane są przypisane do odpowiednich obiektów na scenie jako dzieci.

Sama nauka i użycie umiejętności jest prostym odwołanie się do odpowiednich metod danej umiejętności. Warto zauważyć, że dla UseSkill w obecnej implementacji kontekst użycia umiejętności (cel) jest zawsze ustawiany na null.

Aby móc użyć jakiejś umiejętności, to oprócz jej odblokowania należy ją również aktywować. W tym celu przed ustawieniem umiejętności jako aktywnej najpierw sprawdzamy, czy znajduje się w liście odblokowanych umiejętności w lokalnym drzewie.

SkillTreeVisual

Czas na część wizualną naszego drzewa, która wymaga doszlifowania pod kątem artystycznym – jednakże dla nas jest wystarczająca. Dla lepszego zrozumienia spójrzmy na screen reprezentujący całość już po implementacji (tak, nie jest za piękny ;)):

SkillTreeVisual

Elementy warte uwagi:

  • przyciski „Activate”, „Upgrade” do aktywacji / ulepszania wybranej umiejętności,
  • ramka z właściwościami wybranej umiejętności (nazwa, poziom, koszt ulepszenia),
  • ramka z poznanymi umiejętnościami (tutaj: same umiejętności leczenia, bo tylko taką zaimplementowaliśmy), umiejętność szaro-zielona jest wybrana „do edycji”,
  • ramka z umiejętnościami jeszcze nieznanymi, analogiczna do ramki „Learnt”.

Z racji, że powyższy listing jest bardzo mocno powiązany z Unity, to omówię jedynie ogólnie niektóre fragmenty. Resztę pozostawiam do analizy dla chętnych.

Powyższa metoda służy do włączania/wyłączania focusu przyciski. W przypadku gdy ustawiamy go na true to oprócz aktywowania przycisków aktualizujemy również napisy w ramce z właściwościami umiejętnościami. Po czym w przypadku gdy spełniamy wymagania związane z ulepszeniem umiejętnościami, to aktywujemy przycisk do ulepszenia umiejętności.

Na samym początku focus na przyciski jest wyłączony (ponieważ nie mamy wybranej żadnej umiejętności) oraz aktualizujemy przyciski umiejętności (m.in ustawiamy im z poziomu skryptu odpowiedni onClick).

Wybranie umiejętności odbywa się przez kliknięcie na nią, po czym w pierwszym kroku zmieniamy kolory przycisku, dzięki czemu widzimy która umiejętność została kliknięta. Następnie aktualizujemy aktualnie wybraną umiejętność i aktywujemy focus przycisków (jednocześnie aktualizujmy ramkę właściwości umiejętności).

Reakcja na wciśnięcie klawiszy jest dość proste i ogranicza się głównie do wywołań odpowiednich metod wraz z aktualizacją UI.

Podsumowanie


Jeżeli chodzi o drzewka umiejętności, to już jest wszystko co chciałem Wam przekazać. Wyszło tego całkiem sporo, a jest tego nawet jeszcze więcej – sporo zostało „połknięte” przez to, że nie zajmujemy się Unity. Dlatego gorąco zachęcam wszystkich chętnych do rzucenia okiem na to jak całość wygląda w samym edytorze tego silnika :)

W tym miejscu – tradycyjnie – zachęcam do zagrania w demo, podzieleniem się swoim komentarzem pod tym wpisem, śledzeniem blogiem przez social-media (wszystkie linki są w panelu po prawej stronie) oraz udostępnieniem linku do tego wpisu, blogu wśród swoich znajomych (z góry: wielkie dzięki).

Kolejna, a zarazem ostatnia część już niedługo…

Code ON!