アニメーション自動生成

Last-modified: 2016-05-24 (火) 18:11:31

概要

  • 画像の形式が決まっているときに歩行アニメーションを自動生成したい。
    • 形式が決まっている画像はこんな感じ
      歩行
    • 歩行以外もパターンが決まっている場合、それも自動生成させられる応用力があるとなお良い。
      • 例:風来のシ○ンのように、全キャラに8方向の「静止」「歩行」「攻撃」「被弾」「特技使用」など行動が決まっているときに、それに合わせた画像を用意し自動生成。

インデックスをアニメーションさせる

使い方

  • Inspectorでspritesにスプライトを設定する。
  • 設定するアニメーション
    Animation.jpg
    • キーフレームとして、望むインデックス+0.5を指定していく。
    • Add Animation EventでrefreshSprite()を呼ぶ。
  • スクリプト
    using UnityEngine;
    using System.Collections.Generic;
    
    [RequireComponent(typeof(SpriteRenderer))]
    [RequireComponent(typeof(Animator))]
    public class CharacterIndexAnimation : MonoBehaviour
    {
        public List<Sprite> sprites;
        public float spriteIndex;
    
        private SpriteRenderer spriteRenderer;
        private Animator animator;
    
        private void Awake()
        {
            spriteRenderer = GetComponent<SpriteRenderer>();
            animator = GetComponent<Animator>();
        }
    
        private void refreshSprite()
        {
            Debug.Log((int)spriteIndex);
            spriteRenderer.sprite = sprites[(int)spriteIndex];
        }
    }
    • Inspector
      ScriptInspector.jpg
    • インデックスに対応したスプライトを設定していく。

メリット

  • 実装が簡単。
  • アニメーション、アニメーションコントローラを1つ作ればあとは使いまわせる。
  • 汎用的なスプライト差し替えができる。
    • 他TextureのSpriteを持ってきたりね。
    • でも、そんなことするなら自動生成考えないよね・・・。

デメリット

  • Spriteは手動で設定しないといけない。
    • Texture1枚設定するだけであとは自動化するスクリプト書いた方が簡単で設定ミスもしなくなるね。
  • アニメーションさせるためにfloat値を使うので、値かintへの丸め方を工夫しないといけない。
    • 完成後しばらくたってみたら、Indexに1.5とか指定されてる意味が分からなくて混乱しそうw
  • Animationビューで再生してもspriteは更新されないので確認が面倒。

エディタ拡張で歩行アニメーションを生成する

layer.jpg
tree.jpg

使い方

  1. 画像を自動スライスしておく(順番がそのままであることを前提としているのでリネームしない)。
  2. SpriteRenderer.Spriteにスプライトのどれかを設定。
  3. ポチっとな
    ポチ.jpg

残作業

  • Textureをスライスするところも自動化するか悩み中
  • フレームレートの変更

スクリプト

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

#if
using UnityEditor;
using UnityEditor.Animations;
using AD = UnityEditor.AssetDatabase;
using EGL = UnityEditor.EditorGUILayout;
#endif

/// <summary>
/// キャラクタ
/// </summary>
[RequireComponent(typeof(SpriteRenderer))]
public class Character : MonoBehaviour
{
#if
    /// <summary>
    /// エディタ拡張
    /// </summary>
    [CustomEditor(typeof(Character))]
    [CanEditMultipleObjects]
    public class CharacterEditor : Editor
    {
        /// <summary>
        /// 設定
        /// </summary>
        private static class Settings
        {
            /// <summary>
            /// 名前設定
            /// </summary>
            public static class Names
            {
                /// <summary>ステート名接頭語:歩行中</summary>
                public const string stateWalk = "Walk";
                /// <summary>ステート名接頭語:停止</summary>
                public const string stateIdol = "Idol";

                /// <summary>パラメータ名:X方向</summary>
                public const string paramDirecitonX = "DirectionX";
                /// <summary>パラメータ名:Y方向</summary>
                public const string paramDirecitonY = "DirectionY";
                /// <summary>パラメータ名:歩行中フラグ</summary>
                public const string paramWalking = "Walking";
            }

            /// <summary>方向名とBlendTreeにおける座標ペア</summary>
            public static List<Direction> directions =
                new List<Direction>()
                {
                   new Direction("Down",new Vector2(0,-1) ),    //テクスチャ1行目
                   new Direction("Left",new Vector2(-1,0) ),    //2行目
                   new Direction("Right",new Vector2(1,0) ),    //3行目
                   new Direction("Up",new Vector2(0,1) ),       //4行目
                };
        }

        /// <summary>
        /// 方向名とBlendTreeにおける座標ペアを保持するクラス
        /// </summary>
        private class Direction
        {
            public string Name { get; set; }
            public Vector2 TreePosition { get; set; }

            public Direction(string name, Vector2 treePosition)
            {
                Name = name;
                TreePosition = treePosition;
            }
        }

        /// <summary>AnimatorControllerアセット拡張子</summary>
        private const string extensionController = ".controller";
        /// <summary>AnimationClipアセット拡張子</summary>
        private const string extensionClip = ".anim";

        /// <summary>アセット保存フォルダパス</summary>
        private static string folderPath = "Assets/Animations/";
        /// <summary>AnimationClipをAnimatorControllerの子アセットにするフラグ</summary>
        private static bool subassetFlag = true;

        /// <summary>歩行パターン(インデックスのList)</summary>
        private static List<int> walkIndexes = new List<int>() { 0, 1, 2, 1 };
        /// <summary>静止画インデックス</summary>
        private static int idolIndex = 1;

        /// <summary>Inspector折りたたみフラグ</summary>
        private static bool foldout = false;

        /// <summary>
        /// Inspectorのカスタム
        /// </summary>
        public override void OnInspectorGUI()
        {
            var t = (Character)target;

            //デフォルトInspector
            DrawDefaultInspector();

            //歩行アニメーション自動生成ボタン&実装
            EGL.Separator();
            foldout = EGL.Foldout(foldout, "歩行アニメーション自動生成");
            if(!foldout)
                return;

            //設定
            folderPath = EGL.TextField("フォルダパス", folderPath);
            subassetFlag = EGL.Toggle("Clipサブアセット化", subassetFlag);
            if(subassetFlag)
                EGL.HelpBox(
                    "AnimatorControllerアセットの子アセットとしてAnimationClipを保存",
                    MessageType.Info);
            else
                EGL.HelpBox(
                    "AnimatorControllerアセットと同じフォルダにAnimationClipアセットを保存",
                    MessageType.Info);

            if(GUILayout.Button("歩行アニメーション生成"))
            {
                if(!folderPath.EndsWith("/"))
                    folderPath = folderPath + "/";

                var sr = t.GetComponent<SpriteRenderer>();
                if(sr == null || sr.sprite == null)
                {
                    Debug.LogError("SpriteRenderer.sprite が見つかりません。");
                    return;
                }

                var allasset =
                    new List<Object>(
                        AD.LoadAllAssetsAtPath(AD.GetAssetPath(sr.sprite)));
                var texture =
                    (Texture2D)allasset.
                    Single(x => x.GetType() == typeof(Texture2D));
                var sprites =
                    allasset.
                    Where(x => x.GetType() == typeof(Sprite)).
                    Select(x => (Sprite)x).ToList();

                var assetPath = folderPath + texture.name + extensionController;

                //ファイル存在確認
                if(AD.LoadAssetAtPath<Object>(assetPath))
                {
                    Debug.LogError("既に " + assetPath + " が存在します。");
                    return;
                }

                //Animatorアタッチ
                var animator = t.GetComponent<Animator>();
                if(animator == null)
                    animator = t.gameObject.AddComponent<Animator>();

                //AnimatorController生成
                var controller = new AnimatorController();
                controller.name = texture.name;
                controller.AddLayer("Base Layer");
                animator.runtimeAnimatorController = controller;

                //Parameterを登録
                controller.AddParameter(
                    Settings.Names.paramDirecitonX,
                    AnimatorControllerParameterType.Float);
                controller.AddParameter(
                    Settings.Names.paramDirecitonY,
                    AnimatorControllerParameterType.Float);
                controller.AddParameter(
                    Settings.Names.paramWalking,
                    AnimatorControllerParameterType.Bool);
                controller.parameters[0].defaultFloat = 0;
                controller.parameters[1].defaultFloat = -1;
                controller.parameters[2].defaultBool = false;

                //AnimationClip生成
                var walkClipsWithPos = new List<KeyValuePair<AnimationClip, Vector2>>();
                var idolClipsWithPos = new List<KeyValuePair<AnimationClip, Vector2>>();
                for(int i = 0; i < Settings.directions.Count; ++i)
                {
                    ////静止アニメーション
                    idolClipsWithPos.Add(new KeyValuePair<AnimationClip, Vector2>(
                        MakeAnimacionCrip(
                            texture.name + "_" + Settings.Names.stateIdol + Settings.directions[i].Name,
                            sprites.Skip(i * 3).Take(3).ToList(),
                            new List<int>() { idolIndex }),
                        Settings.directions[i].TreePosition));

                    ////歩行アニメーション
                    walkClipsWithPos.Add(new KeyValuePair<AnimationClip, Vector2>(
                        MakeAnimacionCrip(
                            texture.name + "_" + Settings.Names.stateWalk + Settings.directions[i].Name,
                            sprites.Skip(i * 3).Take(3).ToList(),
                            walkIndexes),
                        Settings.directions[i].TreePosition));
                }

                //BlendTree生成・登録
                var stateMachine = controller.layers[0].stateMachine;
                var idolTree = MakeBlendTree(Settings.Names.stateIdol + "Tree", idolClipsWithPos);
                var walkTree = MakeBlendTree(Settings.Names.stateWalk + "Tree", walkClipsWithPos);
                var idolState = stateMachine.AddState(Settings.Names.stateIdol + "Tree");
                var walkState = stateMachine.AddState(Settings.Names.stateWalk + "Tree");
                idolState.motion = idolTree;
                walkState.motion = walkTree;

                //BlendTree間のTransition生成
                var idolWalkTransition = idolState.AddTransition(walkState);
                var walkIdolTransition = walkState.AddTransition(idolState);
                idolWalkTransition.AddCondition(
                    AnimatorConditionMode.If,
                    0,
                    Settings.Names.paramWalking);
                walkIdolTransition.AddCondition(
                    AnimatorConditionMode.IfNot,
                    0,
                    Settings.Names.paramWalking);

                //デフォルトスプライトを設定
                sr.sprite = sprites[1];

                //アセットファイル出力
                AD.CreateAsset(controller, assetPath);
                AD.AddObjectToAsset(stateMachine, controller);
                foreach(var state in stateMachine.states)
                {
                    AD.AddObjectToAsset(state.state, controller);
                    if(!(state.state.motion is AnimationClip))
                        AD.AddObjectToAsset(state.state.motion, controller);
                    foreach(var transition in state.state.transitions)
                        AD.AddObjectToAsset(transition, controller);
                }

                //AnimationClip出力
                if(subassetFlag)
                {
                    //サブアセットとして登録
                    foreach(var clip in controller.animationClips)
                        AD.AddObjectToAsset(clip, controller);
                    AD.ImportAsset(AD.GetAssetPath(controller));
                }
                else
                {
                    //アセットとして保存
                    foreach(var clip in controller.animationClips)
                        AD.CreateAsset(clip, folderPath + clip.name + extensionClip);
                }

                AD.SaveAssets();
                AD.Refresh();
            }
        }

        /// <summary>
        /// AnimationClip生成
        /// </summary>
        /// <param name="name">名前</param>
        /// <param name="sprites">スプライトList</param>
        /// <param name="animationIndexes">アニメーションのインデックス</param>
        /// <returns></returns>
        private AnimationClip MakeAnimacionCrip(
            string name,
            IList<Sprite> sprites,
            IList<int> animationIndexes)
        {
            var clip = new AnimationClip();
            var binding = new EditorCurveBinding();

            binding.path = "";
            binding.type = typeof(SpriteRenderer);
            binding.propertyName = "m_Sprite";

            //キーフレーム設定
            var keyFrames = new List<ObjectReferenceKeyframe>();
            for(int i = 0; i < animationIndexes.Count; i++)
            {
                if(animationIndexes[i] >= sprites.Count)
                {
                    Debug.LogWarning(
                        "スプライト " +
                        sprites.Count +
                        "枚 に対してインデックス " +
                        animationIndexes[i] +
                        " が指定されたのでスキップします");
                    continue;
                }

                keyFrames.Add(new ObjectReferenceKeyframe()
                {
                    time = (float)i / animationIndexes.Count,
                    value = sprites[animationIndexes[i]]
                });
            }

            //名前、フレームレート、ループ設定
            clip.name = name;
            clip.frameRate = animationIndexes.Count;
            var settings = AnimationUtility.GetAnimationClipSettings(clip);
            settings.loopTime = true;
            AnimationUtility.SetAnimationClipSettings(clip, settings);

            //登録
            AnimationUtility.SetObjectReferenceCurve(
                clip,
                binding,
                keyFrames.ToArray());

            return clip;
        }

