Unity NavMeshAgent 耦合动画移动
9 个月前
· 来自专栏
Unity游戏开发

爱墨客

不冒险才是最大的风险
简单总结下navmeshagent使用中遇到的几个问题.
自己的游戏中是使用agent获取目标速度, 然后根据动画root motion更新GameObject位置.获取速度并旋转物体朝向的代码如下
public Vector2 GetDirToPosbyNav(Vector3 pos)
Vector2 dir = Vector2.zero;
if (!nav.isOnNavMesh)
nav.Warp(new Vector3(Position.x, 0f, Position.z));
return dir;
NavMeshHit hit;
if (!nav.Raycast(pos, out hit))//检测不到路线上的agent
if (!Physics.CheckBox(transform.position + nav.radius * Vector3.up, nav.radius * Vector3.one))
return GameUtil.To2DVector(pos - transform.position);
bool hasDest = nav.SetDestination(pos);
bool hasPath = NavMesh.CalculatePath(Position, pos, NavMesh.AllAreas, path);
if (!hasDest || !hasPath || path.status != NavMeshPathStatus.PathComplete)
return dir;
dir = new Vector2(nav.desiredVelocity.x, nav.desiredVelocity.z).normalized;
return dir;
public void RotateToPosByNav(Vector3 pos)
Vector2 dir = GetDirToPosbyNav(pos);
if (dir != Vector2.zero)
Vector3 targetFWD = new Vector3(dir.x, 0f, dir.y);
transform.rotation = Quaternion.RotateTowards(transform.rotation,
Quaternion.LookRotation(targetFWD, Vector3.up), Const.MaxRoteAngDelta);
}
更新物体位置的代码有两种方法, 顾名思义, 分别命名为UseNav和ForceAnim, nav是navmeshagent, anim是animator, 代码如下
public void UseNav()//基于agent位移
nav.velocity = anim.velocity;//此处赋值在下一帧才会生效
transform.position = nav.nextPosition; //nav.nextPosition就是agent圆柱状collider的位置
public void ForceAnim()//基于动画位移
nav.velocity = Vector3.zero;
nav.nextPosition = tranform.position + anim.deltaPosition;
transform.position = nav.nextPosition;
protected virtual void OnAnimatorMove()//调用位移更新
//两种方法二选一
//ForceAnim();//适用于Idle等无位移动画, 避免被推走
UseNav()//适用于攻击/移动等带位移的动画,避免穿模
private void InitNav()
nav.enabled = true;
nav.updatePosition = false;//重要