Coroutines to run the enemies at my hideout

This post is especially dedicated to GroZZleR, who posted in another forum:

Look @GroZZleR ! I’m using coroutines to run my enemy hideout agents, a new level and game mode coming soon to my ATGM game!

Here’s the code, just so you can see I’m not COMPLETELY allergic to coroutines.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

// runs ALL the enemies at this hideout

public class HideoutBehaviours : MonoBehaviour
{
    public NavMeshAgent EnemyPrefab;

    // simulator-level "I am alarmed" status:
    // tripped when there is an explosion or dead body, for example
    public bool alarmed;

    [Header( "Parent object of all spawns / patrol points")]
    public GameObject Spawns;
    public GameObject Patrols;

    Transform FindRandomSpawn()
    {
        int n = Random.Range( 0, Spawns.transform.childCount);

        var tr = Spawns.transform.GetChild( n);

        return tr;
    }

    Transform FindRandomPatrol()
    {
        int n = Random.Range( 0, Patrols.transform.childCount);

        var tr = Patrols.transform.GetChild( n);

        return tr;
    }

    void Start ()
    {
        StartCoroutine( RunEnemies());
    }

    // marker used in GenericMarker tag script
    const string s_OurEnemies = "ztestonly_enemy_hideout_1_enemies";

    IEnumerator RunEnemies()
    {
        if (EnemyPrefab.gameObject.activeInHierarchy)
        {
            EnemyPrefab.gameObject.SetActive(false);
        }

        while( true)
        {
            yield return new WaitForSeconds( Random.Range( 1.0f, 3.0f));

            if (alarmed)
            {
                // extra wait between alarm checks
                yield return new WaitForSeconds( Random.Range( 2.0f, 4.0f));

                // do nothing, everybody is skedaddling
                var markers = FindObjectsOfType<GenericMarker>();
                bool RemainAlarmed = false;

                foreach( var marker in markers)
                {
                    if (marker.Identity == s_OurEnemies)
                    {
                        RemainAlarmed = true;
                    }
                }

                // once everbody didis outa here and some time passes, chill
                if (!RemainAlarmed)
                {
                    yield return new WaitForSeconds( Random.Range( 2.0f, 4.0f));
                    alarmed = false;
                }
            }
            else
            {
                var dude = Instantiate<NavMeshAgent>( EnemyPrefab);
                dude.transform.position = FindRandomSpawn().position;
                dude.gameObject.SetActive( true);

                dude.gameObject.AddComponent<GenericMarker>().Identity = s_OurEnemies;

                StartCoroutine( RunMeJohnny( dude));
            }
        }
    }

    IEnumerator UpdateSpeed( NavMeshAgent agent)
    {
        float NormalSpeed = Random.Range( 2.0f, 4.0f);

        float AlarmedSpeed = Random.Range( 10.0f, 14.0f);

        while(true)
        {
            if (alarmed)
            {
                agent.speed = AlarmedSpeed;
            }
            else
            {
                agent.speed = NormalSpeed;
            }

            // not everybody instantly alarms!
            yield return Random.Range( 0.5f, 1.0f);

            if (!agent) yield break;
        }
    }

    IEnumerator RunMeJohnny( NavMeshAgent agent)
    {
        float lifeTime = Random.Range( 20.0f, 50.0f);
        bool departing = false;

        StartCoroutine( UpdateSpeed( agent));

        while( true)
        {
            // is it reason for me to go away?
            if (alarmed)
            {
                departing = true;
            }

            // is it time for me to go away?
            if (lifeTime < 0)
            {
                departing = true;
            }

            Vector3 destination = FindRandomPatrol().position;

            if (departing)
            {
                destination = FindRandomSpawn().position;
            }

            agent.SetDestination( destination);

            while( true)
            {
                lifeTime -= Time.deltaTime;

                if (Vector3.Distance( agent.transform.position, destination) < 1)
                {
                    break;
                }

                yield return null;

                if (!agent) yield break;

                // alarm has happened, abandon our patrol
                if (alarmed && !departing)
                {
                    break;
                }
            }

            if (departing)
            {
                Destroy(agent.gameObject);
                yield break;
            }

            yield return null;

            if (!agent) yield break;
        }
    }
}
1 Like

I imagine this is what a proud papa seeing his child walk for the first time feels like.

1 Like