Interakce s hráčem. Log #9 (C#)
14.03.2017

                Ve hře budou tři typy entit. Neutrální, agresivní a neutrálně agresivní. Neutrální, nebude na hráče útočit, dokud hráč nezaútočí první, pak s ním bude bojovat dokud hráč nezmizí z dohledu. Agresivní zaútočí na hráče hned jak bude postava hráče v dohledu, a nepřestane dokud hráč opět neuteče mimo dohled.  A neutrálně agresivní, bude mít dva stavy. V prvním, když bude hráč jen na dohled, tak hráče varuje, a když se hráč přiblíží tak entita zaútočí. Za entitu ve hře považuji jakoukoliv živou postavu. Tedy i hráč, ale hráč je jedinečná entita, který má jiné chování než všechny ostatní. Entity zase obecně spadají pod Objekty. 

                A jak jsem řekl dříve, každý objekt bude mít svůj rádius, ale je zbytečné tenhle rádius psát v každém skriptu, proto vytvořím nadřazenou třídu "BasicObject" ve "Scripts" která bude dědit z MonoBehavior a kterýkoliv objekt bude potomek téhle třídy. Třída "BasicObject" bude mít zatím jedinou property StoppingDistance. Vytvořím skript "Entity" ("Scripts" > "Entities") Ve třídě Entity přepíšu dědičnost na "BasicObject". Pro rozlišení typu entity udělám enumerator EntityType.

 

public enum EntityType
{
	Neutral,    //0
	Aggresive,  //1
	NeutralAggresive, //2
}

 

                Entita musí samozřejmě mít přístup ke svému kontroleru, aby věděl co má právě dělat. Interakce zasahuje totiž do patrolování. Pokud bude entita útočit, přestane s patrolováním, ale v případě, že hráč uteče mimo dohled (rádius) vrátí se NPC k patrole. U neutrálně agresivní entity, při prvotním kontaktu NPC jen pozastaví patrolování, pokud hráč ustoupí, vrátí se zase zpět k patrole.

                Každá jednotlivá entita, jako třeba myš, imp nebo jakákoliv z kreatur bude mít vlastní typ entity. Tenhle typ budu pak nastavovat v konstruktoru jednotlivé kreatury, stejně jako atributy životy, sílu a podobně. V Update() entity přes switch zjistím jaký je entita typ a podle toho se bude chovat. V případě typu Neutral musím nejdřív zjistit, jestli hráč na kreaturu zaútočil. Jednoduše funkcí OnMoseOver() a TookDamage() kterou bude volat PlayerController při dosažení kreatury (v téhle fázi neimplementováno zatím).

 

void OnMouseOver()
{
     if (Input.GetMouseButton(1))
     {
        selected = true;
     }
}

public void TakeDamage(float damage)
{
     tookDamage = true;
}

 

                Pokud jsou obě podmínky splněny zastavím patrolování. V případě neutrálního typu entity se kreatura po útoku "naštve", to se projeví tak, že hráč bude muset překonat dvojnásobek rádiusu kreatury než se jí dostane z dohledu. Pak už jen kontroluji jestli je hráč v dohledu (EntityRadius) kreatury. Pokud ano bude se entita pohybovat směrem k hráči, pokud ne vrátí se zpět k patrole. Do EntityController je tedy potřeba doimplementovat toto chování. První funkci MoveTowardsPlayer() potom funkci ResumePatrol().

 

public void MoveTowardsPlayer()
{
    nma.stoppingDistance = 2f;
    nma.SetDestination(player.position);
    nma.Resume();
    movingTowardsPlayer = true;
    playerReached = false;
    playerInteraction = true;
}

public void ResumePatrol()
{
    movingTowardsPlayer = false;
    playerInteraction = false;
    nma.stoppingDistance = 0.1f;
    EntityToWaypointDistance();
    StartPatrol(waypoints[waypointIndex]);
}

 

Boolean proměnné jsou jen pro kontrolu na rozlišení interakce s hráčem a samostatného patrolovaní v Update() funkci. Chování MoveTowardsPlayer() je v zásadě stejné jako při startu patroly. Jen s tím že prozatím je potřeba nastavit nma.stoppingDistance aby kreatura (vůbec) zastavila v dostatečné vzdálenosti. ResumePatrol() jen zruší veškerou interakci s hráčem a vrátí se k patrole. To je vše k nastavení EntityControlleru.

Pro agresivní chování je postup stejný jako pro neutrální chování, při splnění obou podmínek. Pro neutrálně agresivní chování je potřeba prohodit podmínky, tedy první reakce je když hráč vstoupí do prvního rádiusu, to entita svoji patrolu zastaví a "varuje" hráče. Pokud hráč vstoupí do "agresivního rádiusu", pak entita zaútočí a její EntityRadius nabyde velikosti "varovného radiusu". Celý kód chování vypadá následovně.

 

 new protected void Update()
    {
        base.Update();

        if (ec != null)
        {
            switch (Type)
            {
                case EntityType.Neutral:                       //Neutral Behaviour
                    if (selected)
                    {
                        if (tookDamage)
                        {
                            ec.StopPatrol();

                            if (!largedRadius)
                            {
                                EntityRadius *= 2;
                                largedRadius = true;
                            }

                            if (ec.IsPlayerInRange(EntityRadius))
                            {
                                if (ec.IsPlayerReached())
                                {
                                    //Attack
                                }
                                else
                                {
                                    ec.MoveTowardsPlayer();
                                }
                            }
                            else
                            {
                                ec.ResumePatrol();
                            }
                        }
                    }
                    break;
                case EntityType.Aggresive:                    //Agressive Behaviour
                    if (ec.IsPlayerInRange(EntityRadius))
                    {
                        ec.StopPatrol();
                        if (ec.IsPlayerReached())
                        {
                            //Attack
                        }
                        else
                        {
                            ec.MoveTowardsPlayer();
                        }
                    }
                    else if (!ec.IsPatrolPending())
                    {
                        ec.ResumePatrol();
                    }
                    break;
                case EntityType.NeutralAggresive:            //NeutralAggressive Behaviour
                    if (ec.IsPlayerInRange(NeutralAgressiveRadius))
                    {
                        ec.StopPatrol();
                        if (ec.IsPlayerReached())
                        {
                            //Attack
                        }
                        else if(ec.IsPlayerInRange(EntityRadius))
                        {
                            EntityRadius = NeutralAgressiveRadius;
                            Type = EntityType.Aggresive;
                        }
                    }
                    else if (!ec.IsPatrolPending())
                    {
                        ec.ResumePatrol();
                    }
                    break;
            }
        }
    }

 

Pro funkčnost je potřeba mít také EntityController 

 

new protected void Start()
{
    ec = GetComponent<EntityController>();
    transform.tag = "Entity";

}

 

 

Jak je vidět výše, entity jsou defaultně zelené, ve stavu kdy hráč vstoupil do EntityRadius, se změní barva na červenou, pokud je hráč pouze v NeutralAgressiveRadius, pak je barva žlutá. Jsou to ekvivalenty barev pro akci StopPatrol() = žlutá a MoveTowardsPlayer() - červená. Cyan barva reprezentuje entitu při návratu k patrole (ReturnPatrol()). To je vše k patrolování a interakci.