sobota, 22 kwietnia 2017

[DSP2017] 16# Idą po mnie, więc strzelam - ćwiczenia obrony wirtualnej

Gra Survival Shooter okazała się na tyle sympatyczna i wciągająca, że przeszedłem przez ostatnie 2 części jej tutoriala:

Poprzedni stan gry przeniosłem do folderu SurvivalShooter 1 enemy (Unity Tutorial), natomiast to, co powstało z całego tutoriala trafiło do SurvivalShooter (Unity Tutorial). Czego się nauczyłem?

Po pierwsze i najważniejsze  - jak rozmnażać wroga. Teraz podczas grania nie dość, że atakują mnie trzy rodzaje stworów, to przychodzą z różnych miejsc i mogą się namnażać, jeśli nie będę nadążać z ich odstrzałem.

game1

W Prefabs wrzuciłem sobie ZomBear ze skończonej wersji gry, podobnie jak przy Zombunny podpiąłem znane już skrypty EnemyAttack, EnemyHealth i EnemyMovement. Poza innymi dźwiękami, inną liczbą punktów odbieranego mi życia czy ewentualnie inną prędkością poruszania się w NavMeshAgent różnic generalnie nie ma. To taki sam wróg, jak poprzednio, tylko wygląda jak miś zombi w różowym. Dostał też dokładnie taki sam animator – EnemyAC. Zauważmy, że całą konfigurację nie robię na obiekcie na scenie, tylko na prefabrykacie. To konieczność, jeśli chcemy zombi dynamicznie dodawać podczas gry. Aha, ostatnim razem Zombunny z Hierarchy przeciągnąłem do Prefabs czyniąc z niego prefabrykat. Teraz mogę więc dla porządku usunąć obiekt Zombunny z Hierarchy, bo też będzie dodawany dynamicznie.

Win1

No i przyszła pora na grubego zwierza znanego tutaj pod nazwą Hellephant, czyli jakby nieco oryginalny słoń, tyle że przez h –Winking smileJego animacje są inne, ale chcemy mieć dokładnie taką samą logikę animatora co w EnemyAC. Tworzymy więc w Animations Animator Override Controller o nazwie HellephantAOC. W jego polu Controller ustawiamy EnemyAC, a na pola Move, Idle i Death przeciągamy animacje o odpowiadających nazwach z Hellephant w Characters.

Win2

Prefabrykat Hellephant podobnie jak poprzednio wgrywam do Prefabs ze skończonej wersji gry, ustawiam na nim skrypty typowe dla wroga oraz animator na stworzony przed chwilą HellephantAOC. Gruby zwierz ma trzy życia oraz za każdym razem zabiera z mojego życia 20 punktów. Trzeba się go będzie wyjątkowo strzec.

image

Teraz jak wskazać miejsca, w których będą powstawać kolejne zombi? Tworzymy trzy puste obiekty Game o nazwach ZombunnySpawnPoint, ZombearSpawnPoint i HellephantSpawnPoint. W każdym z nich ustawiam inną pozycję i rotację, a także inny kolor etykiety (klikamy w ikonę z lewej od checkboxa w inspektorze). Poniżej przykładowo widzimy ustawienia dla ZombunnySpawnPoint. Ustawienie kolorowej etykiety pomaga w odnalezieniu obiektu na scenie.

Win5

Teraz potrzebujemy czegoś, co by nam cyklicznie i dynamicznie tworzyło obiekty zombi w określonych miejscach sceny. To zadanie spełnia skrypt EnemyManager przypięty do pustego obiektu Game o takiej samej nazwie. Oto jego kod:

public class EnemyManager : MonoBehaviour
{
    public PlayerHealth playerHealth;
    public GameObject enemy;
    public float spawnTime = 3f;
    public Transform[] spawnPoints;


    void Start ()
    {
        InvokeRepeating ("Spawn", spawnTime, spawnTime);
    }


    void Spawn ()
    {
        if(playerHealth.currentHealth <= 0f)
        {
            return;
        }

        int spawnPointIndex = Random.Range (0, spawnPoints.Length);

        Instantiate (enemy, spawnPoints[spawnPointIndex].position, spawnPoints[spawnPointIndex].rotation);
    }
}

Widzimy, że metodą Instantiate dodajemy obiekt na scenę we wskazanym miejscu i określonej rotacji. InvokeRepeating z kolei realizuje zadanie timera w Unity. Co ciekawe w opisywanej sytuacji podpinamy trzy instancje tego samego skryptu EnemyManager do obiektu EnemyManager. Na pole PlayerHealth przeciągamy Player z Hierarchy. Interesujące jest wskazanie wroga. Nie mamy go na scenie, więc na pole Enemy przeciągamy odpowiedni prefabrylat z Prefabs w Assets. Każda instancja EnemyManager może mieć inny okres namnażania (tworzenia i przerwy). Gruby zwierz znany jako Hellephant z racji swojego śmiertelnego dla nas zagrożenia trzy razy wolniej się powiela niż mniejsze i słabsze gatunki zombi.

Win4

Przejdźmy teraz do mniej ważnej, ale potrzebnej rzeczy: ekranu zakończenia gry. Pojawia się on po utracie życia przez gracza zanim nastąpi restart gry.

game2

Aby go mieć do HUDCanvas dodajemy obiekt ScreenFader typu Image oraz pole tekstowe o nazwie GameOverText. Kanał alfa koloru tła obrazka i koloru tekstu ustawiamy na zero.

Win6

W ekranie końca gry najciekawszą rzeczą nie jest on sam, a jego animacja. Przy zaznaczonym obiekcie HUDCanvas w Hierarchy z menu Window wybieramy Animation. Okno Animation dokujemy sobie obok Game, tworzymy w nim animację GameOverClip, którą zapisujemy do folderu Animations w Assets. Przez Add Property wybieramy, co chcemy animować, mogą to być właściwości składowych. Obsługa timeline jest dość intuicyjna. Czerwona linia to punkt czasowy, w którym jesteśmy i który możemy przesuwać. Powinniśmy być w trybie nagrywania, co symbolizuje oznaczenie niektórych przycisków na czerwono. W panelu z właściwościami  możemy edytować wartości dla punktu czasowego i ramki, w której jesteśmy. Ramkę dla danego punktu czasowego i właściwości można dodać za pomocą przycisku nad właściwościami. Można też zaznaczyć wszystkie punkty danej ramki i przesunąć na timeline do innego punktu czasowego. Podobnie można uczynić z grupą ramek. Wydaje się to proste i intuicyjne. Osobiście nasuwają mi się stare wspomnienia odnośnie animacji w Blend dla aplikacji XAML sprzed ładnych paru lat. Aha, w inspektorze GameOverClip wyłączamy zapętlenie (odznaczamy check przy Loop Time).

Win7

Jak sprawić, by po tym jak utracimy życie, animacja GameOverClip została włączona? Otwieramy animator HUDCanvas, widzimy w nim już stan GameOverClip. Tworzymy nowy pusty stan o nazwie Empty i ustawiamy go na domyślny. Tworzymy tranzycję z Empty do GameOverClip. Definiujemy parametr typu trigger o nazwie GameOver. Na właściwościach tranzycji dodajemy warunek na ten trigger i odznaczamy Has Exit Time.

Win8

Na koniec do HUDCanvas przypinamy skrypt GameOverManager o zawartości:

public class GameOverManager : MonoBehaviour
{
    public PlayerHealth playerHealth;


    Animator anim;


    void Awake()
    {
        anim = GetComponent<Animator>();
    }


    void Update()
    {
        if (playerHealth.currentHealth <= 0)
        {
            anim.SetTrigger("GameOver");
        }
    }
}

Dla stworzenia bardziej klimatycznego nastroju kogoś osaczonego przez zombi możemy w BackgroundMusic w AudioSource włączyć opcję Play On Awake, by ciągle od początku nam grało.

Gra się całkiem, całkiem, ale to jedynie tutorial z Unity. Trzeba będzie pomyśleć jak to zadoptować do HoloLens, ale o tym w następnych odcinkach. Niewykluczone, że zgłębię jeszcze coś z Unity, zresztą zobaczamy. A na razie do zobaczenia.

Brak komentarzy: