Reupload to new git vps.

This commit is contained in:
Daniel Cumbor 2025-07-13 19:33:06 +01:00
commit 8ad72ae00b
57 changed files with 2290 additions and 0 deletions

16
DC.Animator.asmdef Normal file
View file

@ -0,0 +1,16 @@
{
"name": "DC.Animator",
"rootNamespace": "",
"references": [
"GUID:6055be8ebefd69e48b49212b09b47b2f"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

7
DC.Animator.asmdef.meta Normal file
View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: fd7612f2de54f1e46a60c1460f826a43
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Editor.meta Normal file
View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a60c3d1cd509697419e16c967dfffc14
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e980dad5c4f248808f571603257f2611
timeCreated: 1747861571

View file

@ -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<AnimationEditorWindow>("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<AnimationCollection>();
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<Image>();
if (image)
adapter = new ImageAdapter(image);
var text = _targetObject.GetComponent<TextMeshProUGUI>();
if (text)
adapter = new TMPTextAdapter(text);
var tmpro = _targetObject.GetComponent<TextMeshPro>();
if (tmpro)
adapter = new TMPTextAdapter(tmpro);
var spriteRenderer = _targetObject.GetComponent<SpriteRenderer>();
if (spriteRenderer)
adapter = new SpriteAdapter(spriteRenderer);
var rectTransform = _targetObject.GetComponent<RectTransform>();
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

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f24aeb6fb1654955ac87e118100d8b1d
timeCreated: 1747861633

8
Runtime.meta Normal file
View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e657351d63ffca146a291a3fe1b517b0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

3
Runtime/Adapters.meta Normal file
View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 56735d71953b4e5385da5122c22cd6e1
timeCreated: 1747861237

View file

@ -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}")
};
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6c004264ae534a60b0acc1e9b0a1fabf
timeCreated: 1747861252

View file

@ -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}")
};
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3445d296a0bb42dc8cfe1d0f4ab762a1
timeCreated: 1747861417

View file

@ -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}")
};
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 81eaeba71eb74408976c0dbc72a8a454
timeCreated: 1747861361

View file

@ -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}");
}
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d707c0a42bba4df2bde5731ebda18905
timeCreated: 1747861307

View file

@ -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}")
};
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 12a9475c333d43d0ade1f05f8bfd1283
timeCreated: 1747861386

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8c757291c27645019681e3bb8f24ef0f
timeCreated: 1747861055

View file

@ -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;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 906d0b3b5c8a480cbca966bd4f505e12
timeCreated: 1747861219

View file

@ -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;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 87ca0a0406324a70a8a5f7e8bd289a99
timeCreated: 1747861075

View file

@ -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;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 800d1b5a42e24886b87d95dab0e1df99
timeCreated: 1747861100

View file

@ -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;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 735103945dcb47a9b677d3f57350514f
timeCreated: 1747861191

View file

@ -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;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7b6cf6ed822b434d9635fa7841093483
timeCreated: 1747861159

3
Runtime/Core.meta Normal file
View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7305d0795bef4bc7b5554a9a57e6d05d
timeCreated: 1748092703

View file

@ -0,0 +1,15 @@
namespace DC.Animator.Core
{
public enum AnimatableProperty
{
Position,
LocalPosition,
AnchoredPosition,
Scale,
Rotation,
EulerAngles,
Alpha,
Color,
TextColor
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8be1c4fca1da458487554a4860fbd09d
timeCreated: 1747860604

185
Runtime/Core/Animation.cs Normal file
View file

@ -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<AnimatableProperty, AnimationProperty> _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<IAnimation> OnStart;
public event Action<IAnimation> OnComplete;
public event Action<IAnimation> 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;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a3d35500f1f6469cb3baa292cfc1f882
timeCreated: 1747860896

View file

@ -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<IAnimation> _onStart;
private Action<IAnimation> _onComplete;
private Action<IAnimation> _onUpdate;
private static readonly Dictionary<Type, Func<object, IAnimatable>> AdapterFactories = new();
static AnimationBuilder()
{
RegisterAdapter<UnityEngine.UI.Image>((img) => new ImageAdapter(img));
RegisterAdapter<TMPro.TextMeshProUGUI>((text) => new TMPTextAdapter(text));
RegisterAdapter<TMPro.TextMeshPro>((text) => new TMPTextAdapter(text));
RegisterAdapter<SpriteRenderer>((sprite) => new SpriteAdapter(sprite));
RegisterAdapter<Transform>((transform) => new TransformAdapter(transform));
RegisterAdapter<RectTransform>((rectTransform) => new RectTransformAdapter(rectTransform));
}
public static void RegisterAdapter<T>(Func<T, IAnimatable> 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>(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<IAnimation> callback)
{
_onStart = callback;
return this;
}
public AnimationBuilder OnComplete(Action<IAnimation> callback)
{
_onComplete = callback;
return this;
}
public AnimationBuilder OnUpdate(Action<IAnimation> 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;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7363902fe7234f8296b9860043ae5a31
timeCreated: 1747861027

View file

@ -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<IAnimation> _activeAnimations = new();
private readonly ObjectPool<Animation> _animationPool = new(() => new Animation());
private readonly List<IAnimation> _pendingAdditions = new();
private readonly List<IAnimation> _pendingRemovals = new();
public static AnimationRuntime Instance
{
get
{
if (_instance) return _instance;
var go = new GameObject("AnimationManager");
_instance = go.AddComponent<AnimationRuntime>();
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;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e9a1adb612d743eb87fca704d4335d1b
timeCreated: 1747860933

View file

@ -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<IAnimation> callback)
{
BaseBuilder.OnStart(callback);
return this;
}
public AnimationTypeBuilderBase OnComplete(Action<IAnimation> callback)
{
BaseBuilder.OnComplete(callback);
return this;
}
public AnimationTypeBuilderBase OnUpdate(Action<IAnimation> 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;
}
}
}

View file

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b3992f2125ccd5e4686b9f5aba900567

View file

@ -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);
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b60cedf76ef14da8830e3b09f87fed52
timeCreated: 1747860577

View file

@ -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<IAnimation> OnStart;
event Action<IAnimation> OnComplete;
event Action<IAnimation> OnUpdate;
}
}

View file

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 81f201c1b2e3c4845b9becc70b689633

3
Runtime/Data.meta Normal file
View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e430bcc3743b4759ae5d6319ba0c6203
timeCreated: 1747861443

View file

@ -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<AnimationData> 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;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 19427cdf82c041459cba5387f8783925
timeCreated: 1747861458

View file

@ -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;
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5c42bc264cb1491aae30842803feb809
timeCreated: 1748092986

3
Runtime/Utils.meta Normal file
View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b1241ae5d1614af4a88116a9e43b8bf5
timeCreated: 1748092717

View file

@ -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;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 999e76d81bee4d159317479117798d57
timeCreated: 1747860988

View file

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
namespace DC.Animator.Utils
{
public class ObjectPool<T> where T : class
{
private readonly Stack<T> _pool = new Stack<T>();
private readonly Func<T> _createFunc;
public ObjectPool(Func<T> 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;
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a9ab03e1fa84423481b0a96d7299431b
timeCreated: 1747860957

13
package.json Normal file
View file

@ -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"
}
}

7
package.json.meta Normal file
View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 124a82e8e8b1b684e88cc1017d606c62
PackageManifestImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: