Search Unity

Using a NavMeshAgent with a CharacterController

Discussion in 'Scripting' started by ChazBass, Apr 18, 2017.

  1. ChazBass

    ChazBass

    Joined:
    Jul 14, 2013
    Posts:
    120
    Since the Unity docs, Unity Answers, and the wild are a little vague on this, I would like to share how to get a NavMeshAgent and CharacterController to play nice together on an NPC (tested on 5.6). This solution allows the agent to still avoid all defined obstacles and other NPC's while also respecting other character controllers (such as the player) and any game geometry with colliders on it.

    Code (CSharp):
    1.     public class Enemy : MonoBehaviour {
    2.  
    3.         public Transform _playerTrans;
    4.         public float _speed = 2;
    5.         public float _turnSpeed = 3;
    6.  
    7.         private NavMeshAgent _agent;
    8.         private Vector3 _desVelocity;
    9.         private CharacterController _charControl;
    10.  
    11.         void Start() {
    12.  
    13.             this._agent = this.gameObject.GetComponent<NavMeshAgent>();
    14.             this._charControl = this.gameObject.GetComponent<CharacterController>();
    15.  
    16.             this._agent.destination = this._playerTrans.position;
    17.  
    18.             return;
    19.         }
    20.  
    21.         void Update() {
    22.  
    23.             Vector3 lookPos;
    24.             Quaternion targetRot;
    25.  
    26.             this._agent.destination = this._playerTrans.position;
    27.             this._desVelocity = this._agent.desiredVelocity;
    28.  
    29.             this._agent.updatePosition = false;
    30.             this._agent.updateRotation = false;
    31.  
    32.             lookPos = this._playerTrans.position - this.transform.position;
    33.             lookPos.y = 0;
    34.             targetRot = Quaternion.LookRotation(lookPos);
    35.             this.transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, Time.deltaTime * this._turnSpeed);
    36.  
    37.             this._charControl.Move(this._desVelocity.normalized * this._speed * Time.deltaTime);
    38.  
    39.             this._agent.velocity = this._charControl.velocity;
    40.  
    41.             return;
    42.         }
    43.     }
    The key to making sure they play nice is this:

    Code (CSharp):
    1. this._agent.velocity = this._charControl.velocity;
    Thanks to AngryAnt for that little gem in post I found. If you do not update the nav mesh agent with the velocity of the character controller post move, unpredictable behavior results.
     
    Richardm1985 likes this.
  2. Rienhl

    Rienhl

    Joined:
    Nov 14, 2013
    Posts:
    41
    Thanks man! I was exactly looking for something like this!

    Would this also work with a player controller? I mean, can I control my player character with a custom character controller and still use a nav mesh agent to know where it can navigate to?
     
  3. ChazBass

    ChazBass

    Joined:
    Jul 14, 2013
    Posts:
    120
    Sure, it should work with any controller, be it a rigidbody based controller or a custom controller, as long as you update the agent with the velocity the controller sets. That is the critical step to keep the agent functioning correctly.
     
    Rienhl likes this.
  4. Rienhl

    Rienhl

    Joined:
    Nov 14, 2013
    Posts:
    41
  5. AndyMartin458

    AndyMartin458

    Joined:
    Jul 15, 2012
    Posts:
    53
    If all you want is for the NavMeshAgent to not update position ever, then you can set that in Awake/Start instead of Update.


    Code (CSharp):
    1. void Start()
    2. {
    3.         var navMeshAgent = this.GetComponent<NavMeshAgent>();
    4.         navMeshAgent.updatePosition = false;
    5. }
     
  6. olivierus

    olivierus

    Joined:
    Nov 26, 2010
    Posts:
    88
    This doesn't seem to work for me.
    My AI stresses out and flies away.
    I use unity 2017.

    Has someone tested this in 2017?