diff --git a/CHANGELOG.MD b/CHANGELOG.MD index b4000ef..bf06afe 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## [0.5.0] +### Changed +- Added support to control AnimationSequencer though regular unity animations, in both runtime / playtime +- Fixed issue with color tweens no working on the editor > 2021 +- Added a settings menu on `Edit/Preferences/AnimationSequencer` +- You can now disable the auto foldout of the steps while previewing on the Settings + ## [0.4.0] ### Changed - Fixed Unity 2020 compability @@ -185,6 +192,7 @@ Thanks for all the [suggestions](https://github.com/brunomikoski/Animation-Seque ### Added - First initial working version +[0.5.0]: https://github.com/brunomikoski/Animation-Sequencer/releases/tag/v0.5.0 [0.4.0]: https://github.com/brunomikoski/Animation-Sequencer/releases/tag/v0.4.0 [0.3.9]: https://github.com/brunomikoski/Animation-Sequencer/releases/tag/v0.3.9 [0.3.8]: https://github.com/brunomikoski/Animation-Sequencer/releases/tag/v0.3.8 diff --git a/Scripts/Editor/Core/AnimationSequencerControllerCustomEditor.cs b/Scripts/Editor/Core/AnimationSequencerControllerCustomEditor.cs index a4e9cc1..1d2e6e5 100644 --- a/Scripts/Editor/Core/AnimationSequencerControllerCustomEditor.cs +++ b/Scripts/Editor/Core/AnimationSequencerControllerCustomEditor.cs @@ -45,6 +45,7 @@ private void OnEnable() reorderableList.onRemoveCallback += OnClickToRemove; reorderableList.onReorderCallback += OnListOrderChanged; reorderableList.drawHeaderCallback += OnDrawerHeader; + EditorApplication.update += EditorUpdate; EditorApplication.playModeStateChanged += OnEditorPlayModeChanged; #if UNITY_2021_1_OR_NEWER @@ -56,6 +57,8 @@ private void OnEnable() Repaint(); } + + public override bool RequiresConstantRepaint() { return true; @@ -70,6 +73,8 @@ private void OnDisable() reorderableList.onReorderCallback -= OnListOrderChanged; reorderableList.drawHeaderCallback -= OnDrawerHeader; EditorApplication.playModeStateChanged -= OnEditorPlayModeChanged; + EditorApplication.update -= EditorUpdate; + #if UNITY_2021_1_OR_NEWER UnityEditor.SceneManagement.PrefabStage.prefabSaving -= PrefabSaving; #else @@ -88,6 +93,18 @@ private void OnDisable() tweenTimeScale = 1f; } + private void EditorUpdate() + { + if (Application.isPlaying) + return; + + SerializedProperty progressSP = serializedObject.FindProperty("progress"); + if (Mathf.Approximately(progressSP.floatValue, -1)) + return; + + SetProgress(progressSP.floatValue); + } + private void OnEditorPlayModeChanged(PlayModeStateChange playModeState) { if (playModeState == PlayModeStateChange.ExitingEditMode) @@ -206,36 +223,15 @@ protected virtual void DrawCallbacks() private void DrawSettings() { SerializedProperty autoPlayModeSerializedProperty = serializedObject.FindProperty("autoplayMode"); - SerializedProperty playOnAwakeSerializedProperty = serializedObject.FindProperty("playOnAwake"); - SerializedProperty pauseOnAwakeSerializedProperty = serializedObject.FindProperty("pauseOnAwake"); + SerializedProperty pauseOnAwakeSerializedProperty = serializedObject.FindProperty("startPaused"); using (EditorGUI.ChangeCheckScope changedCheck = new EditorGUI.ChangeCheckScope()) { - var autoplayMode = (AnimationSequencerController.AutoplayType)autoPlayModeSerializedProperty.enumValueIndex; + AnimationSequencerController.AutoplayType autoplayMode = (AnimationSequencerController.AutoplayType)autoPlayModeSerializedProperty.enumValueIndex; EditorGUILayout.PropertyField(autoPlayModeSerializedProperty); - string playOnAwakeLabel = null; - string pauseOnAwakeLabel = null; - switch(autoplayMode) - { - case AnimationSequencerController.AutoplayType.Awake: - playOnAwakeLabel = "Play On Awake"; - pauseOnAwakeLabel = "Pause On Awake"; - break; - - case AnimationSequencerController.AutoplayType.OnEnable: - playOnAwakeLabel = "Play On Enable"; - pauseOnAwakeLabel = "Pause On Enable"; - break; - - default: - Debug.LogError($"Unhandled AutoplayType {autoplayMode}"); - break; - } - - EditorGUILayout.PropertyField(playOnAwakeSerializedProperty, new GUIContent(playOnAwakeLabel)); - if (playOnAwakeSerializedProperty.boolValue) - EditorGUILayout.PropertyField(pauseOnAwakeSerializedProperty, new GUIContent(pauseOnAwakeLabel)); + if (autoplayMode != AnimationSequencerController.AutoplayType.Nothing) + EditorGUILayout.PropertyField(pauseOnAwakeSerializedProperty); DrawPlaybackSpeedSlider(); @@ -452,7 +448,7 @@ private void PlaySequence() } wasShowingStepsPanel = showStepsPanel; - showStepsPanel = false; + showStepsPanel = !AnimationSequencerSettings.GetInstance().AutoHideStepsWhenPreviewing; } private void DrawProgressSlider() @@ -469,16 +465,21 @@ private void DrawProgressSlider() if (EditorGUI.EndChangeCheck()) { - if(!sequencerController.IsPlaying) - PlaySequence(); - - sequencerController.PlayingSequence.Goto(tweenProgress * - sequencerController.PlayingSequence.Duration()); + SetProgress(tweenProgress); } GUILayout.FlexibleSpace(); } + private void SetProgress(float tweenProgress) + { + if (!sequencerController.IsPlaying) + PlaySequence(); + + sequencerController.PlayingSequence.Goto(tweenProgress * + sequencerController.PlayingSequence.Duration()); + } + private float GetCurrentSequencerProgress() { float tweenProgress; @@ -572,7 +573,7 @@ private void DuplicateItem(int index) ContextClickUtils.CopyPropertyValue(sourceSerializedProperty, source); source.serializedObject.ApplyModifiedProperties(); } - + private void DrawContextInputOnItem(SerializedProperty element, int index, Rect rect1) { rect1.x -= 24; diff --git a/Scripts/Editor/Core/AnimationSequencerSettings.cs b/Scripts/Editor/Core/AnimationSequencerSettings.cs new file mode 100644 index 0000000..901711a --- /dev/null +++ b/Scripts/Editor/Core/AnimationSequencerSettings.cs @@ -0,0 +1,18 @@ +using UnityEditor; +using UnityEngine; + +namespace BrunoMikoski.AnimationSequencer +{ + public sealed class AnimationSequencerSettings : ScriptableObjectForPreferences + { + [SerializeField] + private bool autoHideStepsWhenPreviewing = true; + public bool AutoHideStepsWhenPreviewing => autoHideStepsWhenPreviewing; + + [SettingsProvider] + private static SettingsProvider SettingsProvider() + { + return CreateSettingsProvider("Animation Sequencer", null); + } + } +} diff --git a/Scripts/Editor/Core/AnimationSequencerSettings.cs.meta b/Scripts/Editor/Core/AnimationSequencerSettings.cs.meta new file mode 100644 index 0000000..77f27f0 --- /dev/null +++ b/Scripts/Editor/Core/AnimationSequencerSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e3a6b363871842658d8fbe8d6348611c +timeCreated: 1663765620 \ No newline at end of file diff --git a/Scripts/Editor/Utility/ScriptableObjectForPreferences.cs b/Scripts/Editor/Utility/ScriptableObjectForPreferences.cs new file mode 100644 index 0000000..3e13715 --- /dev/null +++ b/Scripts/Editor/Utility/ScriptableObjectForPreferences.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace BrunoMikoski.AnimationSequencer +{ + //From https://github.com/baba-s/UniScriptableObjectForPreferences/blob/master/Editor/ScriptableObjectForPreferences.cs + public abstract class ScriptableObjectForPreferences : ScriptableObject + where T : ScriptableObjectForPreferences + { + private static string ConfigName => typeof(T).Name; + private static T instance; + + public static T GetInstance() + { + if (instance != null) + { + return instance; + } + + instance = CreateInstance(); + string json = EditorUserSettings.GetConfigValue(ConfigName); + EditorJsonUtility.FromJsonOverwrite(json, instance); + if (instance == null) + { + instance = CreateInstance(); + } + + return instance; + } + + public static SettingsProvider CreateSettingsProvider( + string settingsProviderPath = null, + Action onGUI = null, + Action onGUIExtra = null + ) + { + if (settingsProviderPath == null) + { + settingsProviderPath = $"{typeof(T).Name}"; + } + + T foundInstance = GetInstance(); + SerializedObject serializedObject = new SerializedObject(foundInstance); + IEnumerable keywords = SettingsProvider.GetSearchKeywordsFromSerializedObject(serializedObject); + SettingsProvider provider = new SettingsProvider(settingsProviderPath, SettingsScope.User, keywords); + provider.guiHandler += _ => OnGuiHandler(onGUI, onGUIExtra); + return provider; + } + + private static void OnGuiHandler(Action onGUI, + Action onGUIExtra) + { + T foundInstance = GetInstance(); + Editor editor = Editor.CreateEditor(foundInstance); + using (EditorGUI.ChangeCheckScope scope = new EditorGUI.ChangeCheckScope()) + { + SerializedObject serializedObject = editor.serializedObject; + serializedObject.Update(); + if (onGUI != null) + { + onGUI(serializedObject); + } + else + { + editor.DrawDefaultInspector(); + } + + onGUIExtra?.Invoke(serializedObject); + if (!scope.changed) + { + return; + } + + serializedObject.ApplyModifiedProperties(); + string json = EditorJsonUtility.ToJson(editor.target); + EditorUserSettings.SetConfigValue(ConfigName, json); + } + } + } +} diff --git a/Scripts/Editor/Utility/ScriptableObjectForPreferences.cs.meta b/Scripts/Editor/Utility/ScriptableObjectForPreferences.cs.meta new file mode 100644 index 0000000..bf66464 --- /dev/null +++ b/Scripts/Editor/Utility/ScriptableObjectForPreferences.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 43e853692c4d4b03a749c094b983417d +timeCreated: 1663765550 \ No newline at end of file diff --git a/Scripts/Runtime/Core/AnimationSequencerController.cs b/Scripts/Runtime/Core/AnimationSequencerController.cs index e586758..8eddfbb 100644 --- a/Scripts/Runtime/Core/AnimationSequencerController.cs +++ b/Scripts/Runtime/Core/AnimationSequencerController.cs @@ -22,7 +22,8 @@ public enum PlayType public enum AutoplayType { Awake, - OnEnable + OnEnable, + Nothing } [SerializeReference] @@ -34,9 +35,7 @@ public enum AutoplayType [SerializeField] private AutoplayType autoplayMode = AutoplayType.Awake; [SerializeField] - protected bool playOnAwake; - [SerializeField] - protected bool pauseOnAwake; + protected bool startPaused; [SerializeField] private float playbackSpeed = 1f; public float PlaybackSpeed => playbackSpeed; @@ -69,6 +68,10 @@ public enum AutoplayType public bool IsPlaying => playingSequence != null && playingSequence.IsActive() && playingSequence.IsPlaying(); public bool IsPaused => playingSequence != null && playingSequence.IsActive() && !playingSequence.IsPlaying(); + [SerializeField, Range(0, 1)] + private float progress = -1; + + protected virtual void Awake() { if (autoplayMode != AutoplayType.Awake) @@ -87,12 +90,9 @@ protected virtual void OnEnable() private void Autoplay() { - if (playOnAwake) - { - Play(); - if (pauseOnAwake) - playingSequence.Pause(); - } + Play(); + if (startPaused) + playingSequence.Pause(); } protected virtual void OnDisable() @@ -276,7 +276,7 @@ public virtual Sequence GenerateSequence() onFinishedEvent.Invoke(); } }); - + for (int i = 0; i < animationSteps.Length; i++) { animationSteps[i].AddTweenToSequence(sequence); @@ -340,12 +340,11 @@ public void SetAutoplayMode(AutoplayType autoplayType) public void SetPlayOnAwake(bool targetPlayOnAwake) { - playOnAwake = targetPlayOnAwake; } public void SetPauseOnAwake(bool targetPauseOnAwake) { - pauseOnAwake = targetPauseOnAwake; + startPaused = targetPauseOnAwake; } public void SetTimeScaleIndependent(bool targetTimeScaleIndependent) @@ -372,7 +371,15 @@ public void SetLoops(int targetLoops) { loops = targetLoops; } - + + private void Update() + { + if (progress == -1.0f) + return; + + SetProgress(progress); + } + #if UNITY_EDITOR // Unity Event Function called when component is added or reset. private void Reset() diff --git a/Scripts/Runtime/Core/DOTweenActions/ColorGraphicDOTWeen.cs b/Scripts/Runtime/Core/DOTweenActions/ColorGraphicDOTWeen.cs index 1a9261d..4d266de 100644 --- a/Scripts/Runtime/Core/DOTweenActions/ColorGraphicDOTWeen.cs +++ b/Scripts/Runtime/Core/DOTweenActions/ColorGraphicDOTWeen.cs @@ -16,11 +16,6 @@ public sealed class ColorGraphicDOTWeen : DOTweenActionBase [SerializeField] private Color color; - public Color Color - { - get => color; - set => color = value; - } private Graphic targetGraphic; private Color previousColor; @@ -40,15 +35,15 @@ protected override Tweener GenerateTween_Internal(GameObject target, float durat previousColor = targetGraphic.color; TweenerCore graphicTween = targetGraphic.DOColor(color, duration); -#if UNITY_EDITOR +#if UNITY_EDITOR if (!Application.isPlaying) { // Work around a Unity bug where updating the colour does not cause any visual change outside of PlayMode. // https://forum.unity.com/threads/editor-scripting-force-color-update.798663/ graphicTween.OnUpdate(() => { - targetGraphic.enabled = false; - targetGraphic.enabled = true; + targetGraphic.transform.localScale = new Vector3(1.001f, 1.001f, 1.001f); + targetGraphic.transform.localScale = new Vector3(1, 1, 1); }); } #endif diff --git a/package.json b/package.json index 1e409dc..1c34759 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "com.brunomikoski.animationsequencer", "displayName": "Animation Sequencer", - "version": "0.4.0", + "version": "0.5.0", "unity": "2018.4", "description": "Animation sequencer is a way to create complex animations of sequence of events by a friendly user interface. Requires DOTween v1.2.632", "keywords": [