Unity3D -- Automatically generate animations

We have many sub-objects in a Prefab, and currently prefab uses a lot of animation states. If you want to change the properties of the Prefab animation in the Idle again, a more violent method is to change the properties that need to be changed directly in the Idle animation to K out, but if the animation changes, we need to change the properties inside the Idle to compare them.Trouble.Then it took a day to find the API and finally get the code to auto-generate the animation. The code below is to generate the animation in editor mode. That's a lot of rubbish. Just go straight to the code and do the whole thing.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
// Set clickable menus on Unity menu bar
public class ResetAnimation : Editor {

    private Transform m_AnimatorPrefab;

    [MenuItem("Animator/ResetProperty")]
    public static void  ResetProperty()
    {
        ScriptableWizard.DisplayWizard<ChoosePrefabWizard> ("ChoosePrefab", "Apply");
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System;
using System.IO;

public class ChoosePrefabWizard : ScriptableWizard {

    public Transform m_AnimatorPrefab;
    public RuntimeAnimatorController m_AnimatorController;

    private const string m_AnimationPath = "Assets/Yummy/Art/Animation";
    private static Dictionary<string, bool> propertyDict = new Dictionary<string, bool>();

    static void CreateWizard()
    {
        ChoosePrefabWizard wizard = ScriptableWizard.DisplayWizard<ChoosePrefabWizard> ("choose prefab");
        wizard.minSize = new Vector2 (300, 250);
    }

    void OnWizardCreate()
    {
        AnimationClip clip = new AnimationClip ();
        clip.frameRate = 24;
        foreach (AnimationClip animationClip in m_AnimatorController.animationClips) {
            foreach (EditorCurveBinding binding in AnimationUtility.GetCurveBindings(animationClip)) {
                string pathName = binding.path + "/" + binding.propertyName;
                if (!propertyDict.ContainsKey(pathName)) {
                    string[] paths = binding.path.Split ('/');
                    string transName = paths [paths.Length - 1];
                    Transform trans = null;
                    foreach (var item in m_AnimatorPrefab.GetComponentsInChildren<Transform>()) {
                        if (item.name == transName) {
                            trans = item;
                            break;
                        }
                    }
                    if (trans == null) {
                        Debug.LogError ("can not find transform:" + transName);
                    }
                    Keyframe keyFrame = new Keyframe();
                    keyFrame.time = 0;
                    keyFrame.value = GetKeyFrameValue(trans, binding.propertyName);

                    AnimationCurve curve = new AnimationCurve ();
                    curve.AddKey (keyFrame);
                    clip.SetCurve (binding.path, binding.type, binding.propertyName, curve);
                    propertyDict.Add (pathName, true);
                }
            }

            foreach (var binding in AnimationUtility.GetObjectReferenceCurveBindings(animationClip)) {
                string pathName = binding.path + "/" + binding.propertyName;

                if (!propertyDict.ContainsKey(pathName)) {
                    string[] paths = binding.path.Split ('/');
                    string transName = paths [paths.Length - 1];
                    Transform trans = null;
                    foreach (var item in m_AnimatorPrefab.GetComponentsInChildren<Transform>()) {
                        if (item.name == transName) {
                            trans = item;
                            break;
                        }
                    }
                    if (trans == null) {
                        Debug.LogError ("can not find transform:" + transName);
                    }

                    ObjectReferenceKeyframe[] keyframes = new ObjectReferenceKeyframe[1];
                    keyframes [0] = new ObjectReferenceKeyframe ();
                    keyframes [0].time = 0;
                    keyframes [0].value = GetObjectRenferenceValue (trans, binding.propertyName);
                    AnimationUtility.SetObjectReferenceCurve (clip, binding, keyframes);
                    propertyDict.Add (pathName, true);
                }
            }
        }
        if (!Directory.Exists(m_AnimationPath)) {
            System.IO.Directory.CreateDirectory (m_AnimationPath);
        }
        AssetDatabase.CreateAsset (clip, m_AnimationPath + "/" + m_AnimatorPrefab.name + "Idle.anim");
        AssetDatabase.SaveAssets ();
    }

    /// <summary>
    /// Get the component's corresponding KeyFrame value
    /// </summary>
    /// <returns>The key frame value.</returns>
    /// <param name="trans">Trans.</param>
    /// <param name="propertyName">Property name.</param>
    float GetKeyFrameValue(Transform trans, string propertyName)
    {
        if (propertyName == "m_LocalScale.x") {
            return trans.localScale.x;
        } else if (propertyName == "m_LocalScale.y") {
            return trans.localScale.y;
        } else if (propertyName == "m_LocalScale.z") {
            return trans.localScale.z;
        } else if (propertyName == "m_LocalPosition.x") {
            return trans.localPosition.x;
        } else if (propertyName == "m_LocalPosition.y") {
            return trans.localPosition.y;
        } else if (propertyName == "m_LocalPosition.z") {
            return trans.localPosition.z;
        } else if (propertyName == "localEulerAnglesRaw.x") {
            return trans.localEulerAngles.x;
        } else if (propertyName == "localEulerAnglesRaw.y") {
            return trans.localEulerAngles.y;
        } else if (propertyName == "localEulerAnglesRaw.z") {
            return trans.localEulerAngles.z;
        } else if (propertyName == "m_Size.x") {
            return trans.GetComponent<SpriteRenderer> ().size.x;
        } else if (propertyName == "m_Size.y") {
            return trans.GetComponent<SpriteRenderer> ().size.y;
        } else if (propertyName == "m_Color.a") {
            return trans.GetComponent<SpriteRenderer> ().color.a;
        } else if (propertyName == "m_Color.r") {
            return trans.GetComponent<SpriteRenderer> ().color.r;
        } else if (propertyName == "m_Color.g") {
            return trans.GetComponent<SpriteRenderer> ().color.g;
        } else if (propertyName == "m_Color.b") {
            return trans.GetComponent<SpriteRenderer> ().color.b;
        }  else if (propertyName == "m_Enabled") {
            if (trans.GetComponent<SpriteRenderer> ().enabled) {
                return 1;
            } else {
                return 0;
            }
        } else {
            Debug.LogError (propertyName + " have not doing");
            return -1;
        }
    }

    /// <summary>
    /// Get the value reference of the component
    /// </summary>
    /// <returns>The object renference value.</returns>
    /// <param name="trans">Trans.</param>
    /// <param name="propertyName">Property name.</param>
    UnityEngine.Object GetObjectRenferenceValue(Transform trans, string propertyName)
    {
        if (propertyName == "m_Sprite") {
            return trans.GetComponent<SpriteRenderer> ().sprite;
        } else {
            Debug.LogError (propertyName + " have not doing");
            return null;
        }
    }

}

ChoosePrefabWizard opens a window and you need to set Prefab and AnimarController. The code automatically creates an Idle animation to restore the changed properties.

Animator Prefab and Animator Controller must be paired, otherwise an error will occur. If you have changed other properties, you need to add the changed properties in GetKeyFrameValue and GetObjectRenferenceValue.

Tags: Unity

Posted on Thu, 16 Jul 2020 11:27:46 -0400 by mandred