From 8ad72ae00bfb08c08e2274cdf3258be521278953 Mon Sep 17 00:00:00 2001 From: Daniel Cumbor Date: Sun, 13 Jul 2025 19:33:06 +0100 Subject: [PATCH] Reupload to new git vps. --- DC.Animator.asmdef | 16 + DC.Animator.asmdef.meta | 7 + Editor.meta | 8 + Editor/AnimationCollectionEditor.cs | 145 +++++++ Editor/AnimationCollectionEditor.cs.meta | 3 + Editor/AnimationEditorWindow.cs | 401 ++++++++++++++++++ Editor/AnimationEditorWindow.cs.meta | 3 + Runtime.meta | 8 + Runtime/Adapters.meta | 3 + Runtime/Adapters/ImageAdapter.cs | 60 +++ Runtime/Adapters/ImageAdapter.cs.meta | 3 + Runtime/Adapters/RectTransformAdapter.cs | 77 ++++ Runtime/Adapters/RectTransformAdapter.cs.meta | 3 + Runtime/Adapters/SpriteAdapter.cs | 59 +++ Runtime/Adapters/SpriteAdapter.cs.meta | 3 + Runtime/Adapters/TMPTextAdapter.cs | 63 +++ Runtime/Adapters/TMPTextAdapter.cs.meta | 3 + Runtime/Adapters/TransformAdapter.cs | 71 ++++ Runtime/Adapters/TransformAdapter.cs.meta | 3 + Runtime/AnimationTypeBuilders.meta | 3 + .../ColorAnimationBuilder.cs | 53 +++ .../ColorAnimationBuilder.cs.meta | 3 + .../FadeAnimationBuilder.cs | 32 ++ .../FadeAnimationBuilder.cs.meta | 3 + .../MoveAnimationBuilder.cs | 76 ++++ .../MoveAnimationBuilder.cs.meta | 3 + .../RotateAnimationBuilder.cs | 87 ++++ .../RotateAnimationBuilder.cs.meta | 3 + .../ScaleAnimationBuilder.cs | 57 +++ .../ScaleAnimationBuilder.cs.meta | 3 + Runtime/Core.meta | 3 + Runtime/Core/AnimatableProperty.cs | 15 + Runtime/Core/AnimatableProperty.cs.meta | 3 + Runtime/Core/Animation.cs | 185 ++++++++ Runtime/Core/Animation.cs.meta | 3 + Runtime/Core/AnimationBuilder.cs | 136 ++++++ Runtime/Core/AnimationBuilder.cs.meta | 3 + Runtime/Core/AnimationRuntime.cs | 95 +++++ Runtime/Core/AnimationRuntime.cs.meta | 3 + Runtime/Core/AnimationTypeBuilderBase.cs | 61 +++ Runtime/Core/AnimationTypeBuilderBase.cs.meta | 2 + Runtime/Core/IAnimatable.cs | 12 + Runtime/Core/IAnimatable.cs.meta | 3 + Runtime/Core/IAnimation.cs | 23 + Runtime/Core/IAnimation.cs.meta | 2 + Runtime/Data.meta | 3 + Runtime/Data/AnimationCollection.cs | 101 +++++ Runtime/Data/AnimationCollection.cs.meta | 3 + Runtime/Data/AnimationData.cs | 41 ++ Runtime/Data/AnimationData.cs.meta | 3 + Runtime/Utils.meta | 3 + Runtime/Utils/EasingFunctions.cs | 278 ++++++++++++ Runtime/Utils/EasingFunctions.cs.meta | 3 + Runtime/Utils/ObjectPool.cs | 21 + Runtime/Utils/ObjectPool.cs.meta | 3 + package.json | 13 + package.json.meta | 7 + 57 files changed, 2290 insertions(+) create mode 100644 DC.Animator.asmdef create mode 100644 DC.Animator.asmdef.meta create mode 100644 Editor.meta create mode 100644 Editor/AnimationCollectionEditor.cs create mode 100644 Editor/AnimationCollectionEditor.cs.meta create mode 100644 Editor/AnimationEditorWindow.cs create mode 100644 Editor/AnimationEditorWindow.cs.meta create mode 100644 Runtime.meta create mode 100644 Runtime/Adapters.meta create mode 100644 Runtime/Adapters/ImageAdapter.cs create mode 100644 Runtime/Adapters/ImageAdapter.cs.meta create mode 100644 Runtime/Adapters/RectTransformAdapter.cs create mode 100644 Runtime/Adapters/RectTransformAdapter.cs.meta create mode 100644 Runtime/Adapters/SpriteAdapter.cs create mode 100644 Runtime/Adapters/SpriteAdapter.cs.meta create mode 100644 Runtime/Adapters/TMPTextAdapter.cs create mode 100644 Runtime/Adapters/TMPTextAdapter.cs.meta create mode 100644 Runtime/Adapters/TransformAdapter.cs create mode 100644 Runtime/Adapters/TransformAdapter.cs.meta create mode 100644 Runtime/AnimationTypeBuilders.meta create mode 100644 Runtime/AnimationTypeBuilders/ColorAnimationBuilder.cs create mode 100644 Runtime/AnimationTypeBuilders/ColorAnimationBuilder.cs.meta create mode 100644 Runtime/AnimationTypeBuilders/FadeAnimationBuilder.cs create mode 100644 Runtime/AnimationTypeBuilders/FadeAnimationBuilder.cs.meta create mode 100644 Runtime/AnimationTypeBuilders/MoveAnimationBuilder.cs create mode 100644 Runtime/AnimationTypeBuilders/MoveAnimationBuilder.cs.meta create mode 100644 Runtime/AnimationTypeBuilders/RotateAnimationBuilder.cs create mode 100644 Runtime/AnimationTypeBuilders/RotateAnimationBuilder.cs.meta create mode 100644 Runtime/AnimationTypeBuilders/ScaleAnimationBuilder.cs create mode 100644 Runtime/AnimationTypeBuilders/ScaleAnimationBuilder.cs.meta create mode 100644 Runtime/Core.meta create mode 100644 Runtime/Core/AnimatableProperty.cs create mode 100644 Runtime/Core/AnimatableProperty.cs.meta create mode 100644 Runtime/Core/Animation.cs create mode 100644 Runtime/Core/Animation.cs.meta create mode 100644 Runtime/Core/AnimationBuilder.cs create mode 100644 Runtime/Core/AnimationBuilder.cs.meta create mode 100644 Runtime/Core/AnimationRuntime.cs create mode 100644 Runtime/Core/AnimationRuntime.cs.meta create mode 100644 Runtime/Core/AnimationTypeBuilderBase.cs create mode 100644 Runtime/Core/AnimationTypeBuilderBase.cs.meta create mode 100644 Runtime/Core/IAnimatable.cs create mode 100644 Runtime/Core/IAnimatable.cs.meta create mode 100644 Runtime/Core/IAnimation.cs create mode 100644 Runtime/Core/IAnimation.cs.meta create mode 100644 Runtime/Data.meta create mode 100644 Runtime/Data/AnimationCollection.cs create mode 100644 Runtime/Data/AnimationCollection.cs.meta create mode 100644 Runtime/Data/AnimationData.cs create mode 100644 Runtime/Data/AnimationData.cs.meta create mode 100644 Runtime/Utils.meta create mode 100644 Runtime/Utils/EasingFunctions.cs create mode 100644 Runtime/Utils/EasingFunctions.cs.meta create mode 100644 Runtime/Utils/ObjectPool.cs create mode 100644 Runtime/Utils/ObjectPool.cs.meta create mode 100644 package.json create mode 100644 package.json.meta diff --git a/DC.Animator.asmdef b/DC.Animator.asmdef new file mode 100644 index 0000000..694678f --- /dev/null +++ b/DC.Animator.asmdef @@ -0,0 +1,16 @@ +{ + "name": "DC.Animator", + "rootNamespace": "", + "references": [ + "GUID:6055be8ebefd69e48b49212b09b47b2f" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/DC.Animator.asmdef.meta b/DC.Animator.asmdef.meta new file mode 100644 index 0000000..509ad3a --- /dev/null +++ b/DC.Animator.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fd7612f2de54f1e46a60c1460f826a43 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor.meta b/Editor.meta new file mode 100644 index 0000000..33c88da --- /dev/null +++ b/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a60c3d1cd509697419e16c967dfffc14 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/AnimationCollectionEditor.cs b/Editor/AnimationCollectionEditor.cs new file mode 100644 index 0000000..da616ca --- /dev/null +++ b/Editor/AnimationCollectionEditor.cs @@ -0,0 +1,145 @@ +#if UNITY_EDITOR +using System; +using DC.Animator.Data; +using DC.Animator.Utils; +using UnityEditor; +using UnityEngine; + +namespace DC.Animator.Editor +{ + [CustomEditor(typeof(AnimationCollection))] + public class AnimationCollectionEditor : UnityEditor.Editor + { + private SerializedProperty _animationsProperty; + private AnimationCollection _collection; + + private void OnEnable() + { + _animationsProperty = serializedObject.FindProperty("animations"); + _collection = (AnimationCollection)target; + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Animation Presets", EditorStyles.boldLabel); + EditorGUILayout.Space(); + + if (GUILayout.Button("Add Animation", GUILayout.Height(30))) AddNewAnimation(); + + EditorGUILayout.Space(); + + for (var i = 0; i < _animationsProperty.arraySize; i++) + { + var animationProperty = _animationsProperty.GetArrayElementAtIndex(i); + var nameProperty = animationProperty.FindPropertyRelative("name"); + var typeProperty = animationProperty.FindPropertyRelative("type"); + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PropertyField(nameProperty, GUIContent.none); + EditorGUILayout.PropertyField(typeProperty, GUIContent.none, GUILayout.Width(100)); + + if (GUILayout.Button("X", GUILayout.Width(25))) + { + _animationsProperty.DeleteArrayElementAtIndex(i); + serializedObject.ApplyModifiedProperties(); + return; + } + + EditorGUILayout.EndHorizontal(); + + var foldoutName = nameProperty.stringValue; + if (string.IsNullOrEmpty(foldoutName)) + foldoutName = "Animation " + i; + + animationProperty.isExpanded = EditorGUILayout.Foldout(animationProperty.isExpanded, foldoutName, true); + + if (animationProperty.isExpanded) + { + EditorGUI.indentLevel++; + + EditorGUILayout.PropertyField(animationProperty.FindPropertyRelative("duration")); + EditorGUILayout.PropertyField(animationProperty.FindPropertyRelative("delay")); + EditorGUILayout.PropertyField(animationProperty.FindPropertyRelative("easingType")); + + EditorGUILayout.Space(); + + var type = (AnimationCollection.AnimationType)typeProperty.enumValueIndex; + + switch (type) + { + case AnimationCollection.AnimationType.Fade: + EditorGUILayout.PropertyField(animationProperty.FindPropertyRelative("fromAlpha")); + EditorGUILayout.PropertyField(animationProperty.FindPropertyRelative("toAlpha")); + break; + + case AnimationCollection.AnimationType.Move: + EditorGUILayout.PropertyField(animationProperty.FindPropertyRelative("fromPosition")); + EditorGUILayout.PropertyField(animationProperty.FindPropertyRelative("toPosition")); + EditorGUILayout.PropertyField(animationProperty.FindPropertyRelative("useLocalPosition")); + EditorGUILayout.PropertyField( + animationProperty.FindPropertyRelative("useAnchoredPosition")); + break; + + case AnimationCollection.AnimationType.Scale: + EditorGUILayout.PropertyField(animationProperty.FindPropertyRelative("fromScale")); + EditorGUILayout.PropertyField(animationProperty.FindPropertyRelative("toScale")); + break; + + case AnimationCollection.AnimationType.Rotate: + EditorGUILayout.PropertyField(animationProperty.FindPropertyRelative("fromEulerAngles")); + EditorGUILayout.PropertyField(animationProperty.FindPropertyRelative("toEulerAngles")); + break; + + case AnimationCollection.AnimationType.Color: + EditorGUILayout.PropertyField(animationProperty.FindPropertyRelative("fromColor")); + EditorGUILayout.PropertyField(animationProperty.FindPropertyRelative("toColor")); + EditorGUILayout.PropertyField(animationProperty.FindPropertyRelative("isTextColor")); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + EditorGUI.indentLevel--; + } + + EditorGUILayout.EndVertical(); + EditorGUILayout.Space(); + } + + serializedObject.ApplyModifiedProperties(); + } + + private void AddNewAnimation() + { + var index = _animationsProperty.arraySize; + _animationsProperty.InsertArrayElementAtIndex(index); + + var element = _animationsProperty.GetArrayElementAtIndex(index); + + element.FindPropertyRelative("name").stringValue = "New Animation"; + element.FindPropertyRelative("type").enumValueIndex = 0; + element.FindPropertyRelative("duration").floatValue = 0.5f; + element.FindPropertyRelative("delay").floatValue = 0f; + element.FindPropertyRelative("easingType").enumValueIndex = (int)Easing.Type.EaseOutQuad; + + element.FindPropertyRelative("fromAlpha").floatValue = 0f; + element.FindPropertyRelative("toAlpha").floatValue = 1f; + + element.FindPropertyRelative("fromScale").vector3Value = Vector3.zero; + element.FindPropertyRelative("toScale").vector3Value = Vector3.one; + + element.FindPropertyRelative("fromColor").colorValue = Color.white; + element.FindPropertyRelative("toColor").colorValue = Color.white; + + element.isExpanded = true; + + serializedObject.ApplyModifiedProperties(); + } + } +} +#endif \ No newline at end of file diff --git a/Editor/AnimationCollectionEditor.cs.meta b/Editor/AnimationCollectionEditor.cs.meta new file mode 100644 index 0000000..35f9ff2 --- /dev/null +++ b/Editor/AnimationCollectionEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e980dad5c4f248808f571603257f2611 +timeCreated: 1747861571 \ No newline at end of file diff --git a/Editor/AnimationEditorWindow.cs b/Editor/AnimationEditorWindow.cs new file mode 100644 index 0000000..69e27d4 --- /dev/null +++ b/Editor/AnimationEditorWindow.cs @@ -0,0 +1,401 @@ +#if UNITY_EDITOR +using System; +using DC.Animator.Adapters; +using DC.Animator.Core; +using DC.Animator.Data; +using DC.Animator.Utils; +using DCAnimator.Data; +using TMPro; +using UnityEditor; +using UnityEngine; +using UnityEngine.UI; + +namespace DC.Animator.Editor +{ + public class AnimationEditorWindow : EditorWindow + { + private readonly string[] _animationTypes = { "Fade", "Move", "Scale", "Rotate", "Color" }; + + private readonly string[] _tabNames = { "Create", "Test", "Manage Presets" }; + private AnimationCollection _animationCollection; + + private AnimationData _currentAnimation = new(); + private bool _isAnimating; + private float _lastUpdateTime; + private string _presetName = "New Preset"; + private IAnimation _previewAnimation; + private Vector2 _scrollPosition; + private int _selectedAnimationType; + + private int _selectedTabIndex; + + private GameObject _targetObject; + + private void OnEnable() + { + ResetCurrentAnimation(); + } + + private void OnGUI() + { + _selectedTabIndex = GUILayout.Toolbar(_selectedTabIndex, _tabNames); + + EditorGUILayout.Space(); + + switch (_selectedTabIndex) + { + case 0: + DrawCreateAnimationTab(); + break; + case 1: + DrawTestAnimationTab(); + break; + case 2: + DrawManagePresetsTab(); + break; + } + + if (!_isAnimating || _previewAnimation == null) return; + + var deltaTime = (float)(EditorApplication.timeSinceStartup - _lastUpdateTime); + _lastUpdateTime = (float)EditorApplication.timeSinceStartup; + + _previewAnimation.Update(deltaTime); + + if (_previewAnimation.IsComplete) _isAnimating = false; + + Repaint(); + } + + [MenuItem("Window/DC Animator/Editor")] + public static void ShowWindow() + { + GetWindow("DC Animator Editor"); + } + + private void ResetCurrentAnimation() + { + _currentAnimation = new AnimationData + { + name = "New Animation", + type = AnimationCollection.AnimationType.Fade, + duration = 0.5f, + delay = 0f, + easingType = Easing.Type.EaseOutQuad, + fromAlpha = 0f, + toAlpha = 1f, + fromScale = Vector3.zero, + toScale = Vector3.one, + fromColor = Color.white, + toColor = Color.white + }; + } + + private void DrawCreateAnimationTab() + { + _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition); + + EditorGUILayout.LabelField("Create New Animation", EditorStyles.boldLabel); + EditorGUILayout.Space(); + + _currentAnimation.name = EditorGUILayout.TextField("Animation Name", _currentAnimation.name); + + _selectedAnimationType = EditorGUILayout.Popup("Animation Type", _selectedAnimationType, _animationTypes); + _currentAnimation.type = (AnimationCollection.AnimationType)_selectedAnimationType; + + EditorGUILayout.Space(); + + EditorGUILayout.LabelField("Common Properties", EditorStyles.boldLabel); + _currentAnimation.duration = EditorGUILayout.FloatField("Duration", _currentAnimation.duration); + _currentAnimation.delay = EditorGUILayout.FloatField("Delay", _currentAnimation.delay); + + var easingNames = Enum.GetNames(typeof(Easing.Type)); + var easingIndex = (int)_currentAnimation.easingType; + easingIndex = EditorGUILayout.Popup("Easing Type", easingIndex, easingNames); + _currentAnimation.easingType = (Easing.Type)easingIndex; + + EditorGUILayout.Space(); + + // Specific Properties + EditorGUILayout.LabelField("Animation Properties", EditorStyles.boldLabel); + + switch (_currentAnimation.type) + { + case AnimationCollection.AnimationType.Fade: + _currentAnimation.fromAlpha = + EditorGUILayout.Slider("From Alpha", _currentAnimation.fromAlpha, 0f, 1f); + _currentAnimation.toAlpha = EditorGUILayout.Slider("To Alpha", _currentAnimation.toAlpha, 0f, 1f); + break; + + case AnimationCollection.AnimationType.Move: + _currentAnimation.fromPosition = + EditorGUILayout.Vector3Field("From Position", _currentAnimation.fromPosition); + _currentAnimation.toPosition = + EditorGUILayout.Vector3Field("To Position", _currentAnimation.toPosition); + _currentAnimation.useLocalPosition = + EditorGUILayout.Toggle("Use Local Position", _currentAnimation.useLocalPosition); + _currentAnimation.useAnchoredPosition = EditorGUILayout.Toggle("Use Anchored Position", + _currentAnimation.useAnchoredPosition); + break; + + case AnimationCollection.AnimationType.Scale: + _currentAnimation.fromScale = + EditorGUILayout.Vector3Field("From Scale", _currentAnimation.fromScale); + _currentAnimation.toScale = EditorGUILayout.Vector3Field("To Scale", _currentAnimation.toScale); + break; + + case AnimationCollection.AnimationType.Rotate: + _currentAnimation.fromEulerAngles = + EditorGUILayout.Vector3Field("From Rotation", _currentAnimation.fromEulerAngles); + _currentAnimation.toEulerAngles = + EditorGUILayout.Vector3Field("To Rotation", _currentAnimation.toEulerAngles); + break; + + case AnimationCollection.AnimationType.Color: + _currentAnimation.fromColor = EditorGUILayout.ColorField("From Color", _currentAnimation.fromColor); + _currentAnimation.toColor = EditorGUILayout.ColorField("To Color", _currentAnimation.toColor); + _currentAnimation.isTextColor = + EditorGUILayout.Toggle("Is Text Color", _currentAnimation.isTextColor); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + EditorGUILayout.Space(); + + EditorGUILayout.BeginHorizontal(); + + _animationCollection = (AnimationCollection)EditorGUILayout.ObjectField("Save To Preset", _animationCollection, + typeof(AnimationCollection), false); + + if (_animationCollection && GUILayout.Button("Save")) SaveAnimationToPreset(); + + EditorGUILayout.EndHorizontal(); + + if (!_animationCollection) + { + EditorGUILayout.BeginHorizontal(); + _presetName = EditorGUILayout.TextField("New Preset Name", _presetName); + + if (GUILayout.Button("Create")) CreateNewPreset(); + + EditorGUILayout.EndHorizontal(); + } + + EditorGUILayout.EndScrollView(); + } + + private void DrawTestAnimationTab() + { + EditorGUILayout.LabelField("Test Animation", EditorStyles.boldLabel); + EditorGUILayout.Space(); + + _targetObject = + (GameObject)EditorGUILayout.ObjectField("Target Object", _targetObject, typeof(GameObject), true); + _animationCollection = (AnimationCollection)EditorGUILayout.ObjectField("Animation Preset", _animationCollection, + typeof(AnimationCollection), false); + + EditorGUILayout.Space(); + + if (_targetObject && _animationCollection) + { + EditorGUILayout.LabelField("Available Animations:", EditorStyles.boldLabel); + + if (_animationCollection.animations.Count == 0) + EditorGUILayout.HelpBox("No animations in preset", MessageType.Info); + else + foreach (var anim in _animationCollection.animations) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField(anim.name, EditorStyles.label); + + if (GUILayout.Button("Play", GUILayout.Width(60))) PlayAnimation(anim.name); + + EditorGUILayout.EndHorizontal(); + } + } + else + { + EditorGUILayout.HelpBox("Select a target object and an animation preset to test animations", + MessageType.Info); + } + } + + private void DrawManagePresetsTab() + { + EditorGUILayout.LabelField("Manage Animation Presets", EditorStyles.boldLabel); + EditorGUILayout.Space(); + + _animationCollection = (AnimationCollection)EditorGUILayout.ObjectField("Animation Preset", _animationCollection, + typeof(AnimationCollection), false); + + EditorGUILayout.Space(); + + if (_animationCollection) + { + EditorGUILayout.LabelField("Animations in Preset:", EditorStyles.boldLabel); + + if (_animationCollection.animations.Count == 0) + EditorGUILayout.HelpBox("No animations in preset", MessageType.Info); + else + for (var i = 0; i < _animationCollection.animations.Count; i++) + { + var anim = _animationCollection.animations[i]; + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField($"{anim.name} ({anim.type})", EditorStyles.label); + + if (GUILayout.Button("Edit", GUILayout.Width(60))) + { + _currentAnimation = anim; + _selectedAnimationType = (int)anim.type; + _selectedTabIndex = 0; // Switch to Create tab + } + + if (GUILayout.Button("Delete", GUILayout.Width(60))) + if (EditorUtility.DisplayDialog("Delete Animation", + $"Are you sure you want to delete animation '{anim.name}'?", + "Delete", "Cancel")) + { + _animationCollection.animations.RemoveAt(i); + EditorUtility.SetDirty(_animationCollection); + AssetDatabase.SaveAssets(); + break; + } + + EditorGUILayout.EndHorizontal(); + } + + EditorGUILayout.Space(); + + if (GUILayout.Button("Create New Animation", GUILayout.Height(30))) + { + ResetCurrentAnimation(); + _selectedTabIndex = 0; // Switch to Create tab + } + } + else + { + EditorGUILayout.BeginHorizontal(); + _presetName = EditorGUILayout.TextField("New Preset Name", _presetName); + + if (GUILayout.Button("Create")) CreateNewPreset(); + + EditorGUILayout.EndHorizontal(); + } + } + + private void CreateNewPreset() + { + if (string.IsNullOrEmpty(_presetName)) + { + EditorUtility.DisplayDialog("Error", "Please enter a name for the preset", "OK"); + return; + } + + var path = EditorUtility.SaveFilePanelInProject( + "Save Animation Preset", + _presetName, + "asset", + "Save animation preset" + ); + + if (string.IsNullOrEmpty(path)) + return; + + _animationCollection = CreateInstance(); + AssetDatabase.CreateAsset(_animationCollection, path); + AssetDatabase.SaveAssets(); + + SaveAnimationToPreset(); + } + + private void SaveAnimationToPreset() + { + if (!_animationCollection) + return; + + for (var i = 0; i < _animationCollection.animations.Count; i++) + if (_animationCollection.animations[i].name == _currentAnimation.name) + { + if (!EditorUtility.DisplayDialog("Overwrite Animation", + $"Animation '{_currentAnimation.name}' already exists. Overwrite?", + "Overwrite", "Cancel")) return; + + _animationCollection.animations[i] = _currentAnimation; + EditorUtility.SetDirty(_animationCollection); + AssetDatabase.SaveAssets(); + + return; + } + + _animationCollection.animations.Add(_currentAnimation); + EditorUtility.SetDirty(_animationCollection); + AssetDatabase.SaveAssets(); + } + + private void PlayAnimation(string animationName) + { + if (!_targetObject || !_animationCollection) + return; + + IAnimatable adapter; + + var image = _targetObject.GetComponent(); + if (image) + adapter = new ImageAdapter(image); + + var text = _targetObject.GetComponent(); + if (text) + adapter = new TMPTextAdapter(text); + + var tmpro = _targetObject.GetComponent(); + if (tmpro) + adapter = new TMPTextAdapter(tmpro); + + var spriteRenderer = _targetObject.GetComponent(); + if (spriteRenderer) + adapter = new SpriteAdapter(spriteRenderer); + + var rectTransform = _targetObject.GetComponent(); + if (rectTransform) + { + adapter = new RectTransformAdapter(rectTransform); + } + else + { + var transform = _targetObject.transform; + adapter = new TransformAdapter(transform); + } + + _previewAnimation = _animationCollection.CreateAnimation(adapter, animationName); + + if (_previewAnimation == null) + { + EditorUtility.DisplayDialog("Error", $"Animation '{animationName}' not found in preset", "OK"); + return; + } + + _previewAnimation.Start(); + _isAnimating = true; + _lastUpdateTime = (float)EditorApplication.timeSinceStartup; + + EditorApplication.update += EditorUpdate; + } + + private void EditorUpdate() + { + if (_isAnimating && _previewAnimation != null) + { + Repaint(); + + if (!_previewAnimation.IsComplete) return; + + _isAnimating = false; + } + + EditorApplication.update -= EditorUpdate; + } + } +} +#endif \ No newline at end of file diff --git a/Editor/AnimationEditorWindow.cs.meta b/Editor/AnimationEditorWindow.cs.meta new file mode 100644 index 0000000..b2b4ba0 --- /dev/null +++ b/Editor/AnimationEditorWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f24aeb6fb1654955ac87e118100d8b1d +timeCreated: 1747861633 \ No newline at end of file diff --git a/Runtime.meta b/Runtime.meta new file mode 100644 index 0000000..ccdd529 --- /dev/null +++ b/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e657351d63ffca146a291a3fe1b517b0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Adapters.meta b/Runtime/Adapters.meta new file mode 100644 index 0000000..7ff6c50 --- /dev/null +++ b/Runtime/Adapters.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 56735d71953b4e5385da5122c22cd6e1 +timeCreated: 1747861237 \ No newline at end of file diff --git a/Runtime/Adapters/ImageAdapter.cs b/Runtime/Adapters/ImageAdapter.cs new file mode 100644 index 0000000..eb7f28b --- /dev/null +++ b/Runtime/Adapters/ImageAdapter.cs @@ -0,0 +1,60 @@ +using System; +using DC.Animator.Core; +using UnityEngine; +using UnityEngine.UI; + +namespace DC.Animator.Adapters +{ + public class ImageAdapter : IAnimatable + { + private readonly Image _image; + + public ImageAdapter(Image image) => _image = image; + + public bool SupportsProperty(AnimatableProperty property) + { + return property switch + { + AnimatableProperty.Alpha or AnimatableProperty.Color => true, + _ => false + }; + } + + public object GetValue(AnimatableProperty property) + { + return property switch + { + AnimatableProperty.Alpha => _image.color.a, + AnimatableProperty.Color => _image.color, + _ => throw new ArgumentException($"ImageAdapter does not support property {property}") + }; + } + + public void SetValue(AnimatableProperty property, object value) + { + switch (property) + { + case AnimatableProperty.Alpha: + var colorAlpha = _image.color; + colorAlpha.a = (float)value; + _image.color = colorAlpha; + break; + case AnimatableProperty.Color: + _image.color = (Color)value; + break; + default: + throw new ArgumentException($"ImageAdapter does not support property {property}"); + } + } + + public Type GetPropertyType(AnimatableProperty property) + { + return property switch + { + AnimatableProperty.Alpha => typeof(float), + AnimatableProperty.Color => typeof(Color), + _ => throw new ArgumentException($"ImageAdapter does not support property {property}") + }; + } + } +} \ No newline at end of file diff --git a/Runtime/Adapters/ImageAdapter.cs.meta b/Runtime/Adapters/ImageAdapter.cs.meta new file mode 100644 index 0000000..cab2e97 --- /dev/null +++ b/Runtime/Adapters/ImageAdapter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6c004264ae534a60b0acc1e9b0a1fabf +timeCreated: 1747861252 \ No newline at end of file diff --git a/Runtime/Adapters/RectTransformAdapter.cs b/Runtime/Adapters/RectTransformAdapter.cs new file mode 100644 index 0000000..680bbca --- /dev/null +++ b/Runtime/Adapters/RectTransformAdapter.cs @@ -0,0 +1,77 @@ +using System; +using DC.Animator.Core; +using UnityEngine; + +namespace DC.Animator.Adapters +{ + public class RectTransformAdapter : IAnimatable + { + private readonly RectTransform _rectTransform; + + public RectTransformAdapter(RectTransform rectTransform) => _rectTransform = rectTransform; + + public bool SupportsProperty(AnimatableProperty property) + { + return property switch + { + AnimatableProperty.Position or AnimatableProperty.LocalPosition or AnimatableProperty.AnchoredPosition + or AnimatableProperty.Scale or AnimatableProperty.Rotation + or AnimatableProperty.EulerAngles => true, + _ => false + }; + } + + public object GetValue(AnimatableProperty property) + { + return property switch + { + AnimatableProperty.Position => _rectTransform.position, + AnimatableProperty.LocalPosition => _rectTransform.localPosition, + AnimatableProperty.AnchoredPosition => _rectTransform.anchoredPosition, + AnimatableProperty.Scale => _rectTransform.localScale, + AnimatableProperty.Rotation => _rectTransform.rotation, + AnimatableProperty.EulerAngles => _rectTransform.eulerAngles, + _ => throw new ArgumentException($"RectTransformAdapter does not support property {property}") + }; + } + + public void SetValue(AnimatableProperty property, object value) + { + switch (property) + { + case AnimatableProperty.Position: + _rectTransform.position = (Vector3)value; + break; + case AnimatableProperty.LocalPosition: + _rectTransform.localPosition = (Vector3)value; + break; + case AnimatableProperty.AnchoredPosition: + _rectTransform.anchoredPosition = (Vector2)value; + break; + case AnimatableProperty.Scale: + _rectTransform.localScale = (Vector3)value; + break; + case AnimatableProperty.Rotation: + _rectTransform.rotation = (Quaternion)value; + break; + case AnimatableProperty.EulerAngles: + _rectTransform.eulerAngles = (Vector3)value; + break; + default: + throw new ArgumentException($"RectTransformAdapter does not support property {property}"); + } + } + + public Type GetPropertyType(AnimatableProperty property) + { + return property switch + { + AnimatableProperty.Position or AnimatableProperty.LocalPosition or AnimatableProperty.Scale + or AnimatableProperty.EulerAngles => typeof(Vector3), + AnimatableProperty.AnchoredPosition => typeof(Vector2), + AnimatableProperty.Rotation => typeof(Quaternion), + _ => throw new ArgumentException($"RectTransformAdapter does not support property {property}") + }; + } + } +} \ No newline at end of file diff --git a/Runtime/Adapters/RectTransformAdapter.cs.meta b/Runtime/Adapters/RectTransformAdapter.cs.meta new file mode 100644 index 0000000..8c758c0 --- /dev/null +++ b/Runtime/Adapters/RectTransformAdapter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3445d296a0bb42dc8cfe1d0f4ab762a1 +timeCreated: 1747861417 \ No newline at end of file diff --git a/Runtime/Adapters/SpriteAdapter.cs b/Runtime/Adapters/SpriteAdapter.cs new file mode 100644 index 0000000..7d7ce4f --- /dev/null +++ b/Runtime/Adapters/SpriteAdapter.cs @@ -0,0 +1,59 @@ +using System; +using DC.Animator.Core; +using UnityEngine; + +namespace DC.Animator.Adapters +{ + public class SpriteAdapter : IAnimatable + { + private readonly SpriteRenderer _spriteRenderer; + + public SpriteAdapter(SpriteRenderer spriteRenderer) => _spriteRenderer = spriteRenderer; + + public bool SupportsProperty(AnimatableProperty property) + { + return property switch + { + AnimatableProperty.Alpha or AnimatableProperty.Color => true, + _ => false + }; + } + + public object GetValue(AnimatableProperty property) + { + return property switch + { + AnimatableProperty.Alpha => _spriteRenderer.color.a, + AnimatableProperty.Color => _spriteRenderer.color, + _ => throw new ArgumentException($"SpriteRendererAdapter does not support property {property}") + }; + } + + public void SetValue(AnimatableProperty property, object value) + { + switch (property) + { + case AnimatableProperty.Alpha: + var colorAlpha = _spriteRenderer.color; + colorAlpha.a = (float)value; + _spriteRenderer.color = colorAlpha; + break; + case AnimatableProperty.Color: + _spriteRenderer.color = (Color)value; + break; + default: + throw new ArgumentException($"SpriteRendererAdapter does not support property {property}"); + } + } + + public Type GetPropertyType(AnimatableProperty property) + { + return property switch + { + AnimatableProperty.Alpha => typeof(float), + AnimatableProperty.Color => typeof(Color), + _ => throw new ArgumentException($"SpriteRendererAdapter does not support property {property}") + }; + } + } +} \ No newline at end of file diff --git a/Runtime/Adapters/SpriteAdapter.cs.meta b/Runtime/Adapters/SpriteAdapter.cs.meta new file mode 100644 index 0000000..a584d3a --- /dev/null +++ b/Runtime/Adapters/SpriteAdapter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 81eaeba71eb74408976c0dbc72a8a454 +timeCreated: 1747861361 \ No newline at end of file diff --git a/Runtime/Adapters/TMPTextAdapter.cs b/Runtime/Adapters/TMPTextAdapter.cs new file mode 100644 index 0000000..337fa8b --- /dev/null +++ b/Runtime/Adapters/TMPTextAdapter.cs @@ -0,0 +1,63 @@ +using System; +using DC.Animator.Core; +using TMPro; +using UnityEngine; + +namespace DC.Animator.Adapters +{ + public class TMPTextAdapter : IAnimatable + { + private readonly TMP_Text _text; + + public TMPTextAdapter(TMP_Text text) => _text = text; + + public bool SupportsProperty(AnimatableProperty property) + { + return property switch + { + AnimatableProperty.Alpha or AnimatableProperty.Color or AnimatableProperty.TextColor => true, + _ => false + }; + } + + public object GetValue(AnimatableProperty property) + { + return property switch + { + AnimatableProperty.Alpha => _text.alpha, + AnimatableProperty.Color or AnimatableProperty.TextColor => _text.color, + _ => throw new ArgumentException($"TextMeshProAdapter does not support property {property}") + }; + } + + public void SetValue(AnimatableProperty property, object value) + { + switch (property) + { + case AnimatableProperty.Alpha: + _text.alpha = (float)value; + break; + case AnimatableProperty.Color: + case AnimatableProperty.TextColor: + _text.color = (Color)value; + break; + default: + throw new ArgumentException($"TextMeshProAdapter does not support property {property}"); + } + } + + public Type GetPropertyType(AnimatableProperty property) + { + switch (property) + { + case AnimatableProperty.Alpha: + return typeof(float); + case AnimatableProperty.Color: + case AnimatableProperty.TextColor: + return typeof(Color); + default: + throw new ArgumentException($"TextMeshProAdapter does not support property {property}"); + } + } + } +} \ No newline at end of file diff --git a/Runtime/Adapters/TMPTextAdapter.cs.meta b/Runtime/Adapters/TMPTextAdapter.cs.meta new file mode 100644 index 0000000..2dc1ca6 --- /dev/null +++ b/Runtime/Adapters/TMPTextAdapter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d707c0a42bba4df2bde5731ebda18905 +timeCreated: 1747861307 \ No newline at end of file diff --git a/Runtime/Adapters/TransformAdapter.cs b/Runtime/Adapters/TransformAdapter.cs new file mode 100644 index 0000000..65fff2a --- /dev/null +++ b/Runtime/Adapters/TransformAdapter.cs @@ -0,0 +1,71 @@ +using System; +using DC.Animator.Core; +using UnityEngine; + +namespace DC.Animator.Adapters +{ + public class TransformAdapter : IAnimatable + { + private readonly Transform _transform; + + public TransformAdapter(Transform transform) => _transform = transform; + + public bool SupportsProperty(AnimatableProperty property) + { + return property switch + { + AnimatableProperty.Position or AnimatableProperty.LocalPosition or AnimatableProperty.Scale + or AnimatableProperty.Rotation or AnimatableProperty.EulerAngles => true, + _ => false + }; + } + + public object GetValue(AnimatableProperty property) + { + return property switch + { + AnimatableProperty.Position => _transform.position, + AnimatableProperty.LocalPosition => _transform.localPosition, + AnimatableProperty.Scale => _transform.localScale, + AnimatableProperty.Rotation => _transform.rotation, + AnimatableProperty.EulerAngles => _transform.eulerAngles, + _ => throw new ArgumentException($"TransformAdapter does not support property {property}") + }; + } + + public void SetValue(AnimatableProperty property, object value) + { + switch (property) + { + case AnimatableProperty.Position: + _transform.position = (Vector3)value; + break; + case AnimatableProperty.LocalPosition: + _transform.localPosition = (Vector3)value; + break; + case AnimatableProperty.Scale: + _transform.localScale = (Vector3)value; + break; + case AnimatableProperty.Rotation: + _transform.rotation = (Quaternion)value; + break; + case AnimatableProperty.EulerAngles: + _transform.eulerAngles = (Vector3)value; + break; + default: + throw new ArgumentException($"TransformAdapter does not support property {property}"); + } + } + + public Type GetPropertyType(AnimatableProperty property) + { + return property switch + { + AnimatableProperty.Position or AnimatableProperty.LocalPosition or AnimatableProperty.Scale + or AnimatableProperty.EulerAngles => typeof(Vector3), + AnimatableProperty.Rotation => typeof(Quaternion), + _ => throw new ArgumentException($"TransformAdapter does not support property {property}") + }; + } + } +} \ No newline at end of file diff --git a/Runtime/Adapters/TransformAdapter.cs.meta b/Runtime/Adapters/TransformAdapter.cs.meta new file mode 100644 index 0000000..db0d572 --- /dev/null +++ b/Runtime/Adapters/TransformAdapter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 12a9475c333d43d0ade1f05f8bfd1283 +timeCreated: 1747861386 \ No newline at end of file diff --git a/Runtime/AnimationTypeBuilders.meta b/Runtime/AnimationTypeBuilders.meta new file mode 100644 index 0000000..c2d8c01 --- /dev/null +++ b/Runtime/AnimationTypeBuilders.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8c757291c27645019681e3bb8f24ef0f +timeCreated: 1747861055 \ No newline at end of file diff --git a/Runtime/AnimationTypeBuilders/ColorAnimationBuilder.cs b/Runtime/AnimationTypeBuilders/ColorAnimationBuilder.cs new file mode 100644 index 0000000..c5af6be --- /dev/null +++ b/Runtime/AnimationTypeBuilders/ColorAnimationBuilder.cs @@ -0,0 +1,53 @@ +using DC.Animator.Core; +using UnityEngine; + +namespace DC.Animator.AnimationTypeBuilders +{ + public class ColorAnimationBuilder : AnimationTypeBuilderBase + { + private Color _fromColor = Color.white; + private bool _hasFromColor; + private bool _isTextColor; + private Color _toColor = Color.white; + + public ColorAnimationBuilder(AnimationBuilder baseBuilder) : base(baseBuilder) { } + + public ColorAnimationBuilder From(Color color) + { + _fromColor = color; + _hasFromColor = true; + return this; + } + + public ColorAnimationBuilder To(Color color) + { + _toColor = color; + return this; + } + + public ColorAnimationBuilder FromCurrent() + { + _hasFromColor = false; + return this; + } + + public ColorAnimationBuilder AsTextColor() + { + _isTextColor = true; + return this; + } + + public override IAnimation Build() + { + var animation = BaseBuilder.Build(); + + var property = _isTextColor ? AnimatableProperty.TextColor : AnimatableProperty.Color; + + if (!_hasFromColor) _fromColor = (Color)animation.GetValue(property); + + animation.SetProperty(property, _fromColor, _toColor); + + return animation; + } + } +} \ No newline at end of file diff --git a/Runtime/AnimationTypeBuilders/ColorAnimationBuilder.cs.meta b/Runtime/AnimationTypeBuilders/ColorAnimationBuilder.cs.meta new file mode 100644 index 0000000..990285f --- /dev/null +++ b/Runtime/AnimationTypeBuilders/ColorAnimationBuilder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 906d0b3b5c8a480cbca966bd4f505e12 +timeCreated: 1747861219 \ No newline at end of file diff --git a/Runtime/AnimationTypeBuilders/FadeAnimationBuilder.cs b/Runtime/AnimationTypeBuilders/FadeAnimationBuilder.cs new file mode 100644 index 0000000..cec845e --- /dev/null +++ b/Runtime/AnimationTypeBuilders/FadeAnimationBuilder.cs @@ -0,0 +1,32 @@ +using DC.Animator.Core; +using UnityEngine; + +namespace DC.Animator.AnimationTypeBuilders +{ + public class FadeAnimationBuilder : AnimationTypeBuilderBase + { + private float _fromAlpha; + private float _toAlpha = 1f; + + public FadeAnimationBuilder(AnimationBuilder baseBuilder) : base(baseBuilder) { } + + public FadeAnimationBuilder From(float alpha) + { + _fromAlpha = Mathf.Clamp01(alpha); + return this; + } + + public FadeAnimationBuilder To(float alpha) + { + _toAlpha = Mathf.Clamp01(alpha); + return this; + } + + public override IAnimation Build() + { + var animation = BaseBuilder.Build(); + animation.SetProperty(AnimatableProperty.Alpha, _fromAlpha, _toAlpha); + return animation; + } + } +} \ No newline at end of file diff --git a/Runtime/AnimationTypeBuilders/FadeAnimationBuilder.cs.meta b/Runtime/AnimationTypeBuilders/FadeAnimationBuilder.cs.meta new file mode 100644 index 0000000..b6e43cc --- /dev/null +++ b/Runtime/AnimationTypeBuilders/FadeAnimationBuilder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 87ca0a0406324a70a8a5f7e8bd289a99 +timeCreated: 1747861075 \ No newline at end of file diff --git a/Runtime/AnimationTypeBuilders/MoveAnimationBuilder.cs b/Runtime/AnimationTypeBuilders/MoveAnimationBuilder.cs new file mode 100644 index 0000000..72fcd15 --- /dev/null +++ b/Runtime/AnimationTypeBuilders/MoveAnimationBuilder.cs @@ -0,0 +1,76 @@ +using DC.Animator.Core; +using UnityEngine; + +namespace DC.Animator.AnimationTypeBuilders +{ + public class MoveAnimationBuilder : AnimationTypeBuilderBase + { + private Vector3 _fromPosition; + private bool _hasFromPosition; + private bool _hasToPosition; + private bool _isAnchored; + private bool _isLocal; + private Vector3 _toPosition; + + public MoveAnimationBuilder(AnimationBuilder baseBuilder) : base(baseBuilder) { } + + public MoveAnimationBuilder From(Vector3 position) + { + _fromPosition = position; + _hasFromPosition = true; + return this; + } + + public MoveAnimationBuilder To(Vector3 position) + { + _toPosition = position; + _hasToPosition = true; + return this; + } + + public MoveAnimationBuilder FromCurrent() + { + _hasFromPosition = false; + return this; + } + + public MoveAnimationBuilder Local() + { + _isLocal = true; + _isAnchored = false; + return this; + } + + public MoveAnimationBuilder Anchored() + { + _isAnchored = true; + _isLocal = false; + return this; + } + + public override IAnimation Build() + { + var animation = BaseBuilder.Build(); + AnimatableProperty property; + + if (_isLocal) + property = AnimatableProperty.LocalPosition; + else if (_isAnchored) + property = AnimatableProperty.AnchoredPosition; + else + property = AnimatableProperty.Position; + + if (!_hasFromPosition) _fromPosition = (Vector3)animation.GetValue(property); + + if (!_hasToPosition) + { + Debug.LogWarning("No target position specified for move animation"); + _toPosition = _fromPosition; + } + + animation.SetProperty(property, _fromPosition, _toPosition); + + return animation; + } + } +} \ No newline at end of file diff --git a/Runtime/AnimationTypeBuilders/MoveAnimationBuilder.cs.meta b/Runtime/AnimationTypeBuilders/MoveAnimationBuilder.cs.meta new file mode 100644 index 0000000..a379abc --- /dev/null +++ b/Runtime/AnimationTypeBuilders/MoveAnimationBuilder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 800d1b5a42e24886b87d95dab0e1df99 +timeCreated: 1747861100 \ No newline at end of file diff --git a/Runtime/AnimationTypeBuilders/RotateAnimationBuilder.cs b/Runtime/AnimationTypeBuilders/RotateAnimationBuilder.cs new file mode 100644 index 0000000..bd0f782 --- /dev/null +++ b/Runtime/AnimationTypeBuilders/RotateAnimationBuilder.cs @@ -0,0 +1,87 @@ +using DC.Animator.Core; +using UnityEngine; + +namespace DC.Animator.AnimationTypeBuilders +{ + public class RotateAnimationBuilder : AnimationTypeBuilderBase + { + private Vector3 _fromEulerAngles; + private Vector3 _toEulerAngles; + private Quaternion _fromRotation; + private Quaternion _toRotation; + private bool _hasFromRotation; + private bool _useEuler = true; + + public RotateAnimationBuilder(AnimationBuilder baseBuilder) : base(baseBuilder) { } + + public RotateAnimationBuilder FromEuler(Vector3 eulerAngles) + { + _fromEulerAngles = eulerAngles; + _fromRotation = Quaternion.Euler(eulerAngles); + _hasFromRotation = true; + _useEuler = true; + return this; + } + + public RotateAnimationBuilder ToEuler(Vector3 eulerAngles) + { + _toEulerAngles = eulerAngles; + _toRotation = Quaternion.Euler(eulerAngles); + _useEuler = true; + return this; + } + + public RotateAnimationBuilder FromQuaternion(Quaternion rotation) + { + _fromRotation = rotation; + _fromEulerAngles = rotation.eulerAngles; + _hasFromRotation = true; + _useEuler = false; + return this; + } + + public RotateAnimationBuilder ToQuaternion(Quaternion rotation) + { + _toRotation = rotation; + _toEulerAngles = rotation.eulerAngles; + _useEuler = false; + return this; + } + + public RotateAnimationBuilder FromCurrent() + { + _hasFromRotation = false; + return this; + } + + public override IAnimation Build() + { + var animation = BaseBuilder.Build(); + + var property = _useEuler ? + AnimatableProperty.EulerAngles : + AnimatableProperty.Rotation; + + if (!_hasFromRotation) + { + if (_useEuler) + { + _fromEulerAngles = (Vector3)animation.GetValue(AnimatableProperty.EulerAngles); + _fromRotation = Quaternion.Euler(_fromEulerAngles); + } + else + { + _fromRotation = (Quaternion)animation.GetValue(AnimatableProperty.Rotation); + _fromEulerAngles = _fromRotation.eulerAngles; + } + } + + var fromValue = _useEuler ? (object)_fromEulerAngles : _fromRotation; + var toValue = _useEuler ? (object)_toEulerAngles : _toRotation; + + animation.SetProperty(property, fromValue, toValue); + + return animation; + } + } +} \ No newline at end of file diff --git a/Runtime/AnimationTypeBuilders/RotateAnimationBuilder.cs.meta b/Runtime/AnimationTypeBuilders/RotateAnimationBuilder.cs.meta new file mode 100644 index 0000000..605f485 --- /dev/null +++ b/Runtime/AnimationTypeBuilders/RotateAnimationBuilder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 735103945dcb47a9b677d3f57350514f +timeCreated: 1747861191 \ No newline at end of file diff --git a/Runtime/AnimationTypeBuilders/ScaleAnimationBuilder.cs b/Runtime/AnimationTypeBuilders/ScaleAnimationBuilder.cs new file mode 100644 index 0000000..be54557 --- /dev/null +++ b/Runtime/AnimationTypeBuilders/ScaleAnimationBuilder.cs @@ -0,0 +1,57 @@ +using DC.Animator.Core; +using UnityEngine; + +namespace DC.Animator.AnimationTypeBuilders +{ + public class ScaleAnimationBuilder : AnimationTypeBuilderBase + { + private Vector3 _fromScale = Vector3.one; + private bool _hasFromScale; + private Vector3 _toScale = Vector3.one; + + public ScaleAnimationBuilder(AnimationBuilder baseBuilder) : base(baseBuilder) { } + + public ScaleAnimationBuilder From(Vector3 scale) + { + _fromScale = scale; + _hasFromScale = true; + return this; + } + + public ScaleAnimationBuilder From(float uniformScale) + { + _fromScale = new Vector3(uniformScale, uniformScale, uniformScale); + _hasFromScale = true; + return this; + } + + public ScaleAnimationBuilder To(Vector3 scale) + { + _toScale = scale; + return this; + } + + public ScaleAnimationBuilder To(float uniformScale) + { + _toScale = new Vector3(uniformScale, uniformScale, uniformScale); + return this; + } + + public ScaleAnimationBuilder FromCurrent() + { + _hasFromScale = false; + return this; + } + + public override IAnimation Build() + { + var animation = BaseBuilder.Build(); + + if (!_hasFromScale) _fromScale = (Vector3)animation.GetValue(AnimatableProperty.Scale); + + animation.SetProperty(AnimatableProperty.Scale, _fromScale, _toScale); + + return animation; + } + } +} \ No newline at end of file diff --git a/Runtime/AnimationTypeBuilders/ScaleAnimationBuilder.cs.meta b/Runtime/AnimationTypeBuilders/ScaleAnimationBuilder.cs.meta new file mode 100644 index 0000000..8c1466b --- /dev/null +++ b/Runtime/AnimationTypeBuilders/ScaleAnimationBuilder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7b6cf6ed822b434d9635fa7841093483 +timeCreated: 1747861159 \ No newline at end of file diff --git a/Runtime/Core.meta b/Runtime/Core.meta new file mode 100644 index 0000000..024d873 --- /dev/null +++ b/Runtime/Core.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7305d0795bef4bc7b5554a9a57e6d05d +timeCreated: 1748092703 \ No newline at end of file diff --git a/Runtime/Core/AnimatableProperty.cs b/Runtime/Core/AnimatableProperty.cs new file mode 100644 index 0000000..30b89d0 --- /dev/null +++ b/Runtime/Core/AnimatableProperty.cs @@ -0,0 +1,15 @@ +namespace DC.Animator.Core +{ + public enum AnimatableProperty + { + Position, + LocalPosition, + AnchoredPosition, + Scale, + Rotation, + EulerAngles, + Alpha, + Color, + TextColor + } +} \ No newline at end of file diff --git a/Runtime/Core/AnimatableProperty.cs.meta b/Runtime/Core/AnimatableProperty.cs.meta new file mode 100644 index 0000000..65de40f --- /dev/null +++ b/Runtime/Core/AnimatableProperty.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8be1c4fca1da458487554a4860fbd09d +timeCreated: 1747860604 \ No newline at end of file diff --git a/Runtime/Core/Animation.cs b/Runtime/Core/Animation.cs new file mode 100644 index 0000000..3dbe1e8 --- /dev/null +++ b/Runtime/Core/Animation.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using DC.Animator.Utils; +using UnityEngine; + +namespace DC.Animator.Core +{ + public class Animation : IAnimation + { + private readonly Dictionary _properties = new(); + private float _currentTime; + private float _delay; + private float _delayTimer; + private float _duration; + private Easing.Function _easingFunction; + private bool _hasStarted; + + private IAnimatable _target; + + public Animation() { } + + public Animation(IAnimatable target, float duration, float delay, Easing.Function easingFunction) + { + _target = target; + _duration = Mathf.Max(duration, 0.001f); // Avoid division by zero + _delay = delay; + _easingFunction = easingFunction ?? Easing.Linear; + + Reset(); + } + + public bool IsComplete { get; private set; } + public bool IsPlaying { get; private set; } + + public event Action OnStart; + public event Action OnComplete; + public event Action OnUpdate; + + public void SetProperty(AnimatableProperty property, object fromValue, object toValue) + { + if (!_target.SupportsProperty(property)) + { + Debug.LogWarning($"Target does not support property {property}"); + return; + } + + var propertyType = _target.GetPropertyType(property); + + _properties[property] = new AnimationProperty + { + FromValue = fromValue, + ToValue = toValue, + PropertyType = propertyType + }; + } + + public object GetValue(AnimatableProperty property) + { + if (_target != null && _target.SupportsProperty(property)) return _target.GetValue(property); + throw new ArgumentException( + $"Cannot get value for property {property}. Either target is null or property is not supported."); + } + + public void Start() + { + if (IsPlaying) return; + + IsPlaying = true; + IsComplete = false; + _currentTime = 0; + _delayTimer = 0; + _hasStarted = false; + + foreach (var prop in _properties) _target.SetValue(prop.Key, prop.Value.FromValue); + } + + public void Pause() + { + IsPlaying = false; + } + + public void Resume() + { + if (!IsComplete) IsPlaying = true; + } + + public void Stop() + { + IsPlaying = false; + + foreach (var prop in _properties) _target.SetValue(prop.Key, prop.Value.ToValue); + + IsComplete = true; + OnComplete?.Invoke(this); + } + + public void Update(float deltaTime) + { + if (!IsPlaying || IsComplete) return; + + if (_delay > 0 && _delayTimer < _delay) + { + _delayTimer += deltaTime; + return; + } + + if (!_hasStarted) + { + _hasStarted = true; + OnStart?.Invoke(this); + } + + _currentTime += deltaTime; + var normalizedTime = Mathf.Clamp01(_currentTime / _duration); + var easedTime = _easingFunction(normalizedTime); + + foreach (var prop in _properties) + { + var interpolatedValue = InterpolateValue( + prop.Value.FromValue, + prop.Value.ToValue, + easedTime, + prop.Value.PropertyType + ); + + _target.SetValue(prop.Key, interpolatedValue); + } + + OnUpdate?.Invoke(this); + + if (_currentTime >= _duration) + { + IsPlaying = false; + IsComplete = true; + OnComplete?.Invoke(this); + } + } + + public void Reset() + { + IsComplete = false; + IsPlaying = false; + _hasStarted = false; + _currentTime = 0; + _delayTimer = 0; + _properties.Clear(); + + OnStart = null; + OnComplete = null; + OnUpdate = null; + } + + public void Initialize(IAnimatable target, float duration, float delay, Easing.Function easingFunction) + { + _target = target; + _duration = Mathf.Max(duration, 0.001f); + _delay = delay; + _easingFunction = easingFunction ?? Easing.Linear; + + Reset(); + } + + private object InterpolateValue(object from, object to, float t, Type propertyType) + { + if (propertyType == typeof(float)) return Mathf.Lerp((float)from, (float)to, t); + + if (propertyType == typeof(Vector2)) return Vector2.Lerp((Vector2)from, (Vector2)to, t); + + if (propertyType == typeof(Vector3)) return Vector3.Lerp((Vector3)from, (Vector3)to, t); + + if (propertyType == typeof(Color)) return Color.Lerp((Color)from, (Color)to, t); + + if (propertyType == typeof(Quaternion)) return Quaternion.Slerp((Quaternion)from, (Quaternion)to, t); + + return t < 0.5f ? from : to; + } + + private class AnimationProperty + { + public object FromValue; + public Type PropertyType; + public object ToValue; + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Animation.cs.meta b/Runtime/Core/Animation.cs.meta new file mode 100644 index 0000000..ee03477 --- /dev/null +++ b/Runtime/Core/Animation.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a3d35500f1f6469cb3baa292cfc1f882 +timeCreated: 1747860896 \ No newline at end of file diff --git a/Runtime/Core/AnimationBuilder.cs b/Runtime/Core/AnimationBuilder.cs new file mode 100644 index 0000000..46eeef8 --- /dev/null +++ b/Runtime/Core/AnimationBuilder.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using DC.Animator.Adapters; +using DC.Animator.AnimationTypeBuilders; +using DC.Animator.Utils; +using UnityEngine; + +namespace DC.Animator.Core +{ + public sealed class AnimationBuilder + { + private IAnimatable _target; + private float _duration = 1f; + private float _delay; + private Easing.Type _easingType = Easing.Type.Linear; + private Action _onStart; + private Action _onComplete; + private Action _onUpdate; + private static readonly Dictionary> AdapterFactories = new(); + + static AnimationBuilder() + { + RegisterAdapter((img) => new ImageAdapter(img)); + RegisterAdapter((text) => new TMPTextAdapter(text)); + RegisterAdapter((text) => new TMPTextAdapter(text)); + RegisterAdapter((sprite) => new SpriteAdapter(sprite)); + RegisterAdapter((transform) => new TransformAdapter(transform)); + RegisterAdapter((rectTransform) => new RectTransformAdapter(rectTransform)); + } + + public static void RegisterAdapter(Func adapterFactory) + { + AdapterFactories[typeof(T)] = obj => adapterFactory((T)obj); + } + + public static IAnimatable GetAdapter(object target) + { + var type = target.GetType(); + + if (AdapterFactories.TryGetValue(type, out var factory)) + return factory(target); + + foreach (var entry in AdapterFactories) + { + if (entry.Key.IsAssignableFrom(type)) + return entry.Value(target); + } + return null; + } + + public static AnimationBuilder For(T target) where T : UnityEngine.Object + { + var adapter = GetAdapter(target); + if (adapter != null) return new AnimationBuilder().WithTarget(adapter); + Debug.LogError($"No animation adapter registered for {typeof(T).Name}"); + return null; + } + + public AnimationBuilder WithTarget(IAnimatable target) + { + _target = target; + return this; + } + + public AnimationBuilder WithDuration(float duration) + { + _duration = Mathf.Max(0.001f, duration); + return this; + } + + public AnimationBuilder WithDelay(float delay) + { + _delay = Mathf.Max(0, delay); + return this; + } + + public AnimationBuilder WithEasing(Easing.Type easingType) + { + _easingType = easingType; + return this; + } + + public AnimationBuilder OnStart(Action callback) + { + _onStart = callback; + return this; + } + + public AnimationBuilder OnComplete(Action callback) + { + _onComplete = callback; + return this; + } + + public AnimationBuilder OnUpdate(Action callback) + { + _onUpdate = callback; + return this; + } + + public FadeAnimationBuilder AsFade() => new(this); + + public MoveAnimationBuilder AsMove() => new(this); + + public ScaleAnimationBuilder AsScale() => new(this); + + public RotateAnimationBuilder AsRotate() => new(this); + + public ColorAnimationBuilder AsColor() => new(this); + + public IAnimation Build() + { + var easingFunction = Easing.GetEasingFunction(_easingType); + var animation = AnimationRuntime.Instance.CreateAnimation(_target, _duration, _delay, easingFunction); + + if (_onStart != null) + animation.OnStart += _onStart; + + if (_onComplete != null) + animation.OnComplete += _onComplete; + + if (_onUpdate != null) + animation.OnUpdate += _onUpdate; + + return animation; + } + + public IAnimation Start() + { + var animation = Build(); + AnimationRuntime.Instance.RegisterAnimation(animation); + animation.Start(); + return animation; + } + } +} \ No newline at end of file diff --git a/Runtime/Core/AnimationBuilder.cs.meta b/Runtime/Core/AnimationBuilder.cs.meta new file mode 100644 index 0000000..e1e69ba --- /dev/null +++ b/Runtime/Core/AnimationBuilder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7363902fe7234f8296b9860043ae5a31 +timeCreated: 1747861027 \ No newline at end of file diff --git a/Runtime/Core/AnimationRuntime.cs b/Runtime/Core/AnimationRuntime.cs new file mode 100644 index 0000000..23d1dbb --- /dev/null +++ b/Runtime/Core/AnimationRuntime.cs @@ -0,0 +1,95 @@ +using System.Collections.Generic; +using DC.Animator.Utils; +using UnityEngine; + +namespace DC.Animator.Core +{ + public class AnimationRuntime : MonoBehaviour + { + private static AnimationRuntime _instance; + + private readonly List _activeAnimations = new(); + private readonly ObjectPool _animationPool = new(() => new Animation()); + private readonly List _pendingAdditions = new(); + private readonly List _pendingRemovals = new(); + + public static AnimationRuntime Instance + { + get + { + if (_instance) return _instance; + + var go = new GameObject("AnimationManager"); + _instance = go.AddComponent(); + DontDestroyOnLoad(go); + return _instance; + } + } + + private void Awake() + { + if (_instance && _instance != this) + { + Destroy(gameObject); + return; + } + + _instance = this; + DontDestroyOnLoad(gameObject); + } + + private void Update() + { + if (_pendingAdditions.Count > 0) + { + _activeAnimations.AddRange(_pendingAdditions); + _pendingAdditions.Clear(); + } + + var deltaTime = Time.deltaTime; + foreach (var animation in _activeAnimations) + { + animation.Update(deltaTime); + + if (animation.IsComplete) _pendingRemovals.Add(animation); + } + + if (_pendingRemovals.Count > 0) + { + foreach (var animation in _pendingRemovals) + { + _activeAnimations.Remove(animation); + ReturnToPool(animation); + } + + _pendingRemovals.Clear(); + } + } + + public void RegisterAnimation(IAnimation animation) + { + _pendingAdditions.Add(animation); + } + + private void ReturnToPool(IAnimation animation) + { + if (animation is not Animation pooledAnimation) return; + + pooledAnimation.Reset(); + _animationPool.Return(pooledAnimation); + } + + public Animation GetFromPool() + { + return _animationPool.Get(); + } + + public Animation CreateAnimation(IAnimatable target, float duration, float delay, + Easing.Function easingFunction) + { + var animation = _animationPool.Get(); + animation.Initialize(target, duration, delay, easingFunction); + return animation; + } + } +} \ No newline at end of file diff --git a/Runtime/Core/AnimationRuntime.cs.meta b/Runtime/Core/AnimationRuntime.cs.meta new file mode 100644 index 0000000..0280422 --- /dev/null +++ b/Runtime/Core/AnimationRuntime.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e9a1adb612d743eb87fca704d4335d1b +timeCreated: 1747860933 \ No newline at end of file diff --git a/Runtime/Core/AnimationTypeBuilderBase.cs b/Runtime/Core/AnimationTypeBuilderBase.cs new file mode 100644 index 0000000..d3e07b5 --- /dev/null +++ b/Runtime/Core/AnimationTypeBuilderBase.cs @@ -0,0 +1,61 @@ +using System; +using DC.Animator.Utils; + +namespace DC.Animator.Core +{ + public abstract class AnimationTypeBuilderBase + { + protected AnimationBuilder BaseBuilder { get; } + + protected AnimationTypeBuilderBase(AnimationBuilder baseBuilder) + { + BaseBuilder = baseBuilder; + } + + public AnimationTypeBuilderBase WithDuration(float duration) + { + BaseBuilder.WithDuration(duration); + return this; + } + + public AnimationTypeBuilderBase WithDelay(float delay) + { + BaseBuilder.WithDelay(delay); + return this; + } + + public AnimationTypeBuilderBase WithEasing(Easing.Type easingType) + { + BaseBuilder.WithEasing(easingType); + return this; + } + + public AnimationTypeBuilderBase OnStart(Action callback) + { + BaseBuilder.OnStart(callback); + return this; + } + + public AnimationTypeBuilderBase OnComplete(Action callback) + { + BaseBuilder.OnComplete(callback); + return this; + } + + public AnimationTypeBuilderBase OnUpdate(Action callback) + { + BaseBuilder.OnUpdate(callback); + return this; + } + + public abstract IAnimation Build(); + + public virtual IAnimation Start() + { + var animation = Build(); + AnimationRuntime.Instance.RegisterAnimation(animation); + animation.Start(); + return animation; + } + } +} \ No newline at end of file diff --git a/Runtime/Core/AnimationTypeBuilderBase.cs.meta b/Runtime/Core/AnimationTypeBuilderBase.cs.meta new file mode 100644 index 0000000..2a1661a --- /dev/null +++ b/Runtime/Core/AnimationTypeBuilderBase.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b3992f2125ccd5e4686b9f5aba900567 \ No newline at end of file diff --git a/Runtime/Core/IAnimatable.cs b/Runtime/Core/IAnimatable.cs new file mode 100644 index 0000000..6f4fea1 --- /dev/null +++ b/Runtime/Core/IAnimatable.cs @@ -0,0 +1,12 @@ +using System; + +namespace DC.Animator.Core +{ + public interface IAnimatable + { + bool SupportsProperty(AnimatableProperty property); + object GetValue(AnimatableProperty property); + void SetValue(AnimatableProperty property, object value); + Type GetPropertyType(AnimatableProperty property); + } +} \ No newline at end of file diff --git a/Runtime/Core/IAnimatable.cs.meta b/Runtime/Core/IAnimatable.cs.meta new file mode 100644 index 0000000..42e781d --- /dev/null +++ b/Runtime/Core/IAnimatable.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b60cedf76ef14da8830e3b09f87fed52 +timeCreated: 1747860577 \ No newline at end of file diff --git a/Runtime/Core/IAnimation.cs b/Runtime/Core/IAnimation.cs new file mode 100644 index 0000000..fbe71fa --- /dev/null +++ b/Runtime/Core/IAnimation.cs @@ -0,0 +1,23 @@ +using System; + +namespace DC.Animator.Core +{ + public interface IAnimation + { + bool IsComplete { get; } + bool IsPlaying { get; } + + void Start(); + void Pause(); + void Resume(); + void Stop(); + void Update(float deltaTime); + + void SetProperty(AnimatableProperty property, object fromValue, object toValue); + object GetValue(AnimatableProperty property); + + event Action OnStart; + event Action OnComplete; + event Action OnUpdate; + } +} diff --git a/Runtime/Core/IAnimation.cs.meta b/Runtime/Core/IAnimation.cs.meta new file mode 100644 index 0000000..3b7dc12 --- /dev/null +++ b/Runtime/Core/IAnimation.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 81f201c1b2e3c4845b9becc70b689633 \ No newline at end of file diff --git a/Runtime/Data.meta b/Runtime/Data.meta new file mode 100644 index 0000000..3067cc2 --- /dev/null +++ b/Runtime/Data.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e430bcc3743b4759ae5d6319ba0c6203 +timeCreated: 1747861443 \ No newline at end of file diff --git a/Runtime/Data/AnimationCollection.cs b/Runtime/Data/AnimationCollection.cs new file mode 100644 index 0000000..8c8362f --- /dev/null +++ b/Runtime/Data/AnimationCollection.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using DC.Animator.Core; +using DCAnimator.Data; +using UnityEngine; + +namespace DC.Animator.Data +{ + [CreateAssetMenu(fileName = "New Collection", menuName = "DCAnimator/Animation Collection")] + public class AnimationCollection : ScriptableObject + { + public enum AnimationType + { + Fade, + Move, + Scale, + Rotate, + Color + } + + public List animations = new(); + + public IAnimation CreateAnimation(IAnimatable target) + { + return animations.Count == 0 ? null : CreateAnimation(target, animations[0]); + } + + public IAnimation CreateAnimation(IAnimatable target, string name) + { + foreach (var animData in animations) + if (animData.name == name) + return CreateAnimation(target, animData); + + Debug.LogWarning($"Animation preset {name} not found"); + return null; + } + + private static IAnimation CreateAnimation(IAnimatable target, AnimationData data) + { + var builder = new AnimationBuilder() + .WithTarget(target) + .WithDuration(data.duration) + .WithDelay(data.delay) + .WithEasing(data.easingType); + + IAnimation animation; + + switch (data.type) + { + case AnimationType.Fade: + animation = builder.AsFade() + .From(data.fromAlpha) + .To(data.toAlpha) + .Build(); + break; + + case AnimationType.Move: + var moveBuilder = builder.AsMove() + .From(data.fromPosition) + .To(data.toPosition); + + if (data.useLocalPosition) + moveBuilder.Local(); + else if (data.useAnchoredPosition) + moveBuilder.Anchored(); + + animation = moveBuilder.Build(); + break; + + case AnimationType.Scale: + animation = builder.AsScale() + .From(data.fromScale) + .To(data.toScale) + .Build(); + break; + + case AnimationType.Rotate: + animation = builder.AsRotate() + .FromEuler(data.fromEulerAngles) + .ToEuler(data.toEulerAngles) + .Build(); + break; + + case AnimationType.Color: + var colorBuilder = builder.AsColor() + .From(data.fromColor) + .To(data.toColor); + + if (data.isTextColor) + colorBuilder.AsTextColor(); + + animation = colorBuilder.Build(); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + return animation; + } + } +} \ No newline at end of file diff --git a/Runtime/Data/AnimationCollection.cs.meta b/Runtime/Data/AnimationCollection.cs.meta new file mode 100644 index 0000000..5e213b1 --- /dev/null +++ b/Runtime/Data/AnimationCollection.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 19427cdf82c041459cba5387f8783925 +timeCreated: 1747861458 \ No newline at end of file diff --git a/Runtime/Data/AnimationData.cs b/Runtime/Data/AnimationData.cs new file mode 100644 index 0000000..15ebb87 --- /dev/null +++ b/Runtime/Data/AnimationData.cs @@ -0,0 +1,41 @@ +using System; +using DC.Animator.Data; +using DC.Animator.Utils; +using UnityEngine; + +namespace DCAnimator.Data +{ + [Serializable] + public class AnimationData + { + // Core properties + public string name; + public AnimationCollection.AnimationType type; + public float duration = 0.5f; + public float delay; + public Easing.Type easingType = Easing.Type.EaseOutQuad; + + // Fade properties + public float fromAlpha; + public float toAlpha = 1f; + + // Move properties + public Vector3 fromPosition; + public Vector3 toPosition; + public bool useLocalPosition = true; + public bool useAnchoredPosition; + + // Scale properties + public Vector3 fromScale = Vector3.one; + public Vector3 toScale = Vector3.one; + + // Rotate properties + public Vector3 fromEulerAngles; + public Vector3 toEulerAngles; + + // Color properties + public Color fromColor = Color.white; + public Color toColor = Color.white; + public bool isTextColor; + } +} \ No newline at end of file diff --git a/Runtime/Data/AnimationData.cs.meta b/Runtime/Data/AnimationData.cs.meta new file mode 100644 index 0000000..2d1dd7e --- /dev/null +++ b/Runtime/Data/AnimationData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5c42bc264cb1491aae30842803feb809 +timeCreated: 1748092986 \ No newline at end of file diff --git a/Runtime/Utils.meta b/Runtime/Utils.meta new file mode 100644 index 0000000..81b0acb --- /dev/null +++ b/Runtime/Utils.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b1241ae5d1614af4a88116a9e43b8bf5 +timeCreated: 1748092717 \ No newline at end of file diff --git a/Runtime/Utils/EasingFunctions.cs b/Runtime/Utils/EasingFunctions.cs new file mode 100644 index 0000000..e45861d --- /dev/null +++ b/Runtime/Utils/EasingFunctions.cs @@ -0,0 +1,278 @@ +using UnityEngine; + +namespace DC.Animator.Utils +{ + public static class Easing + { + public delegate float Function(float t); + + public enum Type + { + Linear, + EaseInSine, + EaseOutSine, + EaseInOutSine, + EaseInQuad, + EaseOutQuad, + EaseInOutQuad, + EaseInCubic, + EaseOutCubic, + EaseInOutCubic, + EaseInQuart, + EaseOutQuart, + EaseInOutQuart, + EaseInQuint, + EaseOutQuint, + EaseInOutQuint, + EaseInExpo, + EaseOutExpo, + EaseInOutExpo, + EaseInCirc, + EaseOutCirc, + EaseInOutCirc, + EaseInBack, + EaseOutBack, + EaseInOutBack, + EaseInElastic, + EaseOutElastic, + EaseInOutElastic, + EaseInBounce, + EaseOutBounce, + EaseInOutBounce + } + + private const float PI = Mathf.PI; + private const float C1 = 1.70158f; + private const float C2 = C1 * 1.525f; + private const float C3 = C1 + 1f; + private const float C4 = 2f * PI / 3f; + private const float C5 = 2f * PI / 4.5f; + + public static Function GetEasingFunction(Type type) + { + return type switch + { + Type.Linear => Linear, + Type.EaseInSine => EaseInSine, + Type.EaseOutSine => EaseOutSine, + Type.EaseInOutSine => EaseInOutSine, + Type.EaseInQuad => EaseInQuad, + Type.EaseOutQuad => EaseOutQuad, + Type.EaseInOutQuad => EaseInOutQuad, + Type.EaseInCubic => EaseInCubic, + Type.EaseOutCubic => EaseOutCubic, + Type.EaseInOutCubic => EaseInOutCubic, + Type.EaseInQuart => EaseInQuart, + Type.EaseOutQuart => EaseOutQuart, + Type.EaseInOutQuart => EaseInOutQuart, + Type.EaseInQuint => EaseInQuint, + Type.EaseOutQuint => EaseOutQuint, + Type.EaseInOutQuint => EaseInOutQuint, + Type.EaseInExpo => EaseInExpo, + Type.EaseOutExpo => EaseOutExpo, + Type.EaseInOutExpo => EaseInOutExpo, + Type.EaseInCirc => EaseInCirc, + Type.EaseOutCirc => EaseOutCirc, + Type.EaseInOutCirc => EaseInOutCirc, + Type.EaseInBack => EaseInBack, + Type.EaseOutBack => EaseOutBack, + Type.EaseInOutBack => EaseInOutBack, + Type.EaseInElastic => EaseInElastic, + Type.EaseOutElastic => EaseOutElastic, + Type.EaseInOutElastic => EaseInOutElastic, + Type.EaseInBounce => EaseInBounce, + Type.EaseOutBounce => EaseOutBounce, + Type.EaseInOutBounce => EaseInOutBounce, + _ => Linear + }; + } + + public static float Linear(float t) + { + return t; + } + + public static float EaseInSine(float t) + { + return 1f - Mathf.Cos(t * PI / 2f); + } + + public static float EaseOutSine(float t) + { + return Mathf.Sin(t * PI / 2f); + } + + public static float EaseInOutSine(float t) + { + return -(Mathf.Cos(PI * t) - 1f) / 2f; + } + + public static float EaseInQuad(float t) + { + return t * t; + } + + public static float EaseOutQuad(float t) + { + return 1f - (1f - t) * (1f - t); + } + + public static float EaseInOutQuad(float t) + { + return t < 0.5f ? 2f * t * t : 1f - Mathf.Pow(-2f * t + 2f, 2f) / 2f; + } + + public static float EaseInCubic(float t) + { + return t * t * t; + } + + public static float EaseOutCubic(float t) + { + return 1f - Mathf.Pow(1f - t, 3f); + } + + public static float EaseInOutCubic(float t) + { + return t < 0.5f ? 4f * t * t * t : 1f - Mathf.Pow(-2f * t + 2f, 3f) / 2f; + } + + public static float EaseInQuart(float t) + { + return t * t * t * t; + } + + public static float EaseOutQuart(float t) + { + return 1f - Mathf.Pow(1f - t, 4f); + } + + public static float EaseInOutQuart(float t) + { + return t < 0.5f ? 8f * t * t * t * t : 1f - Mathf.Pow(-2f * t + 2f, 4f) / 2f; + } + + public static float EaseInQuint(float t) + { + return t * t * t * t * t; + } + + public static float EaseOutQuint(float t) + { + return 1f - Mathf.Pow(1f - t, 5f); + } + + public static float EaseInOutQuint(float t) + { + return t < 0.5f ? 16f * t * t * t * t * t : 1f - Mathf.Pow(-2f * t + 2f, 5f) / 2f; + } + + public static float EaseInExpo(float t) + { + return t == 0f ? 0f : Mathf.Pow(2f, 10f * t - 10f); + } + + public static float EaseOutExpo(float t) + { + return t == 1f ? 1f : 1f - Mathf.Pow(2f, -10f * t); + } + + public static float EaseInOutExpo(float t) + { + return t == 0f ? 0f : + t == 1f ? 1f : + t < 0.5f ? Mathf.Pow(2f, 20f * t - 10f) / 2f : + (2f - Mathf.Pow(2f, -20f * t + 10f)) / 2f; + } + + public static float EaseInCirc(float t) + { + return 1f - Mathf.Sqrt(1f - Mathf.Pow(t, 2f)); + } + + public static float EaseOutCirc(float t) + { + return Mathf.Sqrt(1f - Mathf.Pow(t - 1f, 2f)); + } + + public static float EaseInOutCirc(float t) + { + return t < 0.5f + ? (1f - Mathf.Sqrt(1f - Mathf.Pow(2f * t, 2f))) / 2f + : (Mathf.Sqrt(1f - Mathf.Pow(-2f * t + 2f, 2f)) + 1f) / 2f; + } + + public static float EaseInBack(float t) + { + return C3 * t * t * t - C1 * t * t; + } + + public static float EaseOutBack(float t) + { + return 1f + C3 * Mathf.Pow(t - 1f, 3f) + C1 * Mathf.Pow(t - 1f, 2f); + } + + public static float EaseInOutBack(float t) + { + return t < 0.5f + ? Mathf.Pow(2f * t, 2f) * ((C2 + 1f) * 2f * t - C2) / 2f + : (Mathf.Pow(2f * t - 2f, 2f) * ((C2 + 1f) * (t * 2f - 2f) + C2) + 2f) / 2f; + } + + public static float EaseInElastic(float t) + { + return t switch + { + 0f => 0f, + 1f => 1f, + _ => -Mathf.Pow(2f, 10f * t - 10f) * Mathf.Sin((t * 10f - 10.75f) * C4) + }; + } + + public static float EaseOutElastic(float t) + { + return t switch + { + 0f => 0f, + 1f => 1f, + _ => Mathf.Pow(2f, -10f * t) * Mathf.Sin((t * 10f - 0.75f) * C4) + 1f + }; + } + + public static float EaseInOutElastic(float t) + { + return t == 0f ? 0f : + t == 1f ? 1f : + t < 0.5f ? -(Mathf.Pow(2f, 20f * t - 10f) * Mathf.Sin((20f * t - 11.125f) * C5)) / 2f : + Mathf.Pow(2f, -20f * t + 10f) * Mathf.Sin((20f * t - 11.125f) * C5) / 2f + 1f; + } + + public static float EaseInBounce(float t) + { + return 1f - EaseOutBounce(1f - t); + } + + public static float EaseOutBounce(float t) + { + switch (t) + { + case < 1f / 2.75f: + return 7.5625f * t * t; + case < 2f / 2.75f: + t -= 1.5f / 2.75f; + return 7.5625f * t * t + 0.75f; + case < 2.5f / 2.75f: + t -= 2.25f / 2.75f; + return 7.5625f * t * t + 0.9375f; + default: + t -= 2.625f / 2.75f; + return 7.5625f * t * t + 0.984375f; + } + } + + public static float EaseInOutBounce(float t) + { + return t < 0.5f ? (1f - EaseOutBounce(1f - 2f * t)) / 2f : (1f + EaseOutBounce(2f * t - 1f)) / 2f; + } + } +} \ No newline at end of file diff --git a/Runtime/Utils/EasingFunctions.cs.meta b/Runtime/Utils/EasingFunctions.cs.meta new file mode 100644 index 0000000..d24e9a2 --- /dev/null +++ b/Runtime/Utils/EasingFunctions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 999e76d81bee4d159317479117798d57 +timeCreated: 1747860988 \ No newline at end of file diff --git a/Runtime/Utils/ObjectPool.cs b/Runtime/Utils/ObjectPool.cs new file mode 100644 index 0000000..4a6f41f --- /dev/null +++ b/Runtime/Utils/ObjectPool.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; + +namespace DC.Animator.Utils +{ + public class ObjectPool where T : class + { + private readonly Stack _pool = new Stack(); + private readonly Func _createFunc; + + public ObjectPool(Func createFunc) => _createFunc = createFunc; + + public T Get() => _pool.Count > 0 ? _pool.Pop() : _createFunc(); + + public void Return(T obj) => _pool.Push(obj); + + public void Clear() => _pool.Clear(); + + public int Count => _pool.Count; + } +} \ No newline at end of file diff --git a/Runtime/Utils/ObjectPool.cs.meta b/Runtime/Utils/ObjectPool.cs.meta new file mode 100644 index 0000000..ce32d51 --- /dev/null +++ b/Runtime/Utils/ObjectPool.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a9ab03e1fa84423481b0a96d7299431b +timeCreated: 1747860957 \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..2eae512 --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "name": "com.danielcumbor.dcanimator", + "version": "2.0.0", + "displayName": "DC Animator", + "description": "A custom Unity tool for animating objects.", + "unity": "6000.0", + "unityRelease": "23f1", + "author": { + "name": "Daniel Cumbor", + "email": "danc@ultr.uk", + "url": "https://www.danielcumbor.uk" + } +} \ No newline at end of file diff --git a/package.json.meta b/package.json.meta new file mode 100644 index 0000000..191ac46 --- /dev/null +++ b/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 124a82e8e8b1b684e88cc1017d606c62 +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: