wtorek, 3 maja 2016

Wizualizacja umiejętności

Aby rozgrywka była dla gracza czytelna, gra musi wizualizować wszystkie istotne wydarzenia, które dzieją się w trakcie gry. Dzięki efektom graficznym gracz jest w stanie łatwo określić jakie czynności wykonują przeciwnicy. Takie efekty nie muszą wyglądać widowiskowo, szczególnie gdy miałoby to zmniejszyć czytelność rozgrywki - wszystko to co dzieje się na ekranie powinno być dla gracza jednoznaczne.

Przygotowywanie obiektu


Moim celem jest stworzenie efektu, który reprezentowałby prostą umiejętność, która redukuje wartość żetonów na określonych polach. Będzie to nieskomplikowana sześcienna poświata, której intensywność rośnie na początku trwania efektu, a po chwili maleje, doprowadzając do końca efektu.

Najpierw tworzymy na scenie pusty GameObject, do którego doczepimy 4 quady (dzięki czemu pozycję, rotację i skalę tych quadów będzie można łatwo modyfikować przekształcając pusty GameObject). Quady te będą bocznymi ścianami efektu i należy je ustawić tak, aby reprezentowały boczne ściany sześciany. Następnie importujemy do projektu teksturę w formacie png, która przedstawia przejście białego koloru w przeźroczystość. Zmiana koloru materiału z poziomu skryptu sprawia, że wartości rgb pliku są mnożone przez nową wartość, czyli gdybyśmy kolor naturalnie czerwonej tekstury (r = 1, g = 0, b = 0) ustawili na niebieski (r = 0, g = 0, b = 1), to ostatecznie otrzymalibyśmy czarną teksturę (r = 0, g = 0, b = 0). Dlatego moim zdaniem w przypadku jednolitych tekstur warto jest stosować kolor biały, który potem można przemienić w dowolny inny kolor bez konieczności dodawania kolejnych tekstur. Wyjątkiem od tej reguły są m.in. sytuacje, w których wybrany typ shaderu nie pozwala na modyfikację koloru materiału. Zaimportowaną teksturę przypisujemy do quadów i ustawiamy jej kolor na czerwony.

Kolejną czynnością jest, zmienienie shadera materiału naszego efektu na shader "Sprites/Default".

Jeśli się przyjrzymy, to zauważymy, że na górnej krawędzi naszego efektu znajduje się wąska linia, mimo iż tamta krawędź powinna być przezroczysta:


Niby linia jest stosunkowo trudna do zauważenia, ale wypada się jej pozbyć. Jej istnienie jest spowodowana tym, że tekstura jest w pewnym sensie zapętlona i rozmyta, przez co widać fragment przeciwległej krawędzi tekstury. Aby tego uniknąć należy wybrać użytą teksturę i ustawić w inspektorze wartość wrap mode z wartości repeat na clamp:


Następnie z quadów usuwamy collidery, aby nie przeszkadzały nam w grze i wszystko to wrzucamy w prefab, który umieszczamy w folderze Resources.

Skrypt


Chcemy aby nasz efekt pojawiał się w momencie aktywacji umiejętności żetonów, oraz wysuwał się spod pól znajdujących się na planszy, które zostały objęte działaniem tej umiejętności. Aby to ułatwić, podczas tworzenia instancji tego efektu graficznego oznaczmy pole jako parent dla tego efektu., Dzięki temu przykładowo po ustaleniu lokalnej pozycji na (0, 0, 0) nasz prefab będzie się znajdował dokładnie w miejscu pola. Warto się upewnić, że rotacja poszczególnych quadów w prefabie będzie odpowiadała rotacji którą chcemy uzyskać, dzięki czemu nie będziemy już musieli ustawiać jej za pomocą skryptu.

Tworzymy nowy skrypt i deklarujemy w nim 3 zmienne:

 public bool AutoDestroy;
 float Timer;

 float TimeScale = 0.5f;

Pierwsza zmienna będzie decydowała o tym, czy obiekt ma być automatycznie niszczony po jakimś czasie. Nieautomatyczne niszczenie obiektu mogłoby być przydatne gdybyśmy chcieli aby efekt pojawiał się gdy gracz najedzie myszką na pole w celu sprawdzenia na jakie pola wpłynie umiejętność - wtedy efekt powinien znikać dopiero po przesunięciu kursora poza pole. Z kolei automatyczne niszczenie efektu byłoby pożyteczne po normalnym użyciu umiejętności. Druga zmienna będzie przechowywać informację o tym, jak długo obiekt istnieje, a trzecia zmienna jak długo ma trwać wynurzanie się się efektu.

Kolejną rzeczą na której nam zależy jest dodanie funkcji Start, która posłuży nam do ustawienia odpowiedniej pozycji obiektu:

 void Start () {
  transform.localPosition = new Vector3 (0, 0, 1);

 }

Kamera w grze jest ustawiona w taki sposób, że zwiększenie wartości współrzędnej Z powoduje oddalenie się obiektu od kamery, czyli efekt będzie się znajdował pod planszą w momencie przypisania skryptu.

I następnie dodajemy główny fragment kodu, który ma być wykonywany co klatkę gry

 void Update () {
  Timer += Time.deltaTime;
  if (Timer < TimeScale) {
   transform.localPosition = new Vector3 (0, 0, 2 * (TimeScale - Timer));
  } else if (AutoDestroy) {
   if (Timer < 2 * TimeScale) {
    transform.localPosition = new Vector3 (0, 0, 2 * (Timer - TimeScale));
   } else {
    Destroy (gameObject);
   }
  } else {
   transform.localPosition = new Vector3 (0, 0, 0);
   Destroy (GetComponent<EvadingScript> ());
  }

 }

Timer co klatkę zwiększa się o czas odstępu między tą a poprzednią klatką gry, czyli mierzy czas istnienia obiektu. Jeśli timer jest mniejszy niż czas w trakcie którego obiekt ma się przybliżać do kamery, to jego pozycja na osi Z maleje. Potem skrypt sprawdza, czy obiekt ma być automatycznie zniszczony - jeśli tak, to zaczyna się chować, w przeciwnym razie jego pozycji zostanie przypisany wektor (0, 0, 0). Przypisanie tej pozycji jest ważne, ponieważ odstępy pomiędzy klatkami mogą mieć różny odstęp i gdyby liczba klatek na sekundę była bardzo niska, to mogłoby się zdarzyć, że pozycja na osi Z byłaby równa np. 0.57, przez co efekt byłby ledwo widoczna, mimo iż w tym momencie powinien być widoczny całkowicie. Dodatkowo jeśli czas zostanie przekroczony, to skrypt kasuje sam siebie, ponieważ nie chcemy, aby program niepotrzebnie co klatkę wykonywał czynności umieszczona przez nas w tym skrypcie. Gdy nasza zmienna AutoDestroy jest ustalona jako true, to program zamiast tego co klatkę zwiększa wartość wektora pozycji na osi Z, co powoduje chowanie się obiektu. Po upłynięciu odpowiedniej ilości czasu obiekt do którego przypisany jest skrypt kasuje sam siebie wraz ze swoimi komponentami.

W podobny sposób możemy utworzyć poziomy odpowiednik tej umiejętności, który nie będzie się wysuwał spod ziemi, lecz początkowo będzie przeźroczysty i będzie stawał się bardziej czerwony w trakcie wysuwania się efektu, co w połączeniu z drugim efektem sprawi wrażenie, że efekt nie składa się z kilku ścian, lecz jest bryłą:


Brak komentarzy:

Prześlij komentarz