Unity animator:StateMachineBehaviour的一点应用(施工中)
有什么用
直奔主题,我们先讲讲作用,用法,再慢慢解释
一个简单的应用场景:Unity动画状态机中有一个“特色”是,如果你为一组Animator添加一个triggerA的parameter,用于控制动画A的播放(这里我们举例triggerA触发一次,进入动画A播放一次),你会发现,快速出发两次或多次triggerA,不加入限制条件,动画A将再播放完后再播放一次或多次
已有的解决方案是在脚本中添加一个计时器,控制triggerA的触发频率。但是通过重写StateMachineBehaviour的几个OnState方法,让动画每次在你需要的时候(进入,Update,退出等)清空一次这个输入信号(或是其他操作),便可以更方便,系统的控制这些信号
例如以下是我用于清空输入信号的FSMClearSignals,根据需要,我重写了OnStateEnter和OnStateExit,方便我在进入和退出被挂载的动画状态的时刻,清空之前的输入信号
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FSMClearSignals : StateMachineBehaviour
{
public string[] clearAtEnter;
public string[] clearAtExit;
// OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
foreach (var signal in clearAtEnter)
{
animator.ResetTrigger(signal);
}
}
// OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
//override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
//{
//
//}
// OnStateExit is called when a transition ends and the state machine finishes evaluating this state
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
foreach (var signal in clearAtExit)
{
animator.ResetTrigger(signal);
}
}
// OnStateMove is called right after Animator.OnAnimatorMove()
//override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
//{
// // Implement code that processes and affects root motion
//}
// OnStateIK is called right after Animator.OnAnimatorIK()
//override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
//{
// // Implement code that sets up animation IK (inverse kinematics)
//}
}
实现原理
StateMachineBehaviour具有一个当动画从进入到播放完毕退出的生命周期,通过重写以下的5个方法,你可以轻松的控制动画的各种状态回调,以上的代码只是一个简单的应用
- OnStateEnter()
- OnStateUpdate()
- OnStateExit()
- OnStateMove()
- OnStateIK()
图片
个人的用法
我们现在需要的动画状态下新建一个脚本,它会自动继承StateMachineBehaviour
图片
除了上文所示的FSMClearSignals,出于个人的使用需求,我还建立了三个脚本文件用于向状态机外传送状态信息,分别是
- FSMOnEnter.cs
- FSMOnUpdate.cs
- FSMOnExit.cs
在这个三个脚本中我分别只重写了OnStateEnter(),OnStateUpdate(),OnStateExit()
每个脚本中我都建立了一个string数组public string[] onEnterMessages; 存储我需要发送的信息,例如我
public class FSMOnEnter : StateMachineBehaviour
{
public string[] onEnterMessages;
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
foreach (var msg in onEnterMessages)
{
//animator.gameObject.SendMessage(msg);
animator.gameObject.SendMessageUpwards(msg);
}
}
}
图片
这是每当我进入一次Jump状态,我的FSMOnEnter脚本就会给上级传出一个OnJumpEnter的信息,当然我还需要一个拦截,接收信息的方法,我把他写入在控制我的主角的脚本下
public void OnJumpEnter () {
thrustVec = new Vector3 (0, jumpVelocity, 0);
playerInput.inputEnabled = false;
lockPlane = true;
trackDirection = true;
}
可以看到我在这个方法里实现了跳跃速度,方向的控制,跳跃时的输入锁定。这样一来每当觉得进入一次Jump状态,OnJumpEnter方法就会执行。个人感觉是比之前用协程计时器计算CD而言,系统了不少,也方便了后期团队成员的更多调用。
原文地址:https://www.cnblogs.com/zhxmdefj/p/10714230.html