【Unity】 AnimatorのTriggerをBoolを使って再現する

More than 1 year has passed since last update.

UniRxについての記事のまとめはこちら


やりたいこと

  • PhotonAnimatorViewを使ってTriggerの同期がしたい
  • ただし現時点でTrigger同期は未対応
  • 仕方がないのでAnimatorのBoolを使ってTriggerを再現する

そもそも「Trigger」とは

  • 基本はBoolと同じ
  • ただしTrueにすると自動的にFalseに戻る性質がある
  • 一瞬だけ動作するアニメーションに切り替える時等によく使う

つまり、BoolにTrueを設定したら次フレームでFalseに書き換えてやればよい

作ってみた

私は何でもコンポーネントに分割する派なので、今回はアニメーション管理コンポーネントを作り、そこにTrigger機能を持ったメソッドを作りました。
外から「SetTriggerAttackA」「SetTriggerAttackB」を実行すれば、アニメーション遷移するようにしてあります。

PlayerAnimationController.cs
[RequireComponent(typeof (Animator))]
public class PlayerAnimationController : MonoBehaviour
{
        private enum AnimatorParameters
        {
            IsAttackA,
            IsAttackB
        }

    private Animator _animator;

    /// <summary>
    /// Actionデリゲートを流すSubject
    /// </summary>
    private Subject<Action> _actionSubject = new Subject<Action>();


    private void Start()
    {
        _animator = GetComponent<Animator>();

        //1フレーム遅延させてActionデリゲートを実行
        _actionSubject.DelayFrame(1).Subscribe(x => x());
    }

    /// <summary>
    /// 攻撃アニメーションA開始
    /// </summary>
    public void SetTriggerAttackA()
    {
        //IsAttackATriggerをTrueにする
        _animator.SetBool(AnimatorParameters.IsAttackA.ToString(), true);
        //IsAttackATriggerを次のフレームでFalseにする
        _actionSubject.OnNext(() => _animator.SetBool(AnimatorParameters.IsAttackA.ToString(), false));
    }

    /// <summary>
    /// 攻撃アニメーションB開始
    /// </summary>
    public void SetTriggerAttackB()
    {
        //IsAttackBTriggerをTrueにする
        _animator.SetBool(AnimatorParameters.IsAttackB.ToString(), true);
        //IsAttackBTriggerを次のフレームでFalseにする
        _actionSubject.OnNext(() => _animator.SetBool(AnimatorParameters.IsAttackB.ToString(), false));
    }
}

処理を次フレームに持ち越す方法

Trueにした次のフレームでFalseにする」といった処理はUniRxを使って実現しています。
Actionデリゲートを流せるSubjectを生成し、それにDelayFrame(1)を挟むことでフレームを遅延させてSubscribeでActionデリゲートを実行するようにしています。

UniRxを使った遅延実行
private void Start()
{
    _animator = GetComponent<Animator>();

    Subject<Action> _actionSubject = new Subject<Action>();

    //1フレーム後にActionデリゲートを実行する
    _actionSubject.DelayFrame(1).Subscribe(x => x());

    Debug.Log(string.Format("Startで実行:{0}",Time.frameCount));

    //_actionSubjectに流したActionデリゲートが次フレームで実行される
    _actionSubject.OnNext(() => Debug.Log(string.Format("1フレーム後に実行:{0}", Time.frameCount)));
}
実行結果
Startで実行:1
1フレーム後に実行:2

まとめ

ちゃんとTriggerと同じ挙動をしてくれました。
やはりUniRxは便利ですね(今回の使い方はかなり変則的な方だと思うけど)

ちなみにこの方法で作ったTrigger(中身はただのBool)をPhotonAnimatorViewに食わせたところ、ちゃんと動いてくれました。
ただ同期してくれないタイミングがあったりしたので調査が必要そうです。

3/29 追記

次のフレームに処理を実行するならObservable.NextFrameを使うだけで良さそうです

public void SetTriggerAttackA()
{
    _animator.SetBool("IsAttackATrigger", true);
    Observable.NextFrame()
        .Subscribe(_ => _animator.SetBool("IsAttackATrigger", false));
}
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.