うにてぃブログ

主にUnityとC#に関する記事を書いていきます

【Unity】Animatior の再生を待つ

この記事は、Animator に セットしてる Animation が一つのみを想定している

f:id:hacchi_man:20200212003621p:plain:w300

AnimationStateInfo.IsName

Animation の名前が分かっていた場合は IsName で待つことができます

   private IEnumerator WaitAnimationImpl()
    {
        var animator = gameObject.GetComponent<Animator>();

        // Animationを再生して1フレーム待たないと正しい時間が取れない
        yield return null;
        
        var state = animator.GetCurrentAnimatorStateInfo(0);
        // StateがOpenじゃなくなるまで待つ
        yield return new WaitWhile(() => state.IsName("Open"));
    }

AnimationStateInfo.length

   private IEnumerator WaitAnimationImpl()
    {
        var animator = gameObject.GetComponent<Animator>();

        // 1フレーム待たないと State が反映されない
        yield return null;

        var state = animator.GetCurrentAnimatorStateInfo(0);
        yield return new WaitForSeconds(state.length);
    }

CustomYieldInstruction

CustomYieldInstruction を継承して Animation の待ち用 Yield を作成したりもできる
がanimator は state に反映されるまでに1フレーム待つ必要があるため
ちょっと処理がややこしくなっている

   private IEnumerator WaitAnimationImpl()
    {
        var wait = new WaitForAnimation(gameObject);
        yield return wait;
    }
using UnityEngine;

public class WaitForAnimation : CustomYieldInstruction
{
    public override bool keepWaiting
    {
        get
        {
            if (_wait > 0)
            {
                switch (_wait)
                {
                    // State の反映を待つために1回処理をスキップする
                    case 2:
                        _wait--;
                        return true;
                    case 1:
                        _wait--;
                        var info = _animator.GetCurrentAnimatorStateInfo(_layerIndex);
                        _time = info.length + _offset;
                        break;
                }
            }
            
            _time -= Time.deltaTime;
            return _time > 0f;
        }
    }

    private readonly Animator _animator;
    private readonly float _offset;
    private readonly int _layerIndex;
    private float _time;
    private int _wait;

    public WaitForAnimation(GameObject obj , int layerIndex = 0, float offset = 0f)
    {
        var animator = obj.GetComponent<Animator>();
        _animator = animator;
        _layerIndex = layerIndex;
        _offset = offset;
        
        _wait = 2;
    }

    public WaitForAnimation(Animator animator, int layerIndex = 0, float offset = 0f)
    {
        _animator = animator;
        _layerIndex = layerIndex;
        _offset = offset;
        
        _wait = 2;
    }
}