Navmesh Agent - The Y Next Position & Y Velocity does not update if there is no X velocity.

Tried to post this to Unity Answers but my post seems to be stuck into moderation queue, trying here.

I’m using the Navmesh agent to make player pathfinding movement in a 2D game (XY). I’m trying to implement 2 movement options, a) Mouse Click (which works fine), b) WASD (where the problem lies).

Currently, the player will not move up or down when attempting to go straight up or straight down (pressing only W or S).

After trying to Debug this I found out that the Y axis of the navAgent.nextPosition was not updating unless there was some X axis input. The same thing goes for the navAgent.velocity (despite the navAgent.desiredVelocity to be correct).

It’s my first time using Navmesh so I’m not too sure what could cause this, here is the debug result and some script snippet. I’m trying to use with my WASD movement so I don’t have to add a bunch of colliders on my environment (currently using navmesh obstacles which I carve).

Here’s a image of the debug, a snippet of the script and an image of my navAgent:

using UnityEngine;
using UnityEngine.AI;

public class Script_Player_Controls : MonoBehaviour
{
    [Header("Mouse Player Movement")]
    [SerializeField] private Camera myCamera = default;
    [SerializeField] private ScriptObj_VectorValue startingPosition = default;
    [SerializeField] private ScriptObj_UIBools UIBoolManager = default;
    [SerializeField] private float playerSpeed = 3.4f;
    private Vector2 animationTargetPos;
   

    [Header("WASD Player Movement")]
    private Vector3 direction;

    [Header("Pathfinding")]
    [SerializeField] private NavMeshAgent navAgent = default;
    [SerializeField] private int rayDistance = 100;
    [SerializeField] private float timeBeforeAnimSwitch = 0.5f;

    private void Awake()
    {
        navAgent.updateRotation = false;
        navAgent.updateUpAxis = false;
        navAgent.updatePosition = false;
        playerSpeed = navAgent.speed;
    }

    void Start()
    {
        transform.position = startingPosition.entryPos;
    }

    void FixedUpdate()
    {
        MouseMove();
        WASDMove();
        Vector2 nextPos = navAgent.nextPosition;
        transform.position = Vector2.MoveTowards(transform.position, nextPos, playerSpeed * Time.deltaTime);
    }

    private void WASDMove()
    {
        direction.x = Input.GetAxisRaw("Horizontal");
        direction.y = Input.GetAxisRaw("Vertical");
        if (direction != Vector3.zero)
        {
            direction.x = transform.position.x + direction.normalized.x;
            direction.y = transform.position.y + direction.normalized.y;
            navAgent.destination = direction;
        }
        Debug.Log("NextPos: " + navAgent.nextPosition + ". Destination: " + navAgent.destination + ". Velocity: " + navAgent.velocity + ". Desired Velocity: " + navAgent.desiredVelocity); //Don't worry this atrocity will get removed.
    }

    private void MouseMove()
    {
        MoveAnimation(); //Handles Animations, will be reworked
        MoveRestrictions(); //Handles movement restrictions, will be reworked

        if (Input.GetMouseButton(0) && currentState == PlayerState.walk)
        {
            Ray ray = myCamera.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, rayDistance))
            {
                navAgent.destination = new Vector2(hit.point.x, hit.point.y);
            }

            animationTargetPos = myCamera.ScreenToViewportPoint(Input.mousePosition);
        }
    }

I temporarily fixed it with a “dirty” fix. adding the following right before setting the navAgent.desitination in the WASDMove() method.

            if (direction.y > 0) //Dirty fix for Y axis no movement bug
            {
                direction.x = direction.x + 0.01f;
            }
            else if (direction.y < 0)
            {
                direction.x = direction.x - 0.01f;
            }

basically I noticed that it was impossible when using the mouse controls to have a perfect Y-axis input and that there was always a bit of X-axis to the input (generally within 0.1 to 0.005) so adding this same “imperfection” somehow allows for Y-velocity (since there is X-velocity I reckon).

Seems to work fine right now but if someone knows why this is occurring and has a cleaner fix, please tell me!

EDIT: Nevermind, sometimes the player will go super slow for some reason (seems to be related to how far you are from starting position).
EDIT2: The closest the player is from the the 0,0 worldpoint, the fastest it is on the Y axis.

2 Likes

Ok so the solution was to actually make a custom navAgent following the tutorial here.

I fixed it without having to recreate the entire thing. Still a “Dirty” fix though.

if(shouldMove && moveTowards) {
                lookDirection = agent.velocity.normalized;
                Vector3 targetPosition = moveTowards.transform.position;
                if(Mathf.Abs(transform.localPosition.x) - Mathf.Abs(moveTowards.transform.localPosition.x) < 0.01f){
                    targetPosition.x += 0.02f;
                }
                agent.SetDestination(targetPosition);
            }
            else agent.SetDestination(transform.position);

I’m still having this problem in the latest version of unity. Is it really just one of those “fallen through the cracks” bugs that won’t get a fix?

Setting the destination seems to work fine for me (maybe they fixed it), but I’m getting this issue for NavMeshAgent.Move.

Even something as silly as this…

    public void Move(Vector2 moveDirection)
    {
        if (moveDirection.x == 0)
            moveDirection.x = 0.000001f;
        navMeshAgent.Move(moveDirection);
    }

fixes it. Super strange. Can someone at Unity comment on this?

I have discovered that supplying a non-zero Z component to the vector also results in movement. The agent remains bound to the graph so it doesn’t move at in all the Z. No x drift required.

I’m assuming that there’s some internal check in Move that rejects movement in only the Y direction since the Agent was originally made for 3D, and would typically move in the XZ plane as opposed to the XY. Current fix looks like this.

    public void Move(Vector2 moveDirection)
    {
        var newMove = (Vector3)moveDirection;

        if (newMove.x == 0) //Fixes oddity with navMeshAgent not accepting movement vectors if x == 0. Z value is irrelevant since we're confined to a 2D XY navmesh.
            newMove.z = 0.000001f;

        navMeshAgent.Move(newMove);
    }

Value doesn’t even need to be that low by the way. Just making sure nothing… freaky happens >_>

There was also a strange thing happen in lgotlazy’s method , the agent will stop a while then keep move when input Vertical Axis. So I have to modify the horizontal Axis