Animator组件上有个Apply Root Motion来控制播放动画时是否启用动画自带的位移,有时候我们希望自己控制Root Motion因为动画师构建的位移更加符合角色动画,为此我们给Playable也增加RootMotion的支持。
提供支持的可能性在于Unity提供了OnAnimatorMove函数并能在这个方法内部获取到动画的位移变量,我们要把这个变量传出去但实际上只有动画播放时才回有值,这种不能直接向外界传值的情况我们可以通过事件的方式间接传参,也就是把功能方法准备好,等待OnAnimatorMove调用事件执行并将需要的位移参数(animator.deltaPosition,animator.deltaRotation)传入。
# region RootMotion
private Action<Vector3, Quaternion> rootMotionAction;
private void OnAnimatorMove()
{
rootMotionAction?.Invoke(animator.deltaPosition, animator.deltaRotation);
}
public void SetRootMotionAction(Action<Vector3, Quaternion> rootMotionAction)
{
this.rootMotionAction = rootMotionAction;
}
public void ClearRootMotionAction()
{
rootMotionAction = null;
}
#endregion
对应给外界提供事件的设置、清空函数。
/// <summary>
/// 播放动画
/// </summary>
public void PlayAnimation(string animationClipName, Action<Vector3,Quaternion> rootMotionAction = null,float speed = 1, bool refreshAnimation = false, float transtionFixedTime = 0.25f)
{
if (rootMotionAction != null)
{
view.Animation.SetRootMotionAction(rootMotionAction);
}
view.Animation.PlayAnimation(warriorConfig.GetAnimationByName(animationClipName),speed,refreshAnimation, transtionFixedTime);
}
public void PlayBlendAnimaiton(string clip1Name, string clip2Name, Action<Vector3, Quaternion> rootMotionAction = null, float speed = 1, float transitionFixedTime = 0.25f)
{
if (rootMotionAction != null)
{
view.Animation.SetRootMotionAction(rootMotionAction);
}
AnimationClip clip1 = warriorConfig.GetAnimationByName(clip1Name);
AnimationClip clip2 = warriorConfig.GetAnimationByName(clip2Name);
view.Animation.PlayBlendAnimaiton(clip1, clip2, speed, transitionFixedTime);
}
在播放动画时提供缺省参数Motion事件用于告知用根运动里的位移参数做什么。
public override void Exit()
{
base.Exit();
player.ClearRootMotionAction();
}
public void OnRootMotion(Vector3 deltaPosition, Vector3 deltaRotation)
{
Debug.Log(deltaPosition);
}
player.PlayBlendAnimaiton("Walk", "Run", OnRootMotion);
在移动状态里我们添加测试逻辑,在移动时输出根运动的位置变化量,同时注意状态退出时要清空RootMotion事件。
此时面板上的ApplyRootMotion已经显示被脚本控制。