Search code examples
c#unity-game-enginenavmesh

Problems making anim.SetBool work with NavMeshAgent


I am working on setting up a simple little AI for a character in my game. For some reason I am having major problems getting animations to play while using the NavMeshAgent and I do not understand why. This is a waypoint system that I pooled off Unity API, and I can't even seem to get this working. I am hoping that if someone can give me some input on this if might clear some other things up as well. I am really lost here and would appreciate any input. The code on the bottom all works until it hits Patrol and then the player moves without animating. I feel like there is something more i need to know about navmesh's maybe. Or a lot more I need to know about programming in general.

    e// Patrol.cs
using UnityEngine;
using UnityEngine.AI;
using System.Collections;


public class Enemy_Patrol : MonoBehaviour
{
    public Transform[] points;
    public Animator anim; 

    private int destPoint = 0;
    private NavMeshAgent agent;

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        anim = GetComponent<Animator>(); 

        // Disabling auto-braking allows for continuous movement
        // between points (ie, the agent doesn't slow down as it
        // approaches a destination point).
        agent.autoBraking = false;

        GotoNextPoint();
    }


    void GotoNextPoint()
    {
        // Returns if no points have been set up
        if (points.Length == 0)
            return;

        // Set the agent to go to the currently selected destination.
        agent.destination = points[destPoint].position;
        anim.SetBool("WalkForwards", true);
        anim.SetBool("IsIdle", false);
        // Choose the next point in the array as the destination,
        // cycling to the start if necessary.
        destPoint = (destPoint + 1) % points.Length;
    }


    void Update()
    {
        // Choose the next destination point when the agent gets
        // close to the current one.
        if (!agent.pathPending && agent.remainingDistance < 0.5f)

        GotoNextPoint();
    }
}


// Code i wrote to handle following chasing etc.

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

public class AI_Tester : MonoBehaviour
{
    private float patrolSpeed = .2f;
    public NavMeshAgent agent;
    public GameObject[] waypoints;
    private int waypointInd = 0;
    public Transform player;
    static Animator anim;
    public SealForce_DestructableObjects destructableObjects;
    public Transform enemy;


    // Use this for initialization
    void Start()
    {
        anim = GetComponentInChildren<Animator>();
        agent = GetComponent<NavMeshAgent>();
        destructableObjects = GetComponent<SealForce_DestructableObjects>();
        waypoints = GameObject.FindGameObjectsWithTag("waypoints");
        waypointInd = Random.Range(0, waypoints.Length); 
    }


    void AIMovements()
    {
        if (Vector3.Distance(player.position, this.transform.position) <= 30)
        {
            Vector3 direction = player.position - this.transform.position;
            direction.y = 0;

            this.transform.rotation = Quaternion.Slerp(this.transform.rotation,
                                        Quaternion.LookRotation(direction), 0.1f);

            if (direction.magnitude > 15)
            {
                MoveToFiringRange();
            }


            if (direction.magnitude <= 15)
            {
                AttackPlayer();
            }
        }
        else if (Vector3.Distance(player.position, this.transform.position) > 30)
        {
            WaitingOnAction();
        }
    }
    public void Update()
    {
        AIMovements();
    }
    public void AttackPlayer()
    {
        anim.SetTrigger("IsAttacking");
        anim.SetBool("IsIdle", false);
        anim.SetBool("RunForwards", false);
    }
    public void MoveToFiringRange()
    {
        this.transform.Translate(0, 0, 0.04f);
        anim.SetBool("RunForwards", true);
        anim.SetBool("IsIdle", false);
        anim.ResetTrigger("IsAttacking");
    }
    public void WaitingOnAction()
    {
        anim.SetBool("IsIdle", true);
        anim.SetBool("RunForwards", false); 

        StartCoroutine("BackToPatrol"); 
    }

//program works fine all the up to here. The only thing wrong with patrol is no animation. 

    IEnumerator BackToPatrol()
    {
        yield return new WaitForSeconds(5);
        anim.SetBool("IsIdle", false);

        Patrol(); 
    }
    public void Patrol()
    {

        Debug.Log("In Patrol"); 
        agent.speed = patrolSpeed;
        if (Vector3.Distance(this.transform.position, waypoints[waypointInd].transform.position) >= 2)
        {
            agent.SetDestination(waypoints[waypointInd].transform.position);
            anim.SetBool("WalkForwards", true); 
        }
        if (Vector3.Distance(this.transform.position, waypoints[waypointInd].transform.position) <= 2)
        {
            waypointInd += 1;
            if (waypointInd > waypoints.Length)
            {
                waypointInd = 0;

            }

        }
    }
}

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

public class AI_Tester : MonoBehaviour
{
    public bool isPatrolling; 
    private float patrolSpeed = 1.5f;
    public NavMeshAgent agent;
    public GameObject[] waypoints;
    private int waypointInd = 0;
    public Transform player;
    static Animator anim;
    //public SealForce_DestructableObjects destructableObjects;
    //public Transform enemy;


