明天实现的内容:
通过代码使用动画自带的Root Motion
在这篇博客之前,攻打时是不会呈现位移的,因为咱们没有使用动画自带的Root Motion。为了更好的动画成果,咱们接下来将会使用到Root Motion。

上图中,红色的标识批示了动画的Root Motion量(具体我也不是太懂,反正就是个量),当咱们使用Root Motion时,零碎会将Root Motion量套用到网络游戏对象的transform上,留神是Animator所在的游戏对象,咱们的我的项目中,Animator被放到控制器次级的模型对象上,所以挪动的只是模型。
要应用Root Motion,咱们须要设置Animator组件下的Apply Root Motion为true,然而如果咱们间接就这么做了,那些自身带有Root Motion然而咱们并不想要使用的动画也会被用上,比如说挪动动画,而且因为咱们的模型只是控制器对象的子对象,使用动画的Root Motion会导致模型脱离父对象的原点。为了解决这些问题,咱们还是须要用脚本来使用Root Motion。上面的图片展现的就是我刚刚提到的问题。


咱们的代码将应用OnAnimatorMove办法(MonoBehaviour.OnAnimatorMove),该办法会在动画机算完Root Motion值之后的每一帧调用(然而还是在IK计算之前)。在这里咱们甚至能够对动画机算完之后的Root Motion做批改。为什么是算完之后?因为在算之前批改等于没改。
这次咱们不会去批改Root Motion,咱们将利用OnAnimatorMove的零碎调用机会,首先失去动画机计算的deltaPosition,就是动画机计算出的模型的Root Motion的位移(Root Motion不仅仅是位移还有旋转deltaRotation,然而这次咱们只有位移就行),持续施展传统艺能,在OnAnimatorMove中将deltaPosition,通过发送消息传递给PlayerController,由PlayerController中的OnUpdateRootMotion依据deltaPosition去挪动Rigidbody。毕竟Rigidbody在同一级,位移相干的所有操作还是要交给PlayerController。这样一来,咱们就通过脚本使用了攻打动画的Root Motion。

public class RootMotionController : MonoBehaviour{    private Animator anim;    private void Awake()    {        anim = GetComponent<Animator>();    }    void OnAnimatorMove()    {        SendMessageUpwards("OnUpdateRootMotion", (object)anim.deltaPosition);    }}

能够发现当咱们用了OnAnimatorMove当前,Apply Root Motion变成了Handled by Script。

上面是PlayerController中的OnUpdateRootMotion具体是如何使用Root Motion的。留神,咱们是在每一物理帧中才进行Rigidbody的地位批改,所以在每一个动画帧中要做的事件是累加Root Motion的位移量。

    // Root Motion的位移量 用于脚本使用Root Motion    private Vector3 m_deltaPos;        // 解决刚体的操作    private void FixedUpdate()    {        // 使用Root Motion 要放到批改rb.velocity以前进行        rb.position += m_deltaPos;                // ...                // 清零以后物理帧累积的m_deltaPos        m_deltaPos = Vector3.zero;    }    // 通过脚本使用动画的Root Motion    // 通过RootMotionController脚本中的OnAnimatorMove调用    public void OnUpdateRootMotion(object _deltaPos)    {        // 以后处于attack_oneHand_C动画才会使用Root Motion位移        if (CheckState("attack_oneHand_C", "Attack"))        {            // 更新m_deltaPos为动画机的Root Motion 之所以用累加是因为物理帧和动画帧不一样 在物理帧的最初会将m_deltaPos清零            // 依据我那点可怜的C#基础知识 这一步会导致拆箱 OnAnimatorMove中的那一步会导致装箱 损耗计算资源            m_deltaPos += (Vector3)_deltaPos;        }    }

最初的要害一步,咱们要辨认以后处在什么动画状态,只有在攻打时if (CheckState("attack_oneHand_C", "Attack"))才更新Root Motion,这样做完当前,就躲避了间接Apply Root Motion带来的问题。

依照之前的方法自制位移
如果动画没有自带位移,咱们就只能应用之前曲线加冲量的老办法自制了。然而成果必定就很难有美术们做Root Motion的成果那么好了,毕竟美术大大们在这方面还是比咱们厉害的。

    // 在Attack层的动画节点attack_oneHand_B更新时执行的办法    // 通过PlayerController动画机中的attack_oneHand_B节点上挂载的FSMOnUpdate调用    public void OnAttack_oneHandBUpdate()    {        // 计算攻打时的冲量        m_thrustVec = model.transform.forward * anim.GetFloat("attackOneHandAVelocity"); ;    }    // 在Attack层的动画节点attack_oneHand_C更新时执行的办法    // 通过PlayerController动画机中的attack_oneHand_C节点上挂载的FSMOnUpdate调用    public void OnAttack_oneHandCUpdate()    {        // 计算攻打时的冲量        m_thrustVec = model.transform.forward * anim.GetFloat("attackOneHandAVelocity");    }