TimelineEditor.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. using UnityEditor;
  2. using UnityEngine;
  3. using System.Linq;
  4. namespace Chronos
  5. {
  6. [CustomEditor(typeof(Timeline)), CanEditMultipleObjects]
  7. public class TimelineEditor : Editor
  8. {
  9. protected SerializedProperty mode;
  10. protected SerializedProperty globalClockKey;
  11. protected SerializedProperty rewindable;
  12. protected SerializedProperty recordingDuration;
  13. protected SerializedProperty recordingInterval;
  14. public void OnEnable()
  15. {
  16. mode = serializedObject.FindProperty("_mode");
  17. globalClockKey = serializedObject.FindProperty("_globalClockKey");
  18. rewindable = serializedObject.FindProperty("_rewindable");
  19. recordingDuration = serializedObject.FindProperty("_recordingDuration");
  20. recordingInterval = serializedObject.FindProperty("_recordingInterval");
  21. }
  22. public override void OnInspectorGUI()
  23. {
  24. serializedObject.Update();
  25. EditorGUILayout.PropertyField(mode, new GUIContent("Mode"));
  26. if (!mode.hasMultipleDifferentValues)
  27. {
  28. if (mode.enumValueIndex == (int)TimelineMode.Local)
  29. {
  30. if (!serializedObject.isEditingMultipleObjects)
  31. {
  32. Timeline timeline = (Timeline)serializedObject.targetObject;
  33. LocalClock localClock = timeline.GetComponent<LocalClock>();
  34. if (localClock == null || !localClock.enabled)
  35. {
  36. EditorGUILayout.HelpBox("A local timeline requires a local clock.", MessageType.Error);
  37. }
  38. }
  39. }
  40. else if (mode.enumValueIndex == (int)TimelineMode.Global)
  41. {
  42. EditorGUILayout.PropertyField(globalClockKey, new GUIContent("Global Clock"));
  43. if (!globalClockKey.hasMultipleDifferentValues &&
  44. string.IsNullOrEmpty(globalClockKey.stringValue))
  45. {
  46. EditorGUILayout.HelpBox("A global timeline requires a global clock reference.", MessageType.Error);
  47. }
  48. }
  49. else
  50. {
  51. EditorGUILayout.HelpBox("Unsupported timeline mode.", MessageType.Error);
  52. }
  53. }
  54. bool anyRewindable = serializedObject.targetObjects.OfType<Timeline>().Any(t => t.rewindable);
  55. EditorGUI.BeginDisabledGroup(Application.isPlaying);
  56. {
  57. EditorGUILayout.PropertyField(rewindable, new GUIContent("Rewindable"));
  58. if (anyRewindable)
  59. {
  60. EditorGUILayout.PropertyField(recordingDuration, new GUIContent("Recording Duration"));
  61. EditorGUILayout.PropertyField(recordingInterval, new GUIContent("Recording Interval"));
  62. }
  63. }
  64. EditorGUI.EndDisabledGroup();
  65. if (anyRewindable)
  66. {
  67. float estimate = serializedObject.targetObjects.OfType<Timeline>().Select(t => t.EstimateMemoryUsage()).Sum() / 1024;
  68. string summary;
  69. if (!recordingDuration.hasMultipleDifferentValues &&
  70. !recordingInterval.hasMultipleDifferentValues)
  71. {
  72. summary = string.Format("Rewind for up to {0:0.#} {1} at a {2:0.#} {3} per second precision.\n\nEstimated memory: {4} KiB.",
  73. recordingDuration.floatValue,
  74. recordingDuration.floatValue >= 2 ? "seconds" : "second",
  75. (1 / recordingInterval.floatValue),
  76. (1 / recordingInterval.floatValue) >= 2 ? "snapshots" : "snapshot",
  77. estimate);
  78. }
  79. else
  80. {
  81. summary = string.Format("Estimated memory: {0} KiB.", estimate);
  82. }
  83. EditorGUILayout.HelpBox(summary, MessageType.Info);
  84. }
  85. if (!serializedObject.isEditingMultipleObjects)
  86. {
  87. Timeline timeline = ((Timeline)serializedObject.targetObject);
  88. ParticleSystem particleSystem = timeline.GetComponent<ParticleSystem>();
  89. if (particleSystem != null && timeline.rewindable)
  90. {
  91. if (particleSystem.main.simulationSpace == ParticleSystemSimulationSpace.World)
  92. {
  93. EditorGUILayout.HelpBox("World simulation is incompatible with rewindable particle systems.", MessageType.Warning);
  94. }
  95. bool sendCollisionMessage = false; // Unity API doesn't seem to provide a way to check this.
  96. if (sendCollisionMessage)
  97. {
  98. EditorGUILayout.HelpBox("Collision messages are incompatible with rewindable particle systems.", MessageType.Warning);
  99. }
  100. }
  101. }
  102. if (!serializedObject.isEditingMultipleObjects &&
  103. Application.isPlaying)
  104. {
  105. Timeline timeline = (Timeline)serializedObject.targetObject;
  106. EditorGUILayout.LabelField("Computed Time Scale", timeline.timeScale.ToString("0.00"));
  107. EditorGUILayout.LabelField("Computed Time", timeline.time.ToString("0.00"));
  108. }
  109. serializedObject.ApplyModifiedProperties();
  110. }
  111. }
  112. }