        /// <summary>
        /// BlencTree生成
        /// </summary>
        /// <param name="name">名前</param>
        /// <param name="clipWithPositions">Clipと座標のペア</param>
        /// <returns></returns>
        private BlendTree MakeBlendTree(
            string name,
            ICollection<KeyValuePair<AnimationClip, Vector2>> clipWithPositions)
        {
            var tree = new BlendTree();
            tree.name = name;
            tree.blendType = BlendTreeType.SimpleDirectional2D;
            tree.blendParameter = Settings.Names.paramDirecitonX;
            tree.blendParameterY = Settings.Names.paramDirecitonY;

            foreach(var clip in clipWithPositions)
                tree.AddChild(clip.Key, clip.Value);

            return tree;
        }
    }

#endif
}

メリット

  • スプライトアニメーションらしいアニメーション設定になる。
  • Unityにおけるアニメーションの内部状態の理解が深まる。

デメリット

  • 実装中に頭が痛くなってくる。

エディタ拡張で色んなアニメーションを自動生成する

スクリプト(デバッグしきってない)

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

#if
using UnityEditor;
using UnityEditor.Animations;
using AD = UnityEditor.AssetDatabase;
using EGL = UnityEditor.EditorGUILayout;
#endif

/// <summary>
/// キャラクタ
/// </summary>
[RequireComponent(typeof(SpriteRenderer))]
[RequireComponent(typeof(Animator))]
public class Character2 : MonoBehaviour
{
#if
    /// <summary>画像</summary>
    public Texture2D texture;

    /// <summary>
    /// エディタ拡張
    /// </summary>
    [CustomEditor(typeof(Character2))]
    [CanEditMultipleObjects]
    public class CharacterEditor : Editor
    {
        /// <summary>
        /// 設定
        /// </summary>
        private static class Settings
        {
            /// <summary>アニメーション設定</summary>
            public static List<AnimationSetting> animations =
                new List<AnimationSetting>()
                {
                    new AnimationSetting("IdolDown",new List<int>() {1}, 1, false, "IdolTree", 0, -1),
                    new AnimationSetting("IdolLeft",new List<int>() {4}, 1, false, "IdolTree", -1, 0),
                    new AnimationSetting("IdolRight",new List<int>() {7}, 1, false, "IdolTree", 1, 0),
                    new AnimationSetting("IdolUp",new List<int>() {10}, 1, false, "IdolTree", 0, 1),

                    new AnimationSetting("WalkDown",new List<int>() {0,1,2,1}, 4, true, "WalkTree", 0, -1),
                    new AnimationSetting("WalkLeft",new List<int>() {3,4,5,4}, 4, true, "WalkTree", -1, 0),
                    new AnimationSetting("WalkRight",new List<int>() {6,7,8,7}, 4, true, "WalkTree", 1, 0),
                    new AnimationSetting("WalkUp",new List<int>() {9,10,11,10}, 4, true, "WalkTree", 0, 1),
                };

            /// <summary>パラメータ</summary>
            public static List<AnimatorControllerParameter> parameters =
                new List<AnimatorControllerParameter>()
                {
                    new AnimatorControllerParameter()
                    {
                        name = "DirectionX",
                        type = AnimatorControllerParameterType.Float,
                        defaultFloat = 0f
                    },
                    new AnimatorControllerParameter()
                    {
                        name = "DirectionY",
                        type = AnimatorControllerParameterType.Float,
                        defaultFloat = 0f
                    },
                    new AnimatorControllerParameter()
                    {
                        name = "Walking",
                        type = AnimatorControllerParameterType.Bool,
                        defaultBool = false
                    },
                };

            /// <summary>BlendTree</summary>
            public static List<BlendTreeSetting> blendTrees =
                new List<BlendTreeSetting>()
                {
                    new BlendTreeSetting(
                        "IdolTree",
                         BlendTreeType.SimpleDirectional2D,
                         parameters[0].name,
                         parameters[1].name),
                    new BlendTreeSetting(
                        "WalkTree",
                         BlendTreeType.SimpleDirectional2D,
                         parameters[0].name,
                         parameters[1].name),
                };

            /// <summary>遷移</summary>
            public static List<TransitionSetting> transitions =
                new List<TransitionSetting>()
                {
                    new TransitionSetting(
                        "IdolTree",
                        "WalkTree",
                        parameters[2].name,
                        AnimatorConditionMode.If,
                        0),
                    new TransitionSetting(
                        "WalkTree",
                        "IdolTree",
                        parameters[2].name,
                        AnimatorConditionMode.IfNot,
                        0),
                };
        }

        /// <summary>
        /// アニメーションの設定
        /// </summary>
        private class AnimationSetting
        {
            /// <summary>名前</summary>
            public string Name { get; set; }
            /// <summary>スプライトのインデックスリスト</summary>
            public List<int> SpriteIndexes { get; set; }
            /// <summary>フレームレート</summary>
            public int FrameRate { get; set; }
            /// <summary>ループフラグ</summary>
            public bool Loop { get; set; }
            /// <summary>登録するBlendTree名</summary>
            public string BlendTreeName { get; set; }
            /// <summary>登録するBlendTree座標</summary>
            public Vector2 BlendTreePosition { get; set; }

            public AnimationSetting(
                string name,
                List<int> spriteIndexes,
                int frameRate,
                bool loop,
                string blendTreeName,
                Vector2 blendTreePosition)
            {
                Name = name;
                SpriteIndexes = spriteIndexes;
                FrameRate = frameRate;
                Loop = loop;
                BlendTreeName = blendTreeName;
                BlendTreePosition = blendTreePosition;
            }

            public AnimationSetting(
                string name,
                List<int> spriteIndexes,
                int frameRate,
                bool loop,
                string blendTreeName,
                float blendParameterX,
                float blendParameterY)
                : this(name, spriteIndexes, frameRate, loop, blendTreeName, new Vector2(blendParameterX, blendParameterY))
            { }

            public AnimationSetting(
                string name,
                List<int> spriteIndexes,
                int frameRate,
                bool loop)
                : this(name, spriteIndexes, frameRate, loop, "", Vector2.zero)
            { }
        }

        /// <summary>
        /// フレーム情報
        /// </summary>
        private class AnimationFrame
        {
            /// <summary>スプライト</summary>
            public Sprite Sprite { get; set; }
            /// <summary>フレーム番号</summary>
            public int FrameNo { get; set; }

            public AnimationFrame(Sprite sprite, int frameNo)
            {
                Sprite = sprite;
                FrameNo = frameNo;
            }
        }

        /// <summary>
        /// BlendTree設定
        /// </summary>
        private class BlendTreeSetting
        {
            /// <summary>名前</summary>
            public string Name { get; set; }
            /// <summary>種別</summary>
            public BlendTreeType BlendType { get; set; }
            /// <summary>X軸パラメータ</summary>
            public string BlendParameterX { get; set; }
            /// <summary>Y軸パラメータ</summary>
            public string BlendParameterY { get; set; }

            public BlendTreeSetting(
                string name,
                BlendTreeType blendType,
                string blendParameterX,
                string blendParameterY)
            {
                Name = name;
                BlendType = blendType;
                BlendParameterX = blendParameterX;
                BlendParameterY = blendParameterY;
            }
        }

        /// <summary>
        /// 遷移情報
        /// </summary>
        private class TransitionSetting
        {
            /// <summary>遷移元</summary>
            public string Source { get; set; }
            /// <summary>遷移先</summary>
            public string Description { get; set; }

            /// <summary>パラメータ名</summary>
            public string ConditionParameter { get; set; }
            /// <summary>モード</summary>
            public AnimatorConditionMode ConditionMode { get; set; }
            /// <summary>閾値</summary>
            public float ConditionThreshold { get; set; }

            public TransitionSetting(
                string source,
                string description,
                string parameter,
                AnimatorConditionMode mode,
                float threshold)
            {
                Source = source;
                Description = description;
                ConditionParameter = parameter;
                ConditionMode = mode;
                ConditionThreshold = threshold;
            }
        }

        /// <summary>
        /// AnimationClip生成
        /// </summary>
        /// <param name="sprites">スプライト</param>
        /// <param name="setting">アニメーション設定</param>
        /// <returns></returns>
        private AnimationClip MakeAnimacionCrip(IList<Sprite> sprites, AnimationSetting setting)
        {
            //スプライトとフレーム番号のペアを生成していく
            var animationFrames = new List<AnimationFrame>();
            for(int i = 0; i < setting.SpriteIndexes.Count; ++i)
            {
                var index = setting.SpriteIndexes[i];
                if(index < 0 || index >= sprites.Count)
                    continue;

                animationFrames.Add(new AnimationFrame(sprites[index], i));
            }

            return MakeAnimacionCrip(
                setting.Name,
                animationFrames,
                setting.FrameRate,
                setting.Loop);
        }

        /// <summary>
        /// AnimationClip生成
        /// </summary>
        /// <param name="name">名前</param>
        /// <param name="frames">フレームのコレクション</param>
        /// <param name="frameRate">フレームレート</param>
        /// <param name="loop">ループ</param>
        /// <returns></returns>
        private AnimationClip MakeAnimacionCrip(
            string name,
            ICollection<AnimationFrame> frames,
            float frameRate,
            bool loop)
        {
            var clip = new AnimationClip();
            var binding = new EditorCurveBinding();

            binding.path = "";
            binding.type = typeof(SpriteRenderer);
            binding.propertyName = "m_Sprite";

            //キーフレーム設定
            var keyFrames = new List<ObjectReferenceKeyframe>();
            foreach(var frame in frames)
            {
                keyFrames.Add(new ObjectReferenceKeyframe()
                {
                    time = frame.FrameNo / frameRate,
                    value = frame.Sprite
                });
            }

            //名前、フレームレート、ループ設定
            clip.name = name;
            clip.frameRate = frameRate;
            var settings = AnimationUtility.GetAnimationClipSettings(clip);
            settings.loopTime = loop;
            AnimationUtility.SetAnimationClipSettings(clip, settings);

            //登録
            AnimationUtility.SetObjectReferenceCurve(
                clip,
                binding,
                keyFrames.ToArray());

            return clip;
        }

        /// <summary>AnimatorControllerアセット拡張子</summary>
        private const string extensionController = ".controller";
        /// <summary>AnimationClipアセット拡張子</summary>
        private const string extensionClip = ".anim";

        /// <summary>アセット保存フォルダパス</summary>
        private static string folderPath = "Assets/Animations/";
        /// <summary>AnimationClipをAnimatorControllerの子アセットにするフラグ</summary>
        private static bool subassetFlag = true;

        /// <summary>Inspector折りたたみフラグ</summary>
        private static bool foldout = true;

        /// <summary>
        /// Inspectorのカスタム
        /// </summary>
        public override void OnInspectorGUI()
        {
            var t = (Character2)target;

            //デフォルトInspector
            DrawDefaultInspector();

            //歩行アニメーション自動生成ボタン&実装
            EGL.Separator();
            foldout = EGL.Foldout(foldout, "アニメーション自動生成");
            if(!foldout)
                return;

            //設定
            folderPath = EGL.TextField("フォルダパス", folderPath);
            subassetFlag = EGL.Toggle("Clipサブアセット化", subassetFlag);
            if(subassetFlag)
                EGL.HelpBox(
                    "AnimatorControllerアセットの子アセットとしてAnimationClipを保存",
                    MessageType.Info);
            else
                EGL.HelpBox(
                    "AnimatorControllerアセットと同じフォルダにAnimationClipアセットを保存",
                    MessageType.Info);

            if(GUILayout.Button("アニメーション自動生成!"))
            {
                if(!folderPath.EndsWith("/"))
                    folderPath = folderPath + "/";

                if(t.texture == null)
                {
                    Debug.LogError("Textureが設定されていません。");
                    return;
                }

                //アセットパス
                var assetPath = folderPath + t.texture.name + extensionController;

                //ファイル存在確認
                if(AD.LoadAssetAtPath<Object>(assetPath))
                {
                    Debug.LogError("既に " + assetPath + " が存在します。");
                    return;
                }

                //スプライト取得
                var sprites = AD.LoadAllAssetsAtPath(AD.GetAssetPath(t.texture)).
                    Where(x => x.GetType() == typeof(Sprite)).
                    Select(x => (Sprite)x).
                    ToList();
                if(sprites == null || sprites.Count <= 0)
                {
                    Debug.LogError("スプライトを取得できませんでした");
                    return;
                }

                //Animatorアタッチ
                var animator = t.GetComponent<Animator>();
                if(animator == null)
                    animator = t.gameObject.AddComponent<Animator>();

                //AnimatorController生成
                var controller = new AnimatorController();
                controller.name = t.texture.name;
                controller.AddLayer("Base Layer");
                animator.runtimeAnimatorController = controller;

                //Parameter登録
                foreach(var param in Settings.parameters)
                    controller.AddParameter(param);

                //BlendTree登録
                var blendTrees = new List<BlendTree>();
                foreach(var blendTree in Settings.blendTrees)
                {
                    //BlendTreeをClone (削除されると困るので)
                    var tree = new BlendTree()
                    {
                        name = blendTree.Name,
                        blendType = blendTree.BlendType,
                        blendParameter = blendTree.BlendParameterX,
                        blendParameterY = blendTree.BlendParameterY
                    };

                    blendTrees.Add(tree);
                    controller.AddMotion(tree);
                }

                //AnimationClip生成、登録
                foreach(var animSetting in Settings.animations)
                {
                    var clip = MakeAnimacionCrip(sprites, animSetting);

                    if(animSetting.BlendTreeName != "")
                        blendTrees.Single(x => x.name == animSetting.BlendTreeName).AddChild(
                            clip,
                            animSetting.BlendTreePosition);
                    else
                        controller.AddMotion(clip);
                }

                //Transition生成、登録
                var stateMachine = controller.layers[0].stateMachine;
                foreach(var tranSetting in Settings.transitions)
                {
                    var src = stateMachine.states.Single(x => x.state.name == tranSetting.Source);
                    var des = stateMachine.states.Single(x => x.state.name == tranSetting.Description);

                    var transition = src.state.AddTransition(des.state);
                    transition.AddCondition(
                        tranSetting.ConditionMode,
                        tranSetting.ConditionThreshold,
                        tranSetting.ConditionParameter);
                }

                //デフォルトスプライトを設定
                t.GetComponent<SpriteRenderer>().sprite =
                    sprites[Settings.animations[0].SpriteIndexes[0]];

                //アセットファイル出力
                AD.CreateAsset(controller, assetPath);
                AD.AddObjectToAsset(stateMachine, controller);
                foreach(var state in stateMachine.states)
                {
                    AD.AddObjectToAsset(state.state, controller);
                    if(!(state.state.motion is AnimationClip))
                        AD.AddObjectToAsset(state.state.motion, controller);
                    foreach(var transition in state.state.transitions)
                        AD.AddObjectToAsset(transition, controller);
                }

                //AnimationClip出力
                if(subassetFlag)
                {
                    //サブアセットとして登録
                    foreach(var clip in controller.animationClips)
                        AD.AddObjectToAsset(clip, controller);
                    AD.ImportAsset(AD.GetAssetPath(controller));
                }
                else
                {
                    //アセットとして保存
                    foreach(var clip in controller.animationClips)
                    {
                        //重複防止のリネーム
                        clip.name = t.texture.name + "_" + clip.name;
                        AD.CreateAsset(clip, folderPath + clip.name + extensionClip);
                    }
                }

                AD.SaveAssets();
                AD.Refresh();
            }
        }
    }
#endif
}

メリット

  • 設定してしまえば色んなアニメーションを自動生成できる。

デメリット

  • 特化したスクリプト書く方がいいね。。。

もうこれでいいや

  1. 1キャラ分アニメーションとコントローラを作る。
  2. それを複製する。
  3. 複製したアニメーションのスプライト参照を変更する。

コメント