UnityのMecanimアニメで、ムービープレーヤーのスライダーのような制御がしたい


やりたいこと

  • ムービープレーヤーのスライダーのような制御がしたい
    • アニメ全長の任意の位置へジャンプしたいです。
  • アニメの任意のフレームを再生したい
    • シーケンシャルな再生でなく、任意のフレームに対してランダムにアクセスして、スクリプト制御で正逆任意の速度で再生したいです。
検証環境
  • Unity 2019.4.x (LTS)

方法

具体例

以下のコードでは、対象のスライダーとアニメーターが、コードがアタッチされたオブジェクトの子孫の何処かに存在することを前提にしています。

AnimeSlider.cs
using UnityEngine;
using UnityEngine.UI;

public class AnimeSlider : MonoBehaviour {

    private Slider slider;
    private Animator animator;

    /// <summary>初期化</summary>
    void Start () {
        slider = GetComponentInChildren<Slider> ();
        slider.onValueChanged.AddListener (OnChangeSlider);
        animator = GetComponentInChildren<Animator> ();
        animator.speed = 0; // 再生をポーズ
    }

    /// <summary>スライダが変化</summary>
    public void OnChangeSlider (float _) {
        animator.Play (0, -1, slider.normalizedValue);
    }

}
  • これによって、スライダーの位置に応じた任意のフレームが再生されます。
  • ループするアニメの場合は、スライダの左端と右端で同じフレームが表示されます。
    • 同じにしたくない場合は、slider.normalizedValue * 0.9999999fとかにします。
  • ポーズを解除する場合は、animator.speed = 1;します。

蛇足

複数の同じアニメを時間差で表示
AnimeSlider.cs
using UnityEngine;
using UnityEngine.UI;

public class AnimeSlider : MonoBehaviour {

    private Slider slider;
    private Animator [] animators;

    /// <summary>初期化</summary>
    void Start () {
        slider = GetComponentInChildren<Slider> ();
        slider.onValueChanged.AddListener (OnChangeSlider);
        animators = GetComponentsInChildren<Animator> ();
        foreach (var animator in animators) {
            animator.speed = 0; // 再生をポーズ
        }
    }

    /// <summary>スライダが変化</summary>
    public void OnChangeSlider (float _) {
        for (var i = 0; i < animators.Length; i++) {
            var time = slider.normalizedValue - ((float) i / animators.Length);
            if (time < 0f) { time += 1f; }
            animators [i].Play (0, -1, time);
        }
    }

}