1. 程式人生 > >Unity animator:StateMachineBehaviour的一點應用(施工中)

Unity animator:StateMachineBehaviour的一點應用(施工中)

cto 成員 err eric direct 其他 generic 條件 system

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而言,系統了不少,也方便了後期團隊成員的更多調用。

Unity animator:StateMachineBehaviour的一點應用(施工中)