Search code examples
c#unity-game-enginenavmesh

NavmeshAgent player not parallel to slope of hill when moving over hill


NavmeshAgent player not parallel to slope of hill when moving over hill. On plane surface its going smoothly.

See Video

Below Image properties of navMesh and player https://ibb.co/fijmoV

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class SampleAgentScript : MonoBehaviour {
public Transform  target ;
NavMeshAgent agent;
//  private static bool start1=false , start2=false, start3;
// Use this for initialization

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



void Update()
{

    //if white button click moves to targer-1

    agent.SetDestination(target.position);

}

}

Solution

  • I am not sure if NavmeshAgent is supposed to do that for you. This looks like something you're supposed to do manually.

    You can correct the rotation of the character to match the slope by performing a raycast downwards and obtaining the normal of the hit point. After obtaining the normal of the hit point, you can then calculate the new rotation with that normal hit point. There are many ways to do that calculation but using Quaternion.FromToRotation and lerping the rotation with Quaternion.Lerp seems to work best.

    Finally, make sure to the raycast is only done to Objects you considered as a "Hill" or "Ground". You can do this with the bitwise operation on the layer the "Hill" or "Ground" objects are placed on. The example below assumes that the Objects you consider as "Hill" or "Ground" are on a layer called "Hill".

    //Reference of the moving GameObject that will be corrected
    public GameObject movingObject;
    
    //Offset postion from where the raycast is cast from
    public Vector3 originOffset;
    public float maxRayDist = 100f;
    
    //The speed to apply the corrected slope angle
    public float slopeRotChangeSpeed = 10f;
    
    void Update()
    {
        //Get the object's position
        Transform objTrans = movingObject.transform;
        Vector3 origin = objTrans.position;
    
        //Only register raycast consided as Hill(Can be any layer name)
        int hillLayerIndex = LayerMask.NameToLayer("Hill");
        //Calculate layermask to Raycast to. 
        int layerMask = (1 << hillLayerIndex);
    
    
        RaycastHit slopeHit;
    
        //Perform raycast from the object's position downwards
        if (Physics.Raycast(origin + originOffset, Vector3.down, out slopeHit, maxRayDist, layerMask))
        {
            //Drawline to show the hit point
            Debug.DrawLine(origin + originOffset, slopeHit.point, Color.red);
    
            //Get slope angle from the raycast hit normal then calcuate new pos of the object
            Quaternion newRot = Quaternion.FromToRotation(objTrans.up, slopeHit.normal)
                * objTrans.rotation;
    
            //Apply the rotation 
            objTrans.rotation = Quaternion.Lerp(objTrans.rotation, newRot,
                Time.deltaTime * slopeRotChangeSpeed);
    
        }
    
    }