DOTweenAnimationInspector.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. // Author: Daniele Giardini - http://www.demigiant.com
  2. // Created: 2015/03/12 16:03
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using DG.DemiEditor;
  7. using DG.DOTweenEditor.Core;
  8. using DG.Tweening;
  9. using DG.Tweening.Core;
  10. using UnityEditor;
  11. using UnityEngine;
  12. using UnityEngine.UI;
  13. #if DOTWEEN_TMP
  14. using TMPro;
  15. #endif
  16. namespace DG.DOTweenEditor
  17. {
  18. [CustomEditor(typeof(DOTweenAnimation))]
  19. public class DOTweenAnimationInspector : ABSAnimationInspector
  20. {
  21. static readonly Dictionary<DOTweenAnimationType, Type[]> _AnimationTypeToComponent = new Dictionary<DOTweenAnimationType, Type[]>() {
  22. { DOTweenAnimationType.Move, new[] { typeof(Rigidbody), typeof(Rigidbody2D), typeof(RectTransform), typeof(Transform) } },
  23. { DOTweenAnimationType.LocalMove, new[] { typeof(Transform) } },
  24. { DOTweenAnimationType.Rotate, new[] { typeof(Rigidbody), typeof(Rigidbody2D), typeof(Transform) } },
  25. { DOTweenAnimationType.LocalRotate, new[] { typeof(Transform) } },
  26. { DOTweenAnimationType.Scale, new[] { typeof(Transform) } },
  27. { DOTweenAnimationType.Color, new[] { typeof(SpriteRenderer), typeof(Renderer), typeof(Image), typeof(Text) } },
  28. { DOTweenAnimationType.Fade, new[] { typeof(SpriteRenderer), typeof(Renderer), typeof(Image), typeof(Text) } },
  29. { DOTweenAnimationType.Text, new[] { typeof(Text) } },
  30. { DOTweenAnimationType.PunchPosition, new[] { typeof(RectTransform), typeof(Transform) } },
  31. { DOTweenAnimationType.PunchRotation, new[] { typeof(Transform) } },
  32. { DOTweenAnimationType.PunchScale, new[] { typeof(Transform) } },
  33. { DOTweenAnimationType.ShakePosition, new[] { typeof(RectTransform), typeof(Transform) } },
  34. { DOTweenAnimationType.ShakeRotation, new[] { typeof(Transform) } },
  35. { DOTweenAnimationType.ShakeScale, new[] { typeof(Transform) } },
  36. { DOTweenAnimationType.CameraAspect, new[] { typeof(Camera) } },
  37. { DOTweenAnimationType.CameraBackgroundColor, new[] { typeof(Camera) } },
  38. { DOTweenAnimationType.CameraFieldOfView, new[] { typeof(Camera) } },
  39. { DOTweenAnimationType.CameraOrthoSize, new[] { typeof(Camera) } },
  40. { DOTweenAnimationType.CameraPixelRect, new[] { typeof(Camera) } },
  41. { DOTweenAnimationType.CameraRect, new[] { typeof(Camera) } },
  42. };
  43. #if DOTWEEN_TK2D
  44. static readonly Dictionary<DOTweenAnimationType, Type[]> _Tk2dAnimationTypeToComponent = new Dictionary<DOTweenAnimationType, Type[]>() {
  45. { DOTweenAnimationType.Color, new[] { typeof(tk2dBaseSprite), typeof(tk2dTextMesh) } },
  46. { DOTweenAnimationType.Fade, new[] { typeof(tk2dBaseSprite), typeof(tk2dTextMesh) } },
  47. { DOTweenAnimationType.Text, new[] { typeof(tk2dTextMesh) } }
  48. };
  49. #endif
  50. #if DOTWEEN_TMP
  51. static readonly Dictionary<DOTweenAnimationType, Type[]> _TMPAnimationTypeToComponent = new Dictionary<DOTweenAnimationType, Type[]>() {
  52. { DOTweenAnimationType.Color, new[] { typeof(TextMeshPro), typeof(TextMeshProUGUI) } },
  53. { DOTweenAnimationType.Fade, new[] { typeof(TextMeshPro), typeof(TextMeshProUGUI) } },
  54. { DOTweenAnimationType.Text, new[] { typeof(TextMeshPro), typeof(TextMeshProUGUI) } }
  55. };
  56. #endif
  57. static readonly string[] _AnimationType = new[] {
  58. "None",
  59. "Move", "LocalMove",
  60. "Rotate", "LocalRotate",
  61. "Scale",
  62. "Color", "Fade",
  63. "Text",
  64. "Punch/Position", "Punch/Rotation", "Punch/Scale",
  65. "Shake/Position", "Shake/Rotation", "Shake/Scale",
  66. "Camera/Aspect", "Camera/BackgroundColor", "Camera/FieldOfView", "Camera/OrthoSize", "Camera/PixelRect", "Camera/Rect"
  67. };
  68. static string[] _animationTypeNoSlashes; // _AnimationType list without slashes in values
  69. static string[] _datString; // String representation of DOTweenAnimation enum (here for caching reasons)
  70. DOTweenAnimation _src;
  71. bool _runtimeEditMode; // If TRUE allows to change and save stuff at runtime
  72. int _totComponentsOnSrc; // Used to determine if a Component is added or removed from the source
  73. // ===================================================================================
  74. // MONOBEHAVIOUR METHODS -------------------------------------------------------------
  75. void OnEnable()
  76. {
  77. _src = target as DOTweenAnimation;
  78. onStartProperty = base.serializedObject.FindProperty("onStart");
  79. onPlayProperty = base.serializedObject.FindProperty("onPlay");
  80. onUpdateProperty = base.serializedObject.FindProperty("onUpdate");
  81. onStepCompleteProperty = base.serializedObject.FindProperty("onStepComplete");
  82. onCompleteProperty = base.serializedObject.FindProperty("onComplete");
  83. // Convert _AnimationType to _animationTypeNoSlashes
  84. int len = _AnimationType.Length;
  85. _animationTypeNoSlashes = new string[len];
  86. for (int i = 0; i < len; ++i) {
  87. string a = _AnimationType[i];
  88. a = a.Replace("/", "");
  89. _animationTypeNoSlashes[i] = a;
  90. }
  91. }
  92. override public void OnInspectorGUI()
  93. {
  94. base.OnInspectorGUI();
  95. GUILayout.Space(3);
  96. EditorGUIUtils.SetGUIStyles();
  97. bool playMode = Application.isPlaying;
  98. _runtimeEditMode = _runtimeEditMode && playMode;
  99. GUILayout.BeginHorizontal();
  100. EditorGUIUtils.InspectorLogo();
  101. GUILayout.Label(_src.animationType.ToString() + (string.IsNullOrEmpty(_src.id) ? "" : " [" + _src.id + "]"), EditorGUIUtils.sideLogoIconBoldLabelStyle);
  102. // Up-down buttons
  103. GUILayout.FlexibleSpace();
  104. if (GUILayout.Button("▲", DeGUI.styles.button.toolIco)) UnityEditorInternal.ComponentUtility.MoveComponentUp(_src);
  105. if (GUILayout.Button("▼", DeGUI.styles.button.toolIco)) UnityEditorInternal.ComponentUtility.MoveComponentDown(_src);
  106. GUILayout.EndHorizontal();
  107. if (playMode) {
  108. if (_runtimeEditMode) {
  109. } else {
  110. GUILayout.Space(8);
  111. GUILayout.Label("Animation Editor disabled while in play mode", EditorGUIUtils.wordWrapLabelStyle);
  112. if (!_src.isActive) {
  113. GUILayout.Label("This animation has been toggled as inactive and won't be generated", EditorGUIUtils.wordWrapLabelStyle);
  114. GUI.enabled = false;
  115. }
  116. if (GUILayout.Button(new GUIContent("Activate Edit Mode", "Switches to Runtime Edit Mode, where you can change animations values and restart them"))) {
  117. _runtimeEditMode = true;
  118. }
  119. GUILayout.Label("NOTE: when using DOPlayNext, the sequence is determined by the DOTweenAnimation Components order in the target GameObject's Inspector", EditorGUIUtils.wordWrapLabelStyle);
  120. GUILayout.Space(10);
  121. if (!_runtimeEditMode) return;
  122. }
  123. }
  124. Undo.RecordObject(_src, "DOTween Animation");
  125. // _src.isValid = Validate(); // Moved down
  126. EditorGUIUtility.labelWidth = 120;
  127. if (playMode) {
  128. GUILayout.Space(4);
  129. DeGUILayout.Toolbar("Edit Mode Commands");
  130. DeGUILayout.BeginVBox(DeGUI.styles.box.stickyTop);
  131. GUILayout.BeginHorizontal();
  132. if (GUILayout.Button("TogglePause")) _src.tween.TogglePause();
  133. if (GUILayout.Button("Rewind")) _src.tween.Rewind();
  134. if (GUILayout.Button("Restart")) _src.tween.Restart();
  135. GUILayout.EndHorizontal();
  136. if (GUILayout.Button("Commit changes and restart")) {
  137. _src.tween.Rewind();
  138. _src.tween.Kill();
  139. if (_src.isValid) {
  140. _src.CreateTween();
  141. _src.tween.Play();
  142. }
  143. }
  144. GUILayout.Label("To apply your changes when exiting Play mode, use the Component's upper right menu and choose \"Copy Component\", then \"Paste Component Values\" after exiting Play mode", DeGUI.styles.label.wordwrap);
  145. DeGUILayout.EndVBox();
  146. } else {
  147. bool hasManager = _src.GetComponent<DOTweenVisualManager>() != null;
  148. if (!hasManager) {
  149. if (GUILayout.Button(new GUIContent("Add Manager", "Adds a manager component which allows you to choose additional options for this gameObject"))) {
  150. _src.gameObject.AddComponent<DOTweenVisualManager>();
  151. }
  152. }
  153. }
  154. GUILayout.BeginHorizontal();
  155. DOTweenAnimationType prevAnimType = _src.animationType;
  156. // _src.animationType = (DOTweenAnimationType)EditorGUILayout.EnumPopup(_src.animationType, EditorGUIUtils.popupButton);
  157. _src.isActive = EditorGUILayout.Toggle(new GUIContent("", "If unchecked, this animation will not be created"), _src.isActive, GUILayout.Width(16));
  158. GUI.enabled = _src.isActive;
  159. _src.animationType = AnimationToDOTweenAnimationType(_AnimationType[EditorGUILayout.Popup(DOTweenAnimationTypeToPopupId(_src.animationType), _AnimationType)]);
  160. _src.autoPlay = DeGUILayout.ToggleButton(_src.autoPlay, new GUIContent("AutoPlay", "If selected, the tween will play automatically"));
  161. _src.autoKill = DeGUILayout.ToggleButton(_src.autoKill, new GUIContent("AutoKill", "If selected, the tween will be killed when it completes, and won't be reusable"));
  162. GUILayout.EndHorizontal();
  163. if (prevAnimType != _src.animationType) {
  164. // Set default optional values based on animation type
  165. switch (_src.animationType) {
  166. case DOTweenAnimationType.Move:
  167. case DOTweenAnimationType.LocalMove:
  168. case DOTweenAnimationType.Rotate:
  169. case DOTweenAnimationType.LocalRotate:
  170. case DOTweenAnimationType.Scale:
  171. _src.endValueV3 = Vector3.zero;
  172. _src.endValueFloat = 0;
  173. _src.optionalBool0 = _src.animationType == DOTweenAnimationType.Scale;
  174. break;
  175. case DOTweenAnimationType.Color:
  176. case DOTweenAnimationType.Fade:
  177. _src.endValueFloat = 0;
  178. break;
  179. case DOTweenAnimationType.Text:
  180. _src.optionalBool0 = true;
  181. break;
  182. case DOTweenAnimationType.PunchPosition:
  183. case DOTweenAnimationType.PunchRotation:
  184. case DOTweenAnimationType.PunchScale:
  185. _src.endValueV3 = _src.animationType == DOTweenAnimationType.PunchRotation ? new Vector3(0,180,0) : Vector3.one;
  186. _src.optionalFloat0 = 1;
  187. _src.optionalInt0 = 10;
  188. _src.optionalBool0 = false;
  189. break;
  190. case DOTweenAnimationType.ShakePosition:
  191. case DOTweenAnimationType.ShakeRotation:
  192. case DOTweenAnimationType.ShakeScale:
  193. _src.endValueV3 = _src.animationType == DOTweenAnimationType.ShakeRotation ? new Vector3(90,90,90) : Vector3.one;
  194. _src.optionalInt0 = 10;
  195. _src.optionalFloat0 = 90;
  196. _src.optionalBool0 = false;
  197. break;
  198. case DOTweenAnimationType.CameraAspect:
  199. case DOTweenAnimationType.CameraFieldOfView:
  200. case DOTweenAnimationType.CameraOrthoSize:
  201. _src.endValueFloat = 0;
  202. break;
  203. case DOTweenAnimationType.CameraPixelRect:
  204. case DOTweenAnimationType.CameraRect:
  205. _src.endValueRect = new Rect(0, 0, 0, 0);
  206. break;
  207. }
  208. }
  209. if (_src.animationType == DOTweenAnimationType.None) {
  210. _src.isValid = false;
  211. if (GUI.changed) EditorUtility.SetDirty(_src);
  212. return;
  213. }
  214. if (prevAnimType != _src.animationType || ComponentsChanged()) {
  215. _src.isValid = Validate();
  216. }
  217. if (!_src.isValid) {
  218. GUI.color = Color.red;
  219. GUILayout.BeginVertical(GUI.skin.box);
  220. GUILayout.Label("No valid Component was found for the selected animation", EditorGUIUtils.wordWrapLabelStyle);
  221. GUILayout.EndVertical();
  222. GUI.color = Color.white;
  223. if (GUI.changed) EditorUtility.SetDirty(_src);
  224. return;
  225. }
  226. _src.duration = EditorGUILayout.FloatField("Duration", _src.duration);
  227. if (_src.duration < 0) _src.duration = 0;
  228. _src.delay = EditorGUILayout.FloatField("Delay", _src.delay);
  229. if (_src.delay < 0) _src.delay = 0;
  230. _src.isIndependentUpdate = EditorGUILayout.Toggle("Ignore TimeScale", _src.isIndependentUpdate);
  231. _src.easeType = EditorGUIUtils.FilteredEasePopup(_src.easeType);
  232. if (_src.easeType == Ease.INTERNAL_Custom) {
  233. _src.easeCurve = EditorGUILayout.CurveField(" Ease Curve", _src.easeCurve);
  234. }
  235. _src.loops = EditorGUILayout.IntField(new GUIContent("Loops", "Set to -1 for infinite loops"), _src.loops);
  236. if (_src.loops < -1) _src.loops = -1;
  237. if (_src.loops > 1 || _src.loops == -1)
  238. _src.loopType = (LoopType)EditorGUILayout.EnumPopup(" Loop Type", _src.loopType);
  239. _src.id = EditorGUILayout.TextField("ID", _src.id);
  240. bool canBeRelative = true;
  241. // End value and eventual specific options
  242. switch (_src.animationType) {
  243. case DOTweenAnimationType.Move:
  244. case DOTweenAnimationType.LocalMove:
  245. GUIEndValueV3();
  246. _src.optionalBool0 = EditorGUILayout.Toggle(" Snapping", _src.optionalBool0);
  247. break;
  248. case DOTweenAnimationType.Rotate:
  249. case DOTweenAnimationType.LocalRotate:
  250. if (_src.GetComponent<Rigidbody2D>()) GUIEndValueFloat();
  251. else {
  252. GUIEndValueV3();
  253. _src.optionalRotationMode = (RotateMode)EditorGUILayout.EnumPopup(" Rotation Mode", _src.optionalRotationMode);
  254. }
  255. break;
  256. case DOTweenAnimationType.Scale:
  257. if (_src.optionalBool0) GUIEndValueFloat();
  258. else GUIEndValueV3();
  259. _src.optionalBool0 = EditorGUILayout.Toggle("Uniform Scale", _src.optionalBool0);
  260. break;
  261. case DOTweenAnimationType.Color:
  262. GUIEndValueColor();
  263. canBeRelative = false;
  264. break;
  265. case DOTweenAnimationType.Fade:
  266. GUIEndValueFloat();
  267. if (_src.endValueFloat < 0) _src.endValueFloat = 0;
  268. if (_src.endValueFloat > 1) _src.endValueFloat = 1;
  269. canBeRelative = false;
  270. break;
  271. case DOTweenAnimationType.Text:
  272. GUIEndValueString();
  273. _src.optionalBool0 = EditorGUILayout.Toggle("Rich Text Enabled", _src.optionalBool0);
  274. _src.optionalScrambleMode = (ScrambleMode)EditorGUILayout.EnumPopup("Scramble Mode", _src.optionalScrambleMode);
  275. _src.optionalString = EditorGUILayout.TextField(new GUIContent("Custom Scramble", "Custom characters to use in case of ScrambleMode.Custom"), _src.optionalString);
  276. break;
  277. case DOTweenAnimationType.PunchPosition:
  278. case DOTweenAnimationType.PunchRotation:
  279. case DOTweenAnimationType.PunchScale:
  280. GUIEndValueV3();
  281. canBeRelative = false;
  282. _src.optionalInt0 = EditorGUILayout.IntSlider(new GUIContent(" Vibrato", "How much will the punch vibrate"), _src.optionalInt0, 1, 50);
  283. _src.optionalFloat0 = EditorGUILayout.Slider(new GUIContent(" Elasticity", "How much the vector will go beyond the starting position when bouncing backwards"), _src.optionalFloat0, 0, 1);
  284. if (_src.animationType == DOTweenAnimationType.PunchPosition) _src.optionalBool0 = EditorGUILayout.Toggle(" Snapping", _src.optionalBool0);
  285. break;
  286. case DOTweenAnimationType.ShakePosition:
  287. case DOTweenAnimationType.ShakeRotation:
  288. case DOTweenAnimationType.ShakeScale:
  289. GUIEndValueV3();
  290. canBeRelative = false;
  291. _src.optionalInt0 = EditorGUILayout.IntSlider(new GUIContent(" Vibrato", "How much will the shake vibrate"), _src.optionalInt0, 1, 50);
  292. _src.optionalFloat0 = EditorGUILayout.Slider(new GUIContent(" Randomness", "The shake randomness"), _src.optionalFloat0, 0, 90);
  293. if (_src.animationType == DOTweenAnimationType.ShakePosition) _src.optionalBool0 = EditorGUILayout.Toggle(" Snapping", _src.optionalBool0);
  294. break;
  295. case DOTweenAnimationType.CameraAspect:
  296. case DOTweenAnimationType.CameraFieldOfView:
  297. case DOTweenAnimationType.CameraOrthoSize:
  298. GUIEndValueFloat();
  299. canBeRelative = false;
  300. break;
  301. case DOTweenAnimationType.CameraBackgroundColor:
  302. GUIEndValueColor();
  303. canBeRelative = false;
  304. break;
  305. case DOTweenAnimationType.CameraPixelRect:
  306. case DOTweenAnimationType.CameraRect:
  307. GUIEndValueRect();
  308. canBeRelative = false;
  309. break;
  310. }
  311. // Final settings
  312. if (canBeRelative) _src.isRelative = EditorGUILayout.Toggle(" Relative", _src.isRelative);
  313. // Events
  314. AnimationInspectorGUI.AnimationEvents(this, _src);
  315. if (GUI.changed) EditorUtility.SetDirty(_src);
  316. }
  317. // Returns TRUE if the Component layout on the src gameObject changed (a Component was added or removed)
  318. bool ComponentsChanged()
  319. {
  320. int prevTotComponentsOnSrc = _totComponentsOnSrc;
  321. _totComponentsOnSrc = _src.gameObject.GetComponents<Component>().Length;
  322. return prevTotComponentsOnSrc != _totComponentsOnSrc;
  323. }
  324. // Checks if a Component that can be animated with the given animationType is attached to the src
  325. bool Validate()
  326. {
  327. if (_src.animationType == DOTweenAnimationType.None) return false;
  328. Component srcTarget;
  329. // First check for external plugins
  330. #if DOTWEEN_TK2D
  331. if (_Tk2dAnimationTypeToComponent.ContainsKey(_src.animationType)) {
  332. foreach (Type t in _Tk2dAnimationTypeToComponent[_src.animationType]) {
  333. srcTarget = _src.GetComponent(t);
  334. if (srcTarget != null) {
  335. _src.target = srcTarget;
  336. return true;
  337. }
  338. }
  339. }
  340. #endif
  341. #if DOTWEEN_TMP
  342. if (_TMPAnimationTypeToComponent.ContainsKey(_src.animationType)) {
  343. foreach (Type t in _TMPAnimationTypeToComponent[_src.animationType]) {
  344. srcTarget = _src.GetComponent(t);
  345. if (srcTarget != null) {
  346. _src.target = srcTarget;
  347. return true;
  348. }
  349. }
  350. }
  351. #endif
  352. // Then check for regular stuff
  353. if (_AnimationTypeToComponent.ContainsKey(_src.animationType)) {
  354. foreach (Type t in _AnimationTypeToComponent[_src.animationType]) {
  355. srcTarget = _src.GetComponent(t);
  356. if (srcTarget != null) {
  357. _src.target = srcTarget;
  358. return true;
  359. }
  360. }
  361. }
  362. return false;
  363. }
  364. DOTweenAnimationType AnimationToDOTweenAnimationType(string animation)
  365. {
  366. if (_datString == null) _datString = Enum.GetNames(typeof(DOTweenAnimationType));
  367. animation = animation.Replace("/", "");
  368. return (DOTweenAnimationType)(Array.IndexOf(_datString, animation));
  369. }
  370. int DOTweenAnimationTypeToPopupId(DOTweenAnimationType animation)
  371. {
  372. return Array.IndexOf(_animationTypeNoSlashes, animation.ToString());
  373. }
  374. void GUIEndValueFloat()
  375. {
  376. GUILayout.BeginHorizontal();
  377. GUIToFromButton();
  378. _src.endValueFloat = EditorGUILayout.FloatField(_src.endValueFloat);
  379. GUILayout.EndHorizontal();
  380. }
  381. void GUIEndValueColor()
  382. {
  383. GUILayout.BeginHorizontal();
  384. GUIToFromButton();
  385. _src.endValueColor = EditorGUILayout.ColorField(_src.endValueColor);
  386. GUILayout.EndHorizontal();
  387. }
  388. void GUIEndValueV3()
  389. {
  390. GUILayout.BeginHorizontal();
  391. GUIToFromButton();
  392. _src.endValueV3 = EditorGUILayout.Vector3Field("", _src.endValueV3, GUILayout.Height(16));
  393. GUILayout.EndHorizontal();
  394. }
  395. void GUIEndValueString()
  396. {
  397. GUILayout.BeginHorizontal();
  398. GUIToFromButton();
  399. _src.endValueString = EditorGUILayout.TextArea(_src.endValueString, EditorGUIUtils.wordWrapTextArea);
  400. GUILayout.EndHorizontal();
  401. }
  402. void GUIEndValueRect()
  403. {
  404. GUILayout.BeginHorizontal();
  405. GUIToFromButton();
  406. _src.endValueRect = EditorGUILayout.RectField(_src.endValueRect);
  407. GUILayout.EndHorizontal();
  408. }
  409. void GUIToFromButton()
  410. {
  411. if (GUILayout.Button(_src.isFrom ? "FROM" : "TO", EditorGUIUtils.sideBtStyle, GUILayout.Width(100))) _src.isFrom = !_src.isFrom;
  412. GUILayout.Space(16);
  413. }
  414. }
  415. }