明天实现的内容:
通过代码使用动画自带的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"); }