    // Use this for initialization
    void Start()
    {
        anim = GetComponentInChildren<Animator>();
        agent = GetComponent<NavMeshAgent>();
        //destructableObjects = GetComponent<SealForce_DestructableObjects>();
        waypoints = GameObject.FindGameObjectsWithTag("waypoints");
        waypointInd = Random.Range(0, waypoints.Length);

    }


    void AIMovements()
    {
        if (Vector3.Distance(player.position, this.transform.position) <= 30)
        { 
            Vector3 direction = player.position - this.transform.position;
            direction.y = 0;

            this.transform.rotation = Quaternion.Slerp(this.transform.rotation,
                                        Quaternion.LookRotation(direction), 0.1f);

            if (direction.magnitude > 15)
            {
                //StopCoroutine("BackToPatrol");
                StopCoroutine("Patrol");
                isPatrolling = false; 
                MoveToFiringRange();
            }


            if (direction.magnitude <= 15)
            {
                //StopCoroutine("BackToPatrol");
                StopCoroutine("Patrol");
                isPatrolling = false;  
                AttackPlayer();
            }
        }
        else if (Vector3.Distance(player.position, this.transform.position) > 30 && !isPatrolling)
        {
            //StopCoroutine("BackToPatrol");
            StopCoroutine("Patrol");
            WaitingOnAction();
        }
    }
    public void Update()
    {  
        AIMovements();  
    }
    public void AttackPlayer()
    {
        anim.SetTrigger("IsAttacking");
        anim.SetBool("IsIdle", false);
        anim.SetBool("RunForwards", false);
    }
    public void MoveToFiringRange()
    { 
        this.transform.Translate(0, 0, 0.04f);
        anim.SetBool("RunForwards", true);
        anim.SetBool("IsIdle", false);
        anim.ResetTrigger("IsAttacking");
    }
    public void WaitingOnAction()
    {
        anim.SetBool("IsIdle", true);
        anim.SetBool("RunForwards", false); 

        StartCoroutine("BackToPatrol"); 

    }
    IEnumerator BackToPatrol()
    {
        isPatrolling = true;
        yield return new WaitForSeconds(5);
        anim.SetBool("IsIdle", false); 

        yield return StartCoroutine ("Patrol");
        isPatrolling = false;
    }
    IEnumerator Patrol()
    {
        Debug.Log("In Patrol");
        agent.speed = patrolSpeed;
        agent.SetDestination(waypoints[waypointInd].transform.position);
        anim.SetBool("WalkForwards", true);

        while (Vector3.Distance(this.transform.position, waypoints[waypointInd].transform.position) >= 2 && !isPatrolling)
        {
            yield return null;
        }

        waypointInd++;

        if (waypointInd >= waypoints.Length) waypointInd = 0;



    }


   /* public void  Patrol()
    {
        Debug.Log("In Patrol");
        agent.speed = patrolSpeed;

        if (Vector3.Distance(this.transform.position, waypoints[waypointInd].transform.position) >= 2)
        {
            agent.SetDestination(waypoints[waypointInd].transform.position);
            anim.SetBool("IsIdle", false); 
            anim.SetBool("WalkForwards", false);
        }
        if (Vector3.Distance(this.transform.position, waypoints[waypointInd].transform.position) <= 2)
        {
            waypointInd += 1;
            if (waypointInd > waypoints.Length)
            {
                waypointInd = 0;*/



}

Solution

  • You are calling WaitingOnAction on Update every frame, which will set the animator's IsIdle back to true and start a new BackToPatrol coroutine. This should not happen. Try to check if the character has reached it's destination before calling WaitingOnAction again. Something like:

    else if (Vector3.Distance(player.position, this.transform.position) > 30 && !isPatrolling)
    {
        WaitingOnAction();
    }
    

    And in your Coroutine:

    IEnumerator BackToPatrol()
    {
        isPatrolling = true;
        yield return new WaitForSeconds(5);
        anim.SetBool("IsIdle", false);
    
        yield return StartCoroutine("Patrol"); 
        isPatrolling = false;
    }
    
    IEnumerator Patrol()
    {
        Debug.Log("In Patrol"); 
        agent.speed = patrolSpeed;
        agent.SetDestination(waypoints[waypointInd].transform.position);
        anim.SetBool("WalkForwards", true);
        agent.isStopped = false;
    
        while (Vector3.Distance(this.transform.position, waypoints[waypointInd].transform.position) >= 2 && isPatrolling)
        {
            yield return null;
        }
    
        agent.isStopped = true;
        anim.SetBool("WalkForwards", false);
        waypointInd++;
    
        if(waypointInd >= waypoints.Length) waypointInd = 0;
    }
    

    I didn't test it, but something like this should work.