Controlling speed of diagonal navmesh movement?

Hi all. I’ve been working on a navmesh-based character controller based on this great video from Ciro Continisio. Here’s how I adapted his code to work with the old Input Manager:

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

public class PlayerMovement : MonoBehaviour{
  public float speed = 10f;

  private Vector3 inputValue = Vector3.zero;
  private float inputSqrMagnitude;

  void Update(){
    Step();
  }

  private void Step(){
    inputValue = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));
    inputSqrMagnitude = inputValue.sqrMagnitude;
    if(inputSqrMagnitude >= .01f){
      Vector3 newPosition = transform.localPosition + inputValue * Time.deltaTime * speed;
      NavMeshHit hit;
      bool isValid = NavMesh.SamplePosition(newPosition, out hit, 1.0f, NavMesh.AllAreas);
      if(isValid){
        if((transform.localPosition - hit.position).magnitude >= .02f){
          transform.localPosition = hit.position;
        }else{
          // movement stopped this frame
        }
      }
    }else{
      // no input from player
    }
  }
}

This has been helping me prototype levels very quickly, but I’ve noticed that diagonal movement is much faster than single-axis movement. Typically this can be controlled by normalizing or clamping the magnitude of the target vector, but I’m not sure how to do that here. I’ve tried the following:

  • transform.localPosition = Vector3.ClampMagnitude(hit.position, speed); causes character to teleport diagonally and get stuck in the terrain after any WASD input
  • transform.localPosition = hit.position.normalized; does the same
  • newPosition = Vector3.ClampMagnitude(newPosition, speed); also causes the character to teleport, but they can still move within a small circular area in the level
  • newPosition = newPosition.normalized;, which leaves the character unable to move at all

Any ideas?

When moving diagonally, the NavMeshAgent moves faster than when moving in a straight line because the distance it travels is greater. You can adjust the speed of the NavMeshAgent to compensate for this by reducing its speed when it moves diagonally.

One way to achieve this is by using the velocity property of the NavMeshAgent to calculate its current speed and then adjusting it based on the direction it is moving in. Here’s an example of how you could do this:

public class DiagonalSpeedAdjustment : MonoBehaviour
{
    private NavMeshAgent agent;
    private float diagonalSpeedModifier = 0.7f;

    private void Start()
    {
        agent = GetComponent<NavMeshAgent>();
    }

    private void Update()
    {
        // Calculate the current speed of the agent
        float currentSpeed = agent.velocity.magnitude;

        // If the agent is moving diagonally, adjust its speed
        if (agent.velocity.x != 0 && agent.velocity.z != 0)
        {
            agent.speed = currentSpeed * diagonalSpeedModifier;
        }
        else
        {
            agent.speed = currentSpeed;
        }
    }
}

In this example, the diagonalSpeedModifier variable is used to adjust the speed of the agent when it moves diagonally. A value of 0.7 means that the agent’s speed will be reduced by 30% when moving diagonally.

You can attach this script to your NavMeshAgent game object to apply the diagonal speed adjustment.