Açıklama Yok
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.

AnimationTrackExtensions.cs 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. using System;
  2. using System.Linq;
  3. using UnityEngine;
  4. using UnityEngine.Timeline;
  5. namespace UnityEditor.Timeline
  6. {
  7. /// <summary>
  8. /// Extension Methods for AnimationTracks that require the Unity Editor, and may require the Timeline containing the Animation Track to be currently loaded in the Timeline Editor Window.
  9. /// </summary>
  10. public static class AnimationTrackExtensions
  11. {
  12. /// <summary>
  13. /// Determines whether the Timeline window can enable recording mode on an AnimationTrack.
  14. /// For a track to support recording, it needs to have a valid scene binding,
  15. /// its offset mode should not be Auto and needs to be currently visible in the Timeline Window.
  16. /// </summary>
  17. /// <param name="track">The track to query.</param>
  18. /// <returns>True if recording can start, False otherwise.</returns>
  19. public static bool CanStartRecording(this AnimationTrack track)
  20. {
  21. if (track == null)
  22. {
  23. throw new ArgumentNullException(nameof(track));
  24. }
  25. if (TimelineEditor.state == null)
  26. {
  27. return false;
  28. }
  29. var director = TimelineEditor.inspectedDirector;
  30. var animTrack = TimelineUtility.GetSceneReferenceTrack(track) as AnimationTrack;
  31. return animTrack != null && animTrack.trackOffset != TrackOffset.Auto &&
  32. TimelineEditor.inspectedAsset == animTrack.timelineAsset &&
  33. director != null && TimelineUtility.GetSceneGameObject(director, animTrack) != null;
  34. }
  35. /// <summary>
  36. /// Method that allows querying if a track is current enabled for animation recording.
  37. /// </summary>
  38. /// <param name="track">The track to query.</param>
  39. /// <returns>True if currently recording and False otherwise.</returns>
  40. public static bool IsRecording(this AnimationTrack track)
  41. {
  42. if (track == null)
  43. {
  44. throw new ArgumentNullException(nameof(track));
  45. }
  46. return TimelineEditor.state != null && TimelineEditor.state.IsArmedForRecord(track);
  47. }
  48. /// <summary>
  49. /// Method that enables animation recording for an AnimationTrack.
  50. /// </summary>
  51. /// <param name="track">The AnimationTrack which will be put in recording mode.</param>
  52. /// <returns>True if track was put successfully in recording mode, False otherwise. </returns>
  53. public static bool StartRecording(this AnimationTrack track)
  54. {
  55. if (!CanStartRecording(track))
  56. {
  57. return false;
  58. }
  59. TimelineEditor.state.ArmForRecord(track);
  60. return true;
  61. }
  62. /// <summary>
  63. /// Disables recording mode of an AnimationTrack.
  64. /// </summary>
  65. /// <param name="track">The AnimationTrack which will be taken out of recording mode.</param>
  66. public static void StopRecording(this AnimationTrack track)
  67. {
  68. if (!IsRecording(track) || TimelineEditor.state == null)
  69. {
  70. return;
  71. }
  72. TimelineEditor.state.UnarmForRecord(track);
  73. }
  74. internal static void ConvertToClipMode(this AnimationTrack track)
  75. {
  76. if (!track.CanConvertToClipMode())
  77. return;
  78. UndoExtensions.RegisterTrack(track, L10n.Tr("Convert To Clip"));
  79. if (!track.infiniteClip.empty)
  80. {
  81. var animClip = track.infiniteClip;
  82. TimelineUndo.PushUndo(animClip, L10n.Tr("Convert To Clip"));
  83. UndoExtensions.RegisterTrack(track, L10n.Tr("Convert To Clip"));
  84. var start = AnimationClipCurveCache.Instance.GetCurveInfo(animClip).keyTimes.FirstOrDefault();
  85. animClip.ShiftBySeconds(-start);
  86. track.infiniteClip = null;
  87. var clip = track.CreateClip(animClip);
  88. clip.start = start;
  89. clip.preExtrapolationMode = track.infiniteClipPreExtrapolation;
  90. clip.postExtrapolationMode = track.infiniteClipPostExtrapolation;
  91. clip.recordable = true;
  92. if (Mathf.Abs(animClip.length) < TimelineClip.kMinDuration)
  93. {
  94. clip.duration = 1;
  95. }
  96. var animationAsset = clip.asset as AnimationPlayableAsset;
  97. if (animationAsset)
  98. {
  99. animationAsset.position = track.infiniteClipOffsetPosition;
  100. animationAsset.eulerAngles = track.infiniteClipOffsetEulerAngles;
  101. // going to / from infinite mode should reset this. infinite mode
  102. animationAsset.removeStartOffset = track.infiniteClipRemoveOffset;
  103. animationAsset.applyFootIK = track.infiniteClipApplyFootIK;
  104. animationAsset.loop = track.infiniteClipLoop;
  105. track.infiniteClipOffsetPosition = Vector3.zero;
  106. track.infiniteClipOffsetEulerAngles = Vector3.zero;
  107. }
  108. track.CalculateExtrapolationTimes();
  109. }
  110. track.infiniteClip = null;
  111. EditorUtility.SetDirty(track);
  112. }
  113. internal static void ConvertFromClipMode(this AnimationTrack track, TimelineAsset timeline)
  114. {
  115. if (!track.CanConvertFromClipMode())
  116. return;
  117. UndoExtensions.RegisterTrack(track, L10n.Tr("Convert From Clip"));
  118. var clip = track.clips[0];
  119. var delta = (float)clip.start;
  120. track.infiniteClipTimeOffset = 0.0f;
  121. track.infiniteClipPreExtrapolation = clip.preExtrapolationMode;
  122. track.infiniteClipPostExtrapolation = clip.postExtrapolationMode;
  123. var animAsset = clip.asset as AnimationPlayableAsset;
  124. if (animAsset)
  125. {
  126. track.infiniteClipOffsetPosition = animAsset.position;
  127. track.infiniteClipOffsetEulerAngles = animAsset.eulerAngles;
  128. track.infiniteClipRemoveOffset = animAsset.removeStartOffset;
  129. track.infiniteClipApplyFootIK = animAsset.applyFootIK;
  130. track.infiniteClipLoop = animAsset.loop;
  131. }
  132. // clone it, it may not be in the same asset
  133. var animClip = clip.animationClip;
  134. float scale = (float)clip.timeScale;
  135. if (!Mathf.Approximately(scale, 1.0f))
  136. {
  137. if (!Mathf.Approximately(scale, 0.0f))
  138. scale = 1.0f / scale;
  139. animClip.ScaleTime(scale);
  140. }
  141. TimelineUndo.PushUndo(animClip, L10n.Tr("Convert From Clip"));
  142. animClip.ShiftBySeconds(delta);
  143. // manually delete the clip
  144. var asset = clip.asset;
  145. clip.asset = null;
  146. // Remove the clip, remove old assets
  147. ClipModifier.Delete(timeline, clip);
  148. TimelineUndo.PushDestroyUndo(null, track, asset);
  149. track.infiniteClip = animClip;
  150. EditorUtility.SetDirty(track);
  151. }
  152. internal static bool CanConvertToClipMode(this AnimationTrack track)
  153. {
  154. if (track == null || track.inClipMode)
  155. return false;
  156. return (track.infiniteClip != null && !track.infiniteClip.empty);
  157. }
  158. // Requirements to go from clip mode
  159. // - one clip, recordable, and animation clip belongs to the same asset as the track
  160. internal static bool CanConvertFromClipMode(this AnimationTrack track)
  161. {
  162. if ((track == null) ||
  163. (!track.inClipMode) ||
  164. (track.clips.Length != 1) ||
  165. (track.clips[0].start < 0) ||
  166. (!track.clips[0].recordable))
  167. return false;
  168. var asset = track.clips[0].asset as AnimationPlayableAsset;
  169. if (asset == null)
  170. return false;
  171. return TimelineHelpers.HaveSameContainerAsset(track, asset.clip);
  172. }
  173. }
  174. }