非エンジニア向けに簡易的なアニメーションビューア作ってみた


株式会社グレンジでUnityエンジニアをしている @s_ebata と申します。
この記事はグレンジ Advent Calendar 2020の12/17の記事です。

はじめに

タイトルの通りですが非エンジニア向けに超絶簡易的なアニメーションビューア機能を作ってみました。
本来ならUnityのAnimatorウィンドウとAnimationウィンドウを使えば事足りる機能ですが、本機能は以下の点を重視して手早く作ったものになります。ご留意ください。

  • 非エンジニア向け
  • インスペクタで完結する
  • アニメーションの指定と再生・停止ができる

環境

Unity 2018.4.27f1

demo

こんな感じでLayersとStateをプルダウンから選択して再生・一時停止・再開・停止が可能です

Unityちゃんのアニメーションチェックシーン使っているため若干ややこしい見た目になってますが、インスペクタ内からアニメーションの指定と再生・停止・一時停止・再開ができているのが確認出来るかと思います。
解像度が低くて分かりづらいかもですが、ボタンは左からPlay、Pause、Resume、Stopとなっています。

動画には入っていませんが、AnimationEventsの設定有無も確認できます。

実装

難しいことは一切やっていません。ただただAnimator側の情報を取って表示しているだけです。
細かい制御などは端折って記載しています。

// ...省略...

/// <summary>
/// CustomAnimator参照
/// </summary>
private CustomAnimator _customAnimator;

/// <summary>
/// レイヤー名を格納する配列
/// </summary>
private string[] _layerNames = new string[] { };

/// <summary>
/// ステート名を格納するディクショナリ
/// </summary>
private Dictionary<int, string[]> _stateNamesDict = new Dictionary<int, string[]>();

private int _layerIndex;

private CustomAnimator CustomAnimator
{
    get
    {
        if (_customAnimator == null)
            _customAnimator = target as CustomAnimator;
        return _customAnimator;
    }
}

public override void OnInspectorGUI()
{
    // ...省略...

    EditorGUILayout.LabelField("デバッグ再生");
    _layerIndex = EditorGUILayout.Popup("Layers", _layerIndex, _layerNames);

    var stateNames = _stateNamesDict.ContainsKey(_layerIndex) ? _stateNamesDict[_layerIndex] : new string[] { };
    _stateIndex = EditorGUILayout.Popup("States", _stateIndex, stateNames);
    _stateName = stateNames.Length > 0 ? stateNames[_stateIndex] : string.Empty;

    using (new EditorGUILayout.HorizontalScope())
    {
        if (GUILayout.Button("Play"))
        {
            var fullPathHash = Animator.StringToHash(string.Join(".", _animator.GetLayerName(_layerIndex), _stateName));
            CustomAnimator.Play(fullPathHash, _layerIndex, _normalizedTime, () =>
            {
                Debug.Log("Complete");
            });
        }
        if (GUILayout.Button("Pause"))
        {
            CustomAnimator.Pause();
        }
        if (GUILayout.Button("Resume"))
        {
            CustomAnimator.Resume();
        }
        if (GUILayout.Button("Stop"))
        {
            CustomAnimator.Stop();
        }
    }

    // ...省略...
}

// ...省略...

実行時にAnimatorControllerのLayersとStatesの拾い方がわからなくてググりました。
以下方法で拾えることがわかって勉強になりました。

// UnityEditorのAnimatorControllerでキャスト
var controller = _animator.runtimeAnimatorController as UnityEditor.Animations.AnimatorController;
for (var i = 0; i < controller.layers.Length; i++)
{
    var layer = controller.layers[i];
    Debug.Log(layer.name); // レイヤー名

    var states = layer.stateMachine.states;
    foreach (var state in states)
    {
        Debug.Log(state.state.name); // ステート名
    }
}             

以上になります。