🧯

UnityのSpineアニメーション遷移をAnimation Controllerでやる

2022/05/07に公開

はじめに

Unityにはもう何かデフォルトで2Dボーンアニメーションが出来るモノが入っているっぽいですが、何だかんだ流用性とかもあるし私の中ではまだまだSpineが現役です。使いやすいしね!(折角買ったのに勿体なく感じている訳ではない)

さて、UnityでSpineのアニメーション遷移にAnimation Controllerを使うと便利です。
そういった記事は他にもいくつかあるのですが、自分の備忘録として纏めたものを置いておきます。

今回使用するモデルはアークナイツのショウちゃんです。消火器噴射します!
ショウSD

Spine導入

UnityにSpineを導入する記事はもう1000個くらいネットに転がっています。
この辺とかを参考にすればいいと思います。
https://www.deathponta.com/entry/190226_Spine2Unity
注意点はAtlasの拡張子をatlas.txtに変えるくらいで他に難しいことはない。

Animator Controllerを作成する

遷移の作成

UnityのProjectウィンドウで右クリック⇒Create⇒Animation Controllerより、Animatorを作成しましょう。
今回はBegin(配置)⇒Idle⇒Action_Front(アクション)の簡単な三遷移で行います。
ついでにIdle状態に戻る時はResetのステータスをかまします(特に意味はないかも?)。
Animation Controller

Spine用のStateMachineBehaviourの作成

Spineのアニメーションによって遷移を行うためのスクリプトを作成します。

CharactorMotionState.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Spine.Unity;

/// <summary>
/// キャラクターのモーション遷移を管理(Spine)
/// </summary>
public class CharactorMotionState : StateMachineBehaviour {
    public string _animationName;
    public bool _loop = false;
    public float _timeScale = 1f;
    SkeletonAnimation _spineAnim;
    Animator _animator;
    bool _instate = false;
    bool _init = false;


    /// <summary>
    /// アニメーション遷移開始とともに、初期設定を行う
    /// </summary>
    public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
        _instate = true;
        if (!_init) {
            _spineAnim = animator.GetComponent<SkeletonAnimation>();
            _animator = animator;
            _spineAnim.state.Complete += OnComplete;

            _init = true;
        }
        _spineAnim.timeScale = _timeScale;
        _spineAnim.state.SetAnimation(0, _animationName, _loop);
    }
    public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
        _instate = false;
    }

    /// <summary>
    /// Spineの動作が終了したときの設定
    /// </summary>
    void OnComplete(Spine.TrackEntry entry) {
        if (_instate) {
            // Spineアニメーションが終了したとき、Animator Controllerのトリガーをセットする
            if (_loop == false) {
                _animator.SetTrigger("AnimationEnd");
            }
            else {
                _animator.ResetTrigger("AnimationEnd");
            }
        }
    }
}

アニメーション開始後、OnCompleteでアニメーションの終了を検知し、終了時にはAnimation ControllerのAnimationEndトリガーを付けます。
Animator上でのアニメーション終了検知にAnimationEndを使用します。

Animation Controllerにスクリプトをアタッチ

Animator画面より、StateのAdd Behaviourより先ほど作成したCharactor Motion Stateを追加します。そして、Animation Name(Spineで決めたアニメ名)をインスペクタで入力します。

また、Parametersより、AnimationEndのTriggerと、Action_Frontに遷移する条件の為のFrontActのTriggerを作成しましょう。

Animatorには以下の設定を行っていきます。

  • BeginとAction_Front(ループしないアニメーション)からの遷移条件(Conditions)に、AnimationEndを付ける
  • Idleの遷移条件にFrontActを付ける
  • Begin、Idle、Action_Frontからの遷移のHas Exit Timeのチェックをオフにする(Spineアニメーションを基準にするため)
  • ResetのStateはSpeedをめっちゃ早くし、遷移のExit Timeを0にする
  • お好みでTransit Durationも0にする
    例として、Begin⇒Idleの遷移はこんな感じになります。
    Animator Transit

じゃあ動かすか……

シーンに配置したSpineキャラクターに、先ほど作成したAnimation Controllerを接続します。
Add Component⇒Animatorより、Animatorを作成し、Controllerに先ほど設置したAnimation Controllerを設定。
実際にプレイすると……
SDプレビュー
かわいいね!
FrontActionのTriggerをクリックすることで、綺麗にAction_Frontへと遷移してくれました。

あとはUpdate関数に適当に書いたスクリプトでもアタッチすればOKでしょう。

Player.cs
public class Player : MonoBehaviour {
    private SkeletonAnimation _spine;
    private Animator _animator;

    void Start() {
        _spine = GetComponent<SkeletonAnimation>();
        _animator = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update() {
        if (_animator.GetCurrentAnimatorStateInfo(0).IsName("Idle") && Input.GetKeyDown(KeyCode.Space) == true) {
            _animator.SetTrigger("FrontAct");
            Debug.Log("SHOT!");
        }
    }
}

スペースを押せばアクションをします。

おわりに

遷移のトリガー条件を増やせば、歩行やジャンプ動作のアニメーション遷移もらくちんになります。
ショウちゃん動かしたゲーム何かできるといいな!

Discussion