123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- #if UNITY_EDITOR
- using System;
- using System.Collections.Generic;
- using System.IO;
- using UnityEditor;
- using UnityEditorInternal;
- using UnityEngine;
- namespace Animancer.Editor.Tools
- {
-
-
-
-
-
-
-
-
- [Serializable]
- public class GenerateSpriteAnimationsTool : SpriteModifierTool
- {
-
- #region Tool
-
- [NonSerialized] private List<string> _Names;
- [NonSerialized] private Dictionary<string, List<Sprite>> _NameToSprites;
- [NonSerialized] private ReorderableList _Display;
- [NonSerialized] private bool _NamesAreDirty;
-
-
- public override int DisplayOrder => 3;
-
- public override string Name => "Generate Sprite Animations";
-
- public override string HelpURL => Strings.DocsURLs.GenerateSpriteAnimations;
-
- public override string Instructions
- {
- get
- {
- if (Sprites.Count == 0)
- return "Select the Sprites you want to generate animations from.";
- return "Click Generate.";
- }
- }
-
-
- public override void OnEnable(int index)
- {
- base.OnEnable(index);
- _Names = new List<string>();
- _NameToSprites = new Dictionary<string, List<Sprite>>();
- _Display = AnimancerToolsWindow.CreateReorderableList(_Names, "Animations to Generate", (area, elementIndex, isActive, isFocused) =>
- {
- area.y = Mathf.Ceil(area.y + EditorGUIUtility.standardVerticalSpacing * 0.5f);
- area.height = EditorGUIUtility.singleLineHeight;
- var name = _Names[elementIndex];
- var sprites = _NameToSprites[name];
- AnimancerToolsWindow.BeginChangeCheck();
- name = EditorGUI.TextField(area, name);
- if (AnimancerToolsWindow.EndChangeCheck())
- {
- _Names[elementIndex] = name;
- }
- for (int i = 0; i < sprites.Count; i++)
- {
- area.y += area.height + EditorGUIUtility.standardVerticalSpacing;
- var sprite = sprites[i];
- AnimancerToolsWindow.BeginChangeCheck();
- sprite = (Sprite)EditorGUI.ObjectField(area, sprite, typeof(Sprite), false);
- if (AnimancerToolsWindow.EndChangeCheck())
- {
- sprites[i] = sprite;
- }
- }
- });
- _Display.elementHeightCallback = (elementIndex) =>
- {
- var lineCount = _NameToSprites[_Names[elementIndex]].Count + 1;
- return
- EditorGUIUtility.singleLineHeight * lineCount +
- EditorGUIUtility.standardVerticalSpacing * lineCount;
- };
- }
-
-
- public override void OnSelectionChanged()
- {
- _NameToSprites.Clear();
- _Names.Clear();
- _NamesAreDirty = true;
- }
-
-
- public override void DoBodyGUI()
- {
- EditorGUILayout.PropertyField(AnimancerSettings.NewAnimationFrameRate);
- var sprites = Sprites;
- if (_NamesAreDirty)
- {
- _NamesAreDirty = false;
- GatherNameToSprites(sprites, _NameToSprites);
- _Names.AddRange(_NameToSprites.Keys);
- }
- using (new EditorGUI.DisabledScope(true))
- {
- _Display.DoLayoutList();
- GUILayout.BeginHorizontal();
- {
- GUILayout.FlexibleSpace();
- GUI.enabled = sprites.Count > 0;
- if (GUILayout.Button("Generate"))
- {
- AnimancerGUI.Deselect();
- GenerateAnimationsBySpriteName(sprites);
- }
- }
- GUILayout.EndHorizontal();
- }
- EditorGUILayout.HelpBox("This function is also available via:" +
- "\n - The 'Assets/Create/Animancer' menu." +
- "\n - The Cog icon in the top right of the Inspector for Sprite and Texture assets",
- MessageType.Info);
- }
-
- #endregion
-
- #region Methods
-
-
- private static void GenerateAnimationsBySpriteName(List<Sprite> sprites)
- {
- if (sprites.Count == 0)
- return;
- sprites.Sort(NaturalCompare);
- var nameToSprites = new Dictionary<string, List<Sprite>>();
- GatherNameToSprites(sprites, nameToSprites);
- var pathToSprites = new Dictionary<string, List<Sprite>>();
- var message = ObjectPool.AcquireStringBuilder()
- .Append("Do you wish to generate the following animations?");
- const int MaxLines = 25;
- var line = 0;
- foreach (var nameToSpriteGroup in nameToSprites)
- {
- var path = AssetDatabase.GetAssetPath(nameToSpriteGroup.Value[0]);
- path = Path.GetDirectoryName(path);
- path = Path.Combine(path, nameToSpriteGroup.Key + ".anim");
- pathToSprites.Add(path, nameToSpriteGroup.Value);
- if (++line <= MaxLines)
- {
- message.AppendLine()
- .Append("- ")
- .Append(path)
- .Append(" (")
- .Append(nameToSpriteGroup.Value.Count)
- .Append(" frames)");
- }
- }
- if (line > MaxLines)
- {
- message.AppendLine()
- .Append("And ")
- .Append(line - MaxLines)
- .Append(" others.");
- }
- if (!EditorUtility.DisplayDialog("Generate Sprite Animations?", message.ReleaseToString(), "Generate", "Cancel"))
- return;
- foreach (var pathToSpriteGroup in pathToSprites)
- CreateAnimation(pathToSpriteGroup.Key, pathToSpriteGroup.Value.ToArray());
- AssetDatabase.SaveAssets();
- }
-
- private static char[] _Numbers, _TrimOther;
-
- private static void GatherNameToSprites(List<Sprite> sprites, Dictionary<string, List<Sprite>> nameToSprites)
- {
- for (int i = 0; i < sprites.Count; i++)
- {
- var sprite = sprites[i];
- var name = sprite.name;
-
- if (_Numbers == null)
- _Numbers = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
- name = name.TrimEnd(_Numbers);
-
- if (_TrimOther == null)
- _TrimOther = new char[] { ' ', '_', '-' };
- name = name.TrimEnd(_TrimOther);
-
- if (!nameToSprites.TryGetValue(name, out var spriteGroup))
- {
- spriteGroup = new List<Sprite>();
- nameToSprites.Add(name, spriteGroup);
- }
-
- if (spriteGroup.Count == 0 || spriteGroup[spriteGroup.Count - 1] != sprite)
- spriteGroup.Add(sprite);
- }
- }
-
-
- private static void CreateAnimation(string path, params Sprite[] sprites)
- {
- var frameRate = AnimancerSettings.NewAnimationFrameRate.floatValue;
- var clip = new AnimationClip
- {
- frameRate = frameRate,
- };
- var spriteKeyFrames = new ObjectReferenceKeyframe[sprites.Length];
- for (int i = 0; i < spriteKeyFrames.Length; i++)
- {
- spriteKeyFrames[i] = new ObjectReferenceKeyframe
- {
- time = i / (float)frameRate,
- value = sprites[i]
- };
- }
- var spriteBinding = EditorCurveBinding.PPtrCurve("", typeof(SpriteRenderer), "m_Sprite");
- AnimationUtility.SetObjectReferenceCurve(clip, spriteBinding, spriteKeyFrames);
- AssetDatabase.CreateAsset(clip, path);
- }
-
- #endregion
-
- #region Menu Functions
-
- private const string GenerateAnimationsBySpriteNameFunctionName = "Generate Animations By Sprite Name";
-
-
- [MenuItem(Strings.CreateMenuPrefix + GenerateAnimationsBySpriteNameFunctionName, validate = true)]
- private static bool ValidateGenerateAnimationsBySpriteName()
- {
- var selection = Selection.objects;
- for (int i = 0; i < selection.Length; i++)
- {
- var selected = selection[i];
- if (selected is Sprite || selected is Texture)
- return true;
- }
- return false;
- }
-
- [MenuItem(Strings.CreateMenuPrefix + GenerateAnimationsBySpriteNameFunctionName, priority = Strings.AssetMenuOrder + 13)]
- private static void GenerateAnimationsBySpriteName()
- {
- var sprites = new List<Sprite>();
- var selection = Selection.objects;
- for (int i = 0; i < selection.Length; i++)
- {
- var selected = selection[i];
- if (selected is Sprite sprite)
- {
- sprites.Add(sprite);
- }
- else if (selected is Texture2D texture)
- {
- sprites.AddRange(LoadAllSpritesInTexture(texture));
- }
- }
- GenerateAnimationsBySpriteName(sprites);
- }
-
- private static List<Sprite> _CachedSprites;
-
-
-
-
- private static List<Sprite> GetCachedSpritesToGenerateAnimations()
- {
- if (_CachedSprites == null)
- return _CachedSprites = new List<Sprite>();
-
- if (_CachedSprites.Count == 0)
- {
- EditorApplication.delayCall += () =>
- {
- GenerateAnimationsBySpriteName(_CachedSprites);
- _CachedSprites.Clear();
- };
- }
- return _CachedSprites;
- }
-
-
-
-
- [MenuItem("CONTEXT/" + nameof(Sprite) + GenerateAnimationsBySpriteNameFunctionName)]
- private static void GenerateAnimationsFromSpriteByName(MenuCommand command)
- {
- GetCachedSpritesToGenerateAnimations().Add((Sprite)command.context);
- }
-
-
- [MenuItem("CONTEXT/" + nameof(TextureImporter) + GenerateAnimationsBySpriteNameFunctionName, validate = true)]
- private static bool ValidateGenerateAnimationsFromTextureBySpriteName(MenuCommand command)
- {
- var importer = (TextureImporter)command.context;
- var sprites = LoadAllSpritesAtPath(importer.assetPath);
- return sprites.Length > 0;
- }
-
-
-
-
- [MenuItem("CONTEXT/" + nameof(TextureImporter) + GenerateAnimationsBySpriteNameFunctionName)]
- private static void GenerateAnimationsFromTextureBySpriteName(MenuCommand command)
- {
- var cachedSprites = GetCachedSpritesToGenerateAnimations();
- var importer = (TextureImporter)command.context;
- cachedSprites.AddRange(LoadAllSpritesAtPath(importer.assetPath));
- }
-
- #endregion
-
- }
- }
- #endif
|