Be the first to post for 'Patrolling Using Coroutines'!

If you’re reading this, there probably aren’t very many posts yet. But don’t worry, you can be the first! Either create a new post or just reply to this one to say ‘hi’.

Hi @ben! At 11:15 of the video the sound and video cut out.

Hah I was just going to say that as well. Sound cuts out cept for this clicking/turbo control like sound, and it just sort of freezes. I guess that is one way to make sure we at least attempt a challenge lol. Can’t wait to compare what I did to the result. Basically I just offset the x and z values of the patrol path, but that doesn’t seem quite right.

Hey Ben, i have a problem. My enemy is not waiting, after reaching the next waypoint. I doublechecked everything but still having the problem … Here is my code:

    PlayerMovement player = null;
    Character character;

    float distanceToPlayer;

    Character playerCharacter;

    [Header("Patrolling Setup")]

    [SerializeField] WaypointContainer patrolPath;
    [SerializeField] float waitTime = 2f;
    [SerializeField] float patrolSpeed = 0.5f;
    [SerializeField] float waypointTolerance = 2f;
    int nextWaypointIndex;


    enum State { idle, patrolling, attacking, chasing, gettingAttacked }
    State state = State.idle;

    public bool gettingAttacked = false;


    void Start()
    {
        player = FindObjectOfType<PlayerMovement>();
        character = GetComponent<Character>();
    }

    void Update()
    {
        distanceToPlayer = Vector3.Distance(player.transform.position, transform.position);
        WeaponSystem weaponSystem = GetComponent<WeaponSystem>();
        currentWeaponRange = weaponSystem.GetCurrentWeapon().GetMaxAttackRange();
        playerCharacter = player.GetComponent<Character>();

        if (character.characterAlive && playerCharacter.characterAlive)
        {
            CheckForIdle();
            CheckForPatrolling();
            CheckForGettingAttacked();
            CheckForChasing();
            CheckForAttacking();
        }
        else
        {
            StopAllCoroutines();
        }
    }

    private void CheckForIdle()
    {
        if (distanceToPlayer > chaseRadius && state != State.idle) //Idle
        {
            StopAllCoroutines();
            StartCoroutine(GoInIdle());
        }
    }

    private void CheckForPatrolling()
    {
        if (patrolPath != null)
        {
            if (distanceToPlayer > chaseRadius && state != State.patrolling) // Patrolling
            {
                GetComponent<NavMeshAgent>().speed = patrolSpeed;
                StopAllCoroutines();
                StartCoroutine(Patrol());
            }
        }
    }

    private void CheckForGettingAttacked()
    {
        if (gettingAttacked && state != State.gettingAttacked) // Getting Attacked
        {
            GetComponent<NavMeshAgent>().speed = chaseSpeed;
            StopAllCoroutines();
            StartCoroutine(ReactToAttack());
        }
    }

    private void CheckForChasing()
    {
        if (distanceToPlayer <= chaseRadius && state != State.chasing) //Chasing
        {
            GetComponent<NavMeshAgent>().speed = chaseSpeed;
            StopAllCoroutines();
            StartCoroutine(ChasePlayer());
        }
    }

    private void CheckForAttacking()
    {
        if (distanceToPlayer <= currentWeaponRange && state != State.attacking) //Attacking
        {
            StopAllCoroutines();
            StartCoroutine(AttackPlayer());
        }
    }

    IEnumerator GoInIdle()
    {
        state = State.idle;
        yield return new WaitForEndOfFrame();
    }

    IEnumerator Patrol()
    {
        state = State.patrolling;

        while (true)
        {
            Vector3 nextWaypointPos = patrolPath.transform.GetChild(nextWaypointIndex).position;
            character.SetDestination(nextWaypointPos);
            CycleWaypointWhenClose(nextWaypointPos);
            yield return new WaitForSeconds(waitTime);
        }
    }

    IEnumerator ReactToAttack()
    {
        if (gettingAttacked)
        {
            state = State.gettingAttacked;
            character.SetDestination(player.transform.position);
            yield return new WaitForEndOfFrame();
        }
    }

    IEnumerator ChasePlayer()
    {
        state = State.chasing;

        while (distanceToPlayer <= chaseRadius)
        {
            character.SetDestination(player.transform.position);
            yield return new WaitForEndOfFrame();
        }
    }

    IEnumerator AttackPlayer()
    {
        state = State.attacking;

        while (distanceToPlayer <= currentWeaponRange)
        {
            WeaponSystem weaponSystem = GetComponent<WeaponSystem>();
            weaponSystem.target = player.gameObject;
            weaponSystem.AttackTarget(player.gameObject);
            yield return new WaitForEndOfFrame();
        }
    }

    void CycleWaypointWhenClose(Vector3 nextWaypointPos)
    {
        if(Vector3.Distance(transform.position, nextWaypointPos) <= waypointTolerance)
        {
            nextWaypointIndex = (nextWaypointIndex + 1) % patrolPath.transform.childCount;
        }
    }

    void OnDrawGizmos()
    {
        Gizmos.color = new Color(255f, 0, 0, .5f);
        Gizmos.DrawWireSphere(transform.position, currentWeaponRange);

        Gizmos.color = new Color(0, 0, 255, .5f);
        Gizmos.DrawWireSphere(transform.position, chaseRadius);
    }
}

}

It took me a while, but i was able to fix it :slight_smile: Somehow, my CheckForIdle() killed the waitTime. I still dont really get it, but now its working.

Check your logic in CheckForIdle
If an Enemy is far from the Player, each frame it is first going to Idle state and kills all Coroutins.
Because of this Patrol() is not waiting long enough, it is killed next frame

Well yeah… that is actually unbelievable obvious. Thanks! Was a long day yesterday :d

I’m trying to change the patrol speed for my enemies as running between waypoints doesn’t feel natural. However, changing the navMeshAgent.Speed doesn’t seem to alter the character speed unless I drop it to 0.1f at which point the character virtually stands still. If I increment above 0.1f the character starts running again regardless of the value.
Am I missing something?

Seems to be the animation affecting the speed so think I just need to swap out the run animation for a walk animation when patrolling. Nice challenge to be cracking on with.

Just to confirm I’ve checked that the video plays OK now, and it does. Thanks for raising this.

haha unity kept crashing on me so I upgraded while stuck on the infinite loop.

Code seems to be working fine in 18.2 BTW

My enemies do not wait at the patrol points. They just run onto the next way point immediately. The variable “waypointdwelltime” has no effect. Here is my code:

IEnumerator Patrol()
{
state = State.patrolling;

            while (patrolPath != null)
            {
                Vector3 nextWayPointPos = patrolPath.transform.GetChild(nextWayPointIndex).position;
                character.SetDestination(nextWayPointPos);
                CycleWayPointWhenClose(nextWayPointPos);
                yield return new WaitForSeconds(waypointDwellTime);//wait time at waypoint make this a random range

            }

Privacy & Terms