No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AnimationClipGeneration.cs 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace UnityEditor.U2D.Aseprite
  5. {
  6. internal static class AnimationClipGeneration
  7. {
  8. const string k_RootName = "Root";
  9. public static AnimationClip[] Generate(string assetName,
  10. Sprite[] sprites,
  11. AsepriteFile file,
  12. List<Layer> layers,
  13. List<Frame> frames,
  14. List<Tag> tags,
  15. Dictionary<int, GameObject> layerIdToGameObject)
  16. {
  17. var noOfFrames = file.noOfFrames;
  18. if (tags.Count == 0)
  19. {
  20. var tag = new Tag();
  21. tag.name = assetName + "_Clip";
  22. tag.fromFrame = 0;
  23. tag.toFrame = noOfFrames;
  24. tags.Add(tag);
  25. }
  26. var layersWithDisabledRenderer = new HashSet<Layer>();
  27. for (var i = 0; i < layers.Count; ++i)
  28. {
  29. if (DoesLayerDisableRenderer(layers[i], tags))
  30. layersWithDisabledRenderer.Add(layers[i]);
  31. }
  32. var clips = new List<AnimationClip>(tags.Count);
  33. var animationNames = new HashSet<string>(tags.Count);
  34. for (var i = 0; i < tags.Count; ++i)
  35. {
  36. var clipName = tags[i].name;
  37. if (animationNames.Contains(clipName))
  38. {
  39. var nameIndex = 0;
  40. while (animationNames.Contains(clipName))
  41. clipName = $"{tags[i].name}_{nameIndex++}";
  42. Debug.LogWarning($"The animation clip name {tags[i].name} is already in use. Renaming to {clipName}.");
  43. }
  44. clips.Add(CreateClip(tags[i], clipName, layers, layersWithDisabledRenderer, frames, sprites, layerIdToGameObject));
  45. animationNames.Add(clipName);
  46. }
  47. return clips.ToArray();
  48. }
  49. static bool DoesLayerDisableRenderer(Layer layer, IReadOnlyList<Tag> tags)
  50. {
  51. if (layer.layerType != LayerTypes.Normal)
  52. return false;
  53. var cells = layer.cells;
  54. var linkedCells = layer.linkedCells;
  55. for (var i = 0; i < tags.Count; ++i)
  56. {
  57. var tag = tags[i];
  58. for (var frameIndex = tag.fromFrame; frameIndex < tag.toFrame; ++frameIndex)
  59. {
  60. var foundCell = false;
  61. foreach (var cell in cells)
  62. {
  63. if (cell.frameIndex != frameIndex)
  64. continue;
  65. foundCell = true;
  66. break;
  67. }
  68. if (foundCell)
  69. continue;
  70. foreach (var cell in linkedCells)
  71. {
  72. if (cell.frameIndex != frameIndex)
  73. continue;
  74. foundCell = true;
  75. break;
  76. }
  77. if (!foundCell)
  78. return true;
  79. }
  80. }
  81. return false;
  82. }
  83. static AnimationClip CreateClip(Tag tag, string clipName, List<Layer> layers, HashSet<Layer> layersWithDisabledRenderer, IReadOnlyList<Frame> frames, Sprite[] sprites, Dictionary<int, GameObject> layerIdToGameObject)
  84. {
  85. var animationClip = new AnimationClip()
  86. {
  87. name = clipName,
  88. frameRate = 100f
  89. };
  90. var clipSettings = new AnimationClipSettings();
  91. clipSettings.loopTime = tag.isRepeating;
  92. AnimationUtility.SetAnimationClipSettings(animationClip, clipSettings);
  93. for (var i = 0; i < layers.Count; ++i)
  94. {
  95. var layer = layers[i];
  96. if (layer.layerType != LayerTypes.Normal)
  97. continue;
  98. var layerGo = layerIdToGameObject[layer.index];
  99. if (layerGo.GetComponent<SpriteRenderer>() == null)
  100. continue;
  101. var doesLayerDisableRenderer = layersWithDisabledRenderer.Contains(layer);
  102. var layerTransform = layerGo.transform;
  103. var spriteKeyframes = new List<ObjectReferenceKeyframe>();
  104. var cells = layer.cells;
  105. var activeFrames = AddCellsToClip(cells, in tag, in sprites, frames, ref spriteKeyframes);
  106. var linkedCells = layer.linkedCells;
  107. activeFrames.UnionWith(AddLinkedCellsToClip(linkedCells, in cells, in tag, in sprites, frames, ref spriteKeyframes));
  108. spriteKeyframes.Sort((x, y) => x.time.CompareTo(y.time));
  109. DuplicateLastFrame(ref spriteKeyframes, frames[tag.toFrame - 1], animationClip.frameRate);
  110. var path = GetTransformPath(layerTransform);
  111. var spriteBinding = EditorCurveBinding.PPtrCurve(path, typeof(SpriteRenderer), "m_Sprite");
  112. AnimationUtility.SetObjectReferenceCurve(animationClip, spriteBinding, spriteKeyframes.ToArray());
  113. AddEnabledKeyframes(layerTransform, tag, frames, doesLayerDisableRenderer, in activeFrames, in animationClip);
  114. AddSortOrderKeyframes(layerTransform, layer, tag, frames, in cells, in animationClip);
  115. AddAnimationEvents(in tag, frames, animationClip);
  116. }
  117. return animationClip;
  118. }
  119. static HashSet<int> AddCellsToClip(IReadOnlyList<Cell> cells, in Tag tag, in Sprite[] sprites, IReadOnlyList<Frame> frames, ref List<ObjectReferenceKeyframe> keyFrames)
  120. {
  121. var activeFrames = new HashSet<int>();
  122. var startTime = GetTimeFromFrame(frames, tag.fromFrame);
  123. for (var i = 0; i < cells.Count; ++i)
  124. {
  125. var cell = cells[i];
  126. if (cell.frameIndex < tag.fromFrame ||
  127. cell.frameIndex >= tag.toFrame)
  128. continue;
  129. var sprite = Array.Find(sprites, x => x.GetSpriteID() == cell.spriteId);
  130. if (sprite == null)
  131. continue;
  132. var keyframe = new ObjectReferenceKeyframe();
  133. var time = GetTimeFromFrame(frames, cell.frameIndex);
  134. keyframe.time = time - startTime;
  135. keyframe.value = sprite;
  136. keyFrames.Add(keyframe);
  137. activeFrames.Add(cell.frameIndex);
  138. }
  139. return activeFrames;
  140. }
  141. static HashSet<int> AddLinkedCellsToClip(IReadOnlyList<LinkedCell> linkedCells, in List<Cell> cells, in Tag tag, in Sprite[] sprites, IReadOnlyList<Frame> frames, ref List<ObjectReferenceKeyframe> keyFrames)
  142. {
  143. var activeFrames = new HashSet<int>();
  144. var startTime = GetTimeFromFrame(frames, tag.fromFrame);
  145. for (var i = 0; i < linkedCells.Count; ++i)
  146. {
  147. var linkedCell = linkedCells[i];
  148. if (linkedCell.frameIndex < tag.fromFrame ||
  149. linkedCell.frameIndex >= tag.toFrame)
  150. continue;
  151. var cellIndex = cells.FindIndex(x => x.frameIndex == linkedCell.linkedToFrame);
  152. if (cellIndex == -1)
  153. continue;
  154. var cell = cells[cellIndex];
  155. var sprite = Array.Find(sprites, x => x.GetSpriteID() == cell.spriteId);
  156. if (sprite == null)
  157. continue;
  158. var keyframe = new ObjectReferenceKeyframe();
  159. var time = GetTimeFromFrame(frames, linkedCell.frameIndex);
  160. keyframe.time = time - startTime;
  161. keyframe.value = sprite;
  162. keyFrames.Add(keyframe);
  163. activeFrames.Add(linkedCell.frameIndex);
  164. }
  165. return activeFrames;
  166. }
  167. static void DuplicateLastFrame(ref List<ObjectReferenceKeyframe> keyFrames, Frame lastFrame, float frameRate)
  168. {
  169. if (keyFrames.Count == 0)
  170. return;
  171. var frameTime = 1f / frameRate;
  172. var lastKeyFrame = keyFrames[^1];
  173. var duplicatedFrame = new ObjectReferenceKeyframe();
  174. var time = lastKeyFrame.time + MsToSeconds(lastFrame.duration);
  175. // We remove one AnimationClip frame, since the animation system will automatically add one frame at the end.
  176. time -= frameTime;
  177. duplicatedFrame.time = time;
  178. duplicatedFrame.value = lastKeyFrame.value;
  179. keyFrames.Add(duplicatedFrame);
  180. }
  181. static string GetTransformPath(Transform transform)
  182. {
  183. var path = transform.name;
  184. if (transform.name == k_RootName)
  185. return "";
  186. if (transform.parent.name == k_RootName)
  187. return path;
  188. var parentPath = GetTransformPath(transform.parent) + "/";
  189. path = path.Insert(0, parentPath);
  190. return path;
  191. }
  192. static void AddEnabledKeyframes(Transform layerTransform, Tag tag, IReadOnlyList<Frame> frames, bool doesLayerDisableRenderer, in HashSet<int> activeFrames, in AnimationClip animationClip)
  193. {
  194. if (activeFrames.Count == tag.noOfFrames && !doesLayerDisableRenderer)
  195. return;
  196. var path = GetTransformPath(layerTransform);
  197. var enabledBinding = EditorCurveBinding.FloatCurve(path, typeof(SpriteRenderer), "m_Enabled");
  198. var enabledKeyframes = new List<Keyframe>();
  199. var disabledPrevFrame = false;
  200. var startTime = GetTimeFromFrame(frames, tag.fromFrame);
  201. for (var frameIndex = tag.fromFrame; frameIndex < tag.toFrame; ++frameIndex)
  202. {
  203. var time = GetTimeFromFrame(frames, frameIndex);
  204. time -= startTime;
  205. if (!activeFrames.Contains(frameIndex) && !disabledPrevFrame)
  206. {
  207. var keyframe = GetBoolKeyFrame(false, time);
  208. enabledKeyframes.Add(keyframe);
  209. disabledPrevFrame = true;
  210. }
  211. else if (activeFrames.Contains(frameIndex) && disabledPrevFrame)
  212. {
  213. var keyframe = GetBoolKeyFrame(true, time);
  214. enabledKeyframes.Add(keyframe);
  215. disabledPrevFrame = false;
  216. }
  217. }
  218. if (enabledKeyframes.Count == 0 && !doesLayerDisableRenderer)
  219. return;
  220. // Make sure there is an enable keyframe on the first frame, if the first frame is active.
  221. if (activeFrames.Contains(tag.fromFrame))
  222. {
  223. var keyframe = GetBoolKeyFrame(true, 0f);
  224. enabledKeyframes.Add(keyframe);
  225. }
  226. var animCurve = new AnimationCurve(enabledKeyframes.ToArray());
  227. AnimationUtility.SetEditorCurve(animationClip, enabledBinding, animCurve);
  228. }
  229. static void AddSortOrderKeyframes(Transform layerTransform, Layer layer, Tag tag, IReadOnlyList<Frame> frames, in List<Cell> cells, in AnimationClip animationClip)
  230. {
  231. var layerGo = layerTransform.gameObject;
  232. var spriteRenderer = layerGo.GetComponent<SpriteRenderer>();
  233. if (spriteRenderer == null)
  234. return;
  235. var sortOrderKeyframes = new List<Keyframe>();
  236. var path = GetTransformPath(layerTransform);
  237. var sortOrderBinding = EditorCurveBinding.FloatCurve(path, typeof(SpriteRenderer), "m_SortingOrder");
  238. var startTime = GetTimeFromFrame(frames, tag.fromFrame);
  239. var hasKeyOnFirstFrame = false;
  240. for (var i = 0; i < cells.Count; ++i)
  241. {
  242. var cell = cells[i];
  243. if (cell.frameIndex < tag.fromFrame ||
  244. cell.frameIndex >= tag.toFrame)
  245. continue;
  246. var additiveSortOrder = cell.additiveSortOrder;
  247. if (additiveSortOrder == 0)
  248. continue;
  249. if (cell.frameIndex == tag.fromFrame)
  250. hasKeyOnFirstFrame = true;
  251. var time = GetTimeFromFrame(frames, cell.frameIndex) - startTime;
  252. var keyframe = GetIntKeyFrame(layer.index + additiveSortOrder, time);
  253. sortOrderKeyframes.Add(keyframe);
  254. }
  255. if (sortOrderKeyframes.Count == 0)
  256. return;
  257. if (!hasKeyOnFirstFrame)
  258. {
  259. var firstFrame = GetIntKeyFrame(layer.index, 0f);
  260. sortOrderKeyframes.Add(firstFrame);
  261. }
  262. var animCurve = new AnimationCurve(sortOrderKeyframes.ToArray());
  263. AnimationUtility.SetEditorCurve(animationClip, sortOrderBinding, animCurve);
  264. }
  265. static float GetTimeFromFrame(IReadOnlyList<Frame> frames, int frameIndex)
  266. {
  267. var totalMs = 0;
  268. for (var i = 0; i < frameIndex; ++i)
  269. totalMs += frames[i].duration;
  270. return MsToSeconds(totalMs);
  271. }
  272. static float MsToSeconds(int ms) => ms / 1000f;
  273. static Keyframe GetBoolKeyFrame(bool value, float time)
  274. {
  275. var keyframe = new Keyframe();
  276. keyframe.value = value ? 1f : 0f;
  277. keyframe.time = time;
  278. keyframe.inTangent = float.PositiveInfinity;
  279. keyframe.outTangent = float.PositiveInfinity;
  280. return keyframe;
  281. }
  282. static Keyframe GetIntKeyFrame(int value, float time)
  283. {
  284. var keyframe = new Keyframe();
  285. keyframe.value = value;
  286. keyframe.time = time;
  287. keyframe.inTangent = float.PositiveInfinity;
  288. keyframe.outTangent = float.PositiveInfinity;
  289. return keyframe;
  290. }
  291. static void AddAnimationEvents(in Tag tag, IReadOnlyList<Frame> frames, AnimationClip animationClip)
  292. {
  293. var events = new List<AnimationEvent>();
  294. var startTime = GetTimeFromFrame(frames, tag.fromFrame);
  295. for (var frameIndex = tag.fromFrame; frameIndex < tag.toFrame; ++frameIndex)
  296. {
  297. var frame = frames[frameIndex];
  298. if (frame.eventStrings.Length == 0)
  299. continue;
  300. var frameTime = GetTimeFromFrame(frames, frameIndex);
  301. var eventStrings = frame.eventStrings;
  302. for (var m = 0; m < eventStrings.Length; ++m)
  303. {
  304. events.Add(new AnimationEvent()
  305. {
  306. time = frameTime - startTime,
  307. functionName = eventStrings[m]
  308. });
  309. }
  310. }
  311. if (events.Count > 0)
  312. AnimationUtility.SetAnimationEvents(animationClip, events.ToArray());
  313. }
  314. }
  315. }