My NavMeshAgent does not get close enough to Player

public class EnemyChasingState : EnemyBaseState
{
    private readonly int LocomotionHash = Animator.StringToHash("Locomotion");
    private readonly int SpeedHash = Animator.StringToHash("Speed");

    private const float CrossFadeDuration = 0.1f;
    private const float AnimatorDampTime = 0.1f;

    public EnemyChasingState(EnemyStateMachine stateMachine) : base(stateMachine) { }

    public override void Enter()
    {
        stateMachine.Animator.CrossFadeInFixedTime(LocomotionHash, CrossFadeDuration);
    }

    public override void Tick(float deltaTime)
    {
        if (!IsInChaseRange())
        {
            stateMachine.SwitchState(new EnemyIdleState(stateMachine));
            return;
        }
        else
        {
            MoveToPlayer(deltaTime);

            FacePlayer();

            stateMachine.Animator.SetFloat(SpeedHash,
                stateMachine.Controller.velocity.normalized.magnitude, AnimatorDampTime, deltaTime);
        }
    }

    public override void Exit()
    {
        if(stateMachine.Agent.isOnNavMesh)
        {
            stateMachine.Agent.ResetPath();
        }

        stateMachine.Agent.velocity = Vector3.zero;
    }

    private void MoveToPlayer(float deltaTime)
    {
        if (stateMachine.Agent.isOnNavMesh)
        {
            if (Vector3.Distance(stateMachine.Agent.destination, stateMachine.Player.transform.position) > 0.05f
                || stateMachine.Agent.remainingDistance == 0)
            {
                stateMachine.Agent.SetDestination(stateMachine.Player.transform.position);
            }

            Move(stateMachine.Agent.desiredVelocity.normalized * stateMachine.MovementSpeed, deltaTime);
        }
        stateMachine.Agent.velocity = stateMachine.Controller.velocity;
    }
}

I created an Enemy opponent that approaches the player and dodges immediately when they get too close (i.e. within attacking range). These series of actions are set up to repeat themselves using a behaviour tree.

When the enemy approaches a player, it’s behaviour is defined by this class called EnemyChasingState. This chasing state class uses the enemy’s NavMeshAgent component stored in a managing state machine component to determine the path to travel. (the NavMeshAgent component is called by using “stateMachine.Agent”).

the MoveToPlayer(deltaTime) function is called every frame (Tick(deltaTime)) to keep track of the player while chasing the player.

At first, I added constraints using if statements to prevent the NavMeshAgent destination from being recalculated every frame.

if (stateMachine.Agent.isOnNavMesh)
{
    if (Vector3.Distance(stateMachine.Agent.destination, stateMachine.Player.transform.position) > 0.05f
        || stateMachine.Agent.remainingDistance == 0)
    {
        stateMachine.Agent.SetDestination(stateMachine.Player.transform.position);
    }
}

However, it doesn’t change the outcome. The enemy stops before it gets close enough to the player to intersect the enemy’s attacking range, which would allow the enemy to continue the behaviour tree loop of actions.

The enemy does approach the player and dodges in it’s first attempt, but after that, all further attempts to approach and dodge the player fails because the enemy stops approaching its attacking zone.

I tried setting the Stopping Distance to 0 and disabling Auto Braking in the Nav Mesh Agent, but it doesn’t seem to do anything.

Essentially, after dodging the first time, the enemy approaches the player, but then stops a certain distance away from the player. When that happens, the NavMeshAgent.remainingDistance property is set to 0 and the desiredVelocity is set to Vector3.zero. whereas the actual distance from the player is further than the enemy’s attacking range to continue looping the behaviours.

I’ve tried every test I could think of but I can’t figure out what is stopping the NavMeshAgent prematurely. The EnemyChasingState is the only state that makes use of the NavMeshAgent component for locomotion (through stateMachine.Agent), and in any case where it exits the chasing state, the NavMeshAgent.ResetPath() is called to stop the nav mesh agent from tracking anything.

I don’t know if there is some kind of way to debug the NavMeshAgent source code directly. I don’t really know how the component gets its values. Has anyone encountered this problem?

Could you please submit this issue along with a reproduction project by using the "Report a Bug feature in the Editor? From the menu bar, select “Help → Report a Bug…”. Our Customer QA team will then investigate the issue further.

Hello, I’ve never used the “report a bug” feature in the editor before and I have a question. When you select “report a bug”, does it automatically send my entire project source code to the costumer QA team for them to see?

I’m sorry, I completely missed this! By default, yes, the project you currently have open will be attached along with all the project files. This helps us greatly in investigating the issue by ensuring that we have quick access to a project with the correct setup for reproduction. Attached projects are only used internally for testing reasons and are never shared outside the company.

However, you can remove the project from the attached files if you don’t want to share it (log files and such will still be attached, though). But then please make sure to list all the conditions necessary to reproduce the issue. Attachments like videos and screenshots are also very helpful.

That’s okay. I already used a “report a bug” feature and they helped me diagnose what was wrong with my code. This helped me figure out a solution that I’ll share here in case anyone is interested.

In my game logic, my EnemyChasingState class uses the NavMeshAgent to guide the enemy statemachine character. There are other state classes that move the enemy without using NavMeshAgent, such as EnemyDodgingState. States like dodging translate the enemy in a specific direction without the need for NavMeshAgent pathfinding, however when those other states move the enemy, the NavMeshAgent origin is offset from the actual character’s origin.

What I ended up doing is disabling the NavMeshAgent always and only enabling it when a specific state class wants to use it and also disable it after that state that uses it is destroyed. This resets the origin of the NavMeshAgent back to the player if they ever get moved in any particular direction without the NavMeshAgent.

1 Like