如何让NavmeshAgent控制的car agent旋转角度匹配坡面
核心原因
NavMeshAgent默认的旋转更新仅处理水平方向的Y轴朝向调整,不会根据地面坡面的法向量计算倾斜姿态,因此车辆在坡面上行驶时会保持水平状态,和坡面错位。
具体实现步骤
- 第一步:关闭NavMeshAgent的自动旋转
代码中设置NavMeshAgent.updateRotation = false,将旋转控制权交给手动逻辑,避免默认的水平旋转覆盖坡面适配的姿态计算结果。 - 第二步:获取当前车辆所在位置的坡面法向量
有两种常用获取方式:- 从车辆中心点向下发射Physics射线检测地面碰撞,获取碰撞点的
normal属性作为坡面法向量,适合有地面碰撞层的场景 - 调用
NavMesh.SamplePosition采样当前点位的NavMesh面片信息,直接获取NavMesh面片的法向量,无需依赖地面碰撞层,和导航逻辑的匹配度更高
- 从车辆中心点向下发射Physics射线检测地面碰撞,获取碰撞点的
- 第三步:合并导航朝向与坡面姿态,平滑更新车辆旋转
从NavMeshAgent.desiredVelocity中取出导航系统给出的期望前进方向,将该方向投影到坡面法向量对应的平面上,再结合坡面法向量计算出最终的目标旋转值,通过插值平滑过渡避免姿态跳变。
示例代码
using UnityEngine; using UnityEngine.AI; [RequireComponent(typeof(NavMeshAgent))] public class CarSlopeAlign : MonoBehaviour { private NavMeshAgent _agent; // 旋转平滑系数,数值越大姿态切换越快 public float smoothSpeed = 6f; // 地面检测最大距离 public float checkDistance = 1.2f; public LayerMask groundLayer; private void Awake() { _agent = GetComponent<NavMeshAgent>(); // 关闭Agent自带的旋转控制 _agent.updateRotation = false; } private void Update() { // 未启用导航或已到达目标点时不做处理 if (!_agent.isOnNavMesh || _agent.remainingDistance <= _agent.stoppingDistance) return; // 向下发射射线检测地面 if (Physics.Raycast(transform.position + Vector3.up * 0.3f, Vector3.down, out RaycastHit hit, checkDistance, groundLayer)) { // 获取导航期望前进方向 Vector3 desiredForward = _agent.desiredVelocity.normalized; // 将前进方向投影到坡面平面,适配坡面倾斜 desiredForward = Vector3.ProjectOnPlane(desiredForward, hit.normal).normalized; if (desiredForward != Vector3.zero) { // 计算适配坡面的目标旋转 Quaternion targetRotation = Quaternion.LookRotation(desiredForward, hit.normal); // 平滑更新车辆旋转 transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, Time.deltaTime * smoothSpeed); } } } }
注意:如果场景坡面坡度超过了NavMesh烘焙时设置的
Max Slope参数,车辆将无法驶上对应坡面,需要提前确认烘焙参数和场景坡度匹配。如果需要适配颠簸地形,可以改为采集四个车轮位置的地面法向量取平均值,姿态表现会更真实。
内容的提问来源于stack exchange,提问作者Pulse
相关产品推荐
相关产品推荐

