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;//重要