为移动状态添加RootMotion使用,并兼容原先的模式

首先添加启用RootMotion的控制量,只有在config中勾选了ApplyRootMotionForMove才会将实际的RootMotion逻辑添加到Action事件中,在Exit时也添加判断逻辑。

    private bool ApplyRootMotionForMove;

    public override void Init(IStateMachineOwner owner, int stateType, StateMachine stateMachine)
    {
        base.Init(owner, stateType, stateMachine);
        characterController = player.GetComponent<CharacterController>();
        ApplyRootMotionForMove = player.CharacterConfig.ApplyRootMotionForMove;
    }
    public override void Enter()
    {
        //播放待机动作
        //player.PlayAnimation("Walk");
        Action<Vector3, Quaternion> rootMotion = null;
        if(ApplyRootMotionForMove)
        {
            rootMotion = OnRootMotion;
        }
        player.PlayBlendAnimaiton("Walk", "Run", rootMotion);
        player.SetBlendAnimationWeight(1);
    }

    public override void Exit()
    {
        base.Exit();
        if(ApplyRootMotionForMove) player.ClearRootMotionAction();
    }

这里有一个小trick,在这里我们并没有做运行时修改ApplyRootMotion的逻辑(可以注册事件监听来实现),因此,如果开发者在运行时更改ApplyRootMotion的值,对应的数据(Action事件)并没有清空造成问题,所以我们只在Init的时候读取一次ApplyRootMotion的值,在这之后修改面板值将不再起作用来规避风险。

alt

在原来的移动状态进行中,玩家的位移由方向单位量乘以速度得到,通过RootMotion实现位移时,我们仍然使用鼠标控制玩家的朝向,对玩家的物理位移量进行修改。RootMotion中的deltaPosition提供好了沿玩家朝向方向的位移,我们要做的只是控制动画播放的速度,动画播放速度越快,玩家每帧产生的物理位移越多,这样动画的播放速度和玩家的位移是严格匹配的,比只设置移动速度更加的协调(原来只考虑了玩家的移动速度,移动速度100时动画还按原速度播放就会很不协调)。

    private void OnRootMotion(Vector3 deltaPosition, Quaternion deltaRotation)
    {
        float speed = Mathf.Lerp(player.WalkSpeed, player.RunSpeed, runTransition);
        player.AnimationSpeed = speed;
        deltaPosition.y = -9.8f * Time.deltaTime;
        characterController.Move(deltaPosition);
    }

alt

之前写Speed属性的时候设置Clip速度的时候i写成0了修改下,最后把SO中的动画Clip替换成带RM版本的。

最终效果如下,可以很明显看到在跑步时动画的播放频率和移动速度匹配了(因为每一帧的deltaPostion是有动画实际的播放决定的),跑着小碎步。

alt