MRが楽しい

MRやVRについて学習したことを書き残す

Unityで基本変形(移動・回転・スケール)のアニメーションを作成する その6(アニメーションの終了を検知する)

本日は Unity の技術調査枠です。
基本変形(移動・回転・スケール)のアニメーションを作成する方法についてまとめます。
前回記事の続きになります。
bluebirdofoz.hatenablog.com

今回は前回設定を行った「一度だけ再生するアニメーション」の終了タイミングを検知する方法です。

アニメーションの終了を検知する

前回作成した[Loop Time]を無効化したアニメーションコントローラを利用します。
以下のように順を追ってアニメーションを行うコントローラとスクリプトを作成しました。
f:id:bluebirdofoz:20181015221611j:plain
・TriggerKick.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// スクリプトを追加するオブジェクトに必要なコンポーネントの列記
[RequireComponent(typeof(Animator))] 
public class TriggerKick : MonoBehaviour {
    /// <summary>
    /// Animatorコンポーネント
    /// </summary>
    private Animator animator;

    /// <summary>
    /// 起動時の初期化
    /// </summary>
    void Start () {
        // Animatorコンポーネントの取得
        animator = GetComponent<Animator>();
    }

    /// <summary>
    /// 定期実行
    /// </summary>
    void Update()
    {
        // Zキー押下で実行する
        if (Input.GetKey(KeyCode.Z))
        {
            // トリガーを実行する
            animator.SetTrigger("AnimTrigger_Z");
        }
        // Yキー押下で実行する
        if (Input.GetKey(KeyCode.Y))
        {
            // トリガーを実行する
            animator.SetTrigger("AnimTrigger_Y");
        }
        // Xキー押下で実行する
        if (Input.GetKey(KeyCode.X))
        {
            // トリガーを実行する
            animator.SetTrigger("AnimTrigger_X");
        }
        // Rキー押下で実行する
        if (Input.GetKey(KeyCode.R))
        {
            // トリガーを実行する
            animator.SetTrigger("AnimTrigger_Reset");
        }
    }
}

シーンを再生します。
Y キーを押して、最初のアニメーションが開始した直後に X キーを押してみます。
すると以下のようにアニメーションの途中で次のアニメーションが割り込んでしまいます。
f:id:bluebirdofoz:20181015221621g:plain

アニメーションが完了するまで入力を受け付けないようにコードを修正します。
normalizedTime を参照する事で、ループを行わないアニメーションの終了を検知できます。
normalizedTime はアニメーション開始時に0を、1ループ分の再生完了後に1以上の値を返します。
docs.unity3d.com

normalizedTime を利用する際は GetCurrentAnimatorStateInfo で参照するレイヤを指定する必要があります。
今回は以下の通り、Base Layer しか存在しないので GetCurrentAnimatorStateInfo(0) で参照を行います。
f:id:bluebirdofoz:20181015221631j:plain

コードを以下の通り修正します。
EntryState については待機する必要はないので、EntryState のときのみ待機を無視しています。
・TriggerKick.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// スクリプトを追加するオブジェクトに必要なコンポーネントの列記
[RequireComponent(typeof(Animator))] 
public class TriggerKick : MonoBehaviour {
    /// <summary>
    /// Animatorコンポーネント
    /// </summary>
    private Animator animator;

    /// <summary>
    /// EntryStateのハッシュ値を取得
    /// </summary>
    static int entryState = Animator.StringToHash("Base Layer.EntryState");

    /// <summary>
    /// 起動時の初期化
    /// </summary>
    void Start () {
        // Animatorコンポーネントの取得
        animator = GetComponent<Animator>();
    }

    /// <summary>
    /// 定期実行
    /// </summary>
    void Update()
    {
        // アニメーションが再生完了(normalizedTime 1以上)
        // または EntryState のときのみ、入力を受け付け
        if (animator.GetCurrentAnimatorStateInfo(0).fullPathHash == entryState ||
            animator.GetCurrentAnimatorStateInfo(0).normalizedTime > 1.0f)
        {
            // Zキー押下で実行する
            if (Input.GetKey(KeyCode.Z))
            {
                // トリガーを実行する
                animator.SetTrigger("AnimTrigger_Z");
            }
            // Yキー押下で実行する
            if (Input.GetKey(KeyCode.Y))
            {
                // トリガーを実行する
                animator.SetTrigger("AnimTrigger_Y");
            }
            // Xキー押下で実行する
            if (Input.GetKey(KeyCode.X))
            {
                // トリガーを実行する
                animator.SetTrigger("AnimTrigger_X");
            }
            // Rキー押下で実行する
            if (Input.GetKey(KeyCode.R))
            {
                // トリガーを実行する
                animator.SetTrigger("AnimTrigger_Reset");
            }
        }
    }
}

シーンを再生します。
アニメーションが完了したタイミングで次の入力が受け付けられるようになりました。
f:id:bluebirdofoz:20181015221648g:plain