【Unity】UniRxでアニメーションの開始と終了をスクリプトで受け取る

## 概要

Unityのアニメーションの開始と終了をスクリプトで受け取って操作する手順です。

## サンプル

実装するサンプルです。Attackアニメーションの開始、終了および、Combinationアニメーションの開始、終了時にテキストが更新されていることが分かります。

![AnimationSample.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/901444/f273ddf0-75b7-7e5f-11fb-3615ed5f0d21.gif)

無料Assetの以下を使わせていただきました。

https://assetstore.unity.com/packages/3d/animations/haon-sd-series-bundle-84992

## 必要なもの

事前にUniRxをimportしておいてください。動かしたいオブジェクトやアニメーションも必要になります。

https://assetstore.unity.com/packages/tools/integration/unirx-reactive-extensions-for-unity-17276?locale=ja-JP

## 実装手順

### AnimationControllerの設定

動かしたいモデルにアタッチするAnimationControllerの設定をします。
今回は1つの攻撃アニメーションの`State`とコンビネーションの攻撃を合わせた`Sub State Machine`を用意しました。

アニメーションの開始と終了を受け取るために`ObservableStateMachineTrigger`をアタッチしてください。

読んでも詳しく書いてないんですが、`ObservableStateMachineTrigger`については以下から参照できます。


- Base Layer
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/901444/cdfe89b1-f9e8-5d84-96e8-90f48137977b.png)
- Combination(`Sub-State-Machine`)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/901444/8e277d2a-a6fc-ee2a-8d99-a65faa16080c.png)

### サンプルコード

AnimationControllerと合わせてアタッチするスクリプトです。

トリガーイベントとして以下を設定しています。他にもトリガーはあるので以下を参考にしてください。
https://github.com/neuecc/UniRx/wiki/UniRx.Triggers

- `OnStateEnterAsObservable`
    - Stateが開始したとき
- `OnStateExitAsObservable`
    - Stateが終了したとき

トリガー内で指定のStateを検知したときにテキストを書き換える処理にしています。
ここはご自身の好きな処理で大丈夫です。


```c#:AnimationUniRxSample.cs
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using UnityEngine.UI;
using UniRx;
using UniRx.Triggers;

public class AnimationUniRxSample : MonoBehaviour
{
    public Text text;

    void Start()
    {
        Animator animator = this.GetComponent<Animator>();

        // AnimatorからObservableStateMachineTriggerの参照を取得
        ObservableStateMachineTrigger trigger =
            animator.GetBehaviour<ObservableStateMachineTrigger>();

        // Stateの開始イベント
        IDisposable enterState = trigger
            .OnStateEnterAsObservable()
            .Subscribe(onStateInfo =>
            {
                AnimatorStateInfo info = onStateInfo.StateInfo;
                // Base Layer
                if (info.IsName("Base Layer.Attack"))
                {
                    text.text = "攻撃中: Attack";
                }
                // Sub State Machine
                if (info.IsName("Combination.WGS_attackA1"))
                {
                    text.text = "攻撃中: Combination";
                }
            }).AddTo(this);

        // Stateの終了イベント
        IDisposable exitState = trigger
            .OnStateExitAsObservable()
            .Subscribe(onStateInfo =>
            {
                AnimatorStateInfo info = onStateInfo.StateInfo;
                // Base Layer
                if (info.IsName("Base Layer.Attack"))
                {
                    text.text = "攻撃終了: Attack";
                }
                // Sub State Machine                
                if (info.IsName("Combination.WGS_attackA3"))
                {
                    text.text = "攻撃終了: Combination";
                }
            }).AddTo(this);
    }
}
```

※Sub-State-Machineの名前については、`Base Layer`からではなく`Sub-State-Machineの名前`.`Sub-State-MachineのState`で書いてください。
今回の場合、開始部分については`Combination.WGS_attackA1`、終了部分については`Combination.WGS_attackA3`にしております。

### 動かすオブジェクトにアタッチする

動かすモデルにAnimatorControllerとスクリプトをアタッチしてください。Animatorの設定等については省略します。

すると実行してTriggerをオンにするとアニメーションと同時にテキストが更新されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/901444/c2c44c5d-e378-9abe-e057-7c511ce70cea.png)

### 動作テスト

動作させる方法については環境によってことなるので割愛しますが、私の場合はAnimatorControllerの編集画面で適当に`Trigger`パラメータを設定し、対象のステートに向かって`Make Transition` > `ConditionsでTriggerを設定`の流れにしています。

![AnimationSample.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/901444/f273ddf0-75b7-7e5f-11fb-3615ed5f0d21.gif)

## まとめ

超簡単に開始と終了が作れたのでターン制のゲームなんかではすごく役に立つと思います。
ただ、UniRx最強だけど覚えることが多すぎる。

## 参考記事

https://bluebirdofoz.hatenablog.com/entry/2021/08/02/223435