首页 > 文章 > Unity animator:StateMachineBehaviour的一点应用(施工中)

Unity animator:StateMachineBehaviour的一点应用(施工中)

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而言,系统了不少,也方便了后期团队成员的更多调用。

时间:2019-04-16 00:50:02阅读(58)
联系我们 - 留言反馈
© 2017 版权所有 鲁ICP备17052893号