为移动状态添加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的值,在这之后修改面板值将不再起作用来规避风险。
在原来的移动状态进行中,玩家的位移由方向单位量乘以速度得到,通过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);
}
之前写Speed属性的时候设置Clip速度的时候i写成0了修改下,最后把SO中的动画Clip替换成带RM版本的。
最终效果如下,可以很明显看到在跑步时动画的播放频率和移动速度匹配了(因为每一帧的deltaPostion是有动画实际的播放决定的),跑着小碎步。