From 60d6fe67e2011e2f9e94e42ecffd1ee0b7c336a9 Mon Sep 17 00:00:00 2001 From: Onur Balci Date: Tue, 18 Mar 2025 14:11:24 +0000 Subject: [PATCH 01/55] Add sequence ease support --- .../LitMotion/Runtime/MotionSequenceBuilder.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceBuilder.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceBuilder.cs index c4494013..e4afd2ee 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceBuilder.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceBuilder.cs @@ -39,6 +39,7 @@ public static void Return(MotionSequenceBuilderSource source) MotionSequenceBuilderSource next; ushort version; MotionSequenceItem[] buffer; + Ease ease; int count; double tail; double lastTail; @@ -70,10 +71,16 @@ public void Join(MotionHandle handle) Insert(lastTail, handle); } + public void WithEase(Ease ease) + { + this.ease = ease; + } + public MotionHandle Schedule(Action> configuration) { var source = MotionSequenceSource.Rent(); var builder = LMotion.Create(0.0, duration, (float)duration) + .WithEase(ease) .WithOnComplete(source.OnCompleteDelegate) .WithOnCancel(source.OnCancelDelegate); @@ -148,6 +155,14 @@ public readonly MotionSequenceBuilder Join(MotionHandle handle) return this; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly MotionSequenceBuilder WithEase(Ease ease) + { + CheckIsDisposed(); + source.WithEase(ease); + return this; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public MotionHandle Run() { From b48161bcfdda3ff09ebb57bb32d7e7284190d2ac Mon Sep 17 00:00:00 2001 From: Onur Balci Date: Wed, 26 Mar 2025 11:39:01 +0000 Subject: [PATCH 02/55] Add sequence test --- .../LitMotion/Tests/Runtime/SequenceTest.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/LitMotion/Assets/LitMotion/Tests/Runtime/SequenceTest.cs b/src/LitMotion/Assets/LitMotion/Tests/Runtime/SequenceTest.cs index 6a629b87..dd41452d 100644 --- a/src/LitMotion/Assets/LitMotion/Tests/Runtime/SequenceTest.cs +++ b/src/LitMotion/Assets/LitMotion/Tests/Runtime/SequenceTest.cs @@ -193,5 +193,41 @@ public void Test_Error_UseMotionHandleInSequence() handle.Time = 0; }, "Cannot access the motion in sequence."); } + + [UnityTest] + public IEnumerator Test_SequenceWithEase() + { + var x1 = 0f; + var x2 = 0f; + Ease ease = Ease.InExpo; + + var motionHandle = LSequence.Create() + .Append(LMotion.Create(0f, 1f, 5f).Bind(v => x1 = v)) + .Append(LMotion.Create(0f, 1f, 5f).Bind(v => x2 = v)) + .WithEase(ease) + .Run(); + + motionHandle.Preserve(); + + for (int i = 1; i <= 10; i++) + { + yield return new WaitForSeconds(1f); + float sequenceProgress = (float)motionHandle.Time / 10f; + float sequenceEasedTime = EaseUtility.Evaluate(sequenceProgress, ease); + Assert.AreEqual(GetX1Time(sequenceEasedTime), x1, 0.01f, $"iteration: {i}"); + Assert.AreEqual(GetX2Time(sequenceEasedTime), x2, 0.01f, $"iteration: {i}"); + } + yield break; + + float GetX1Time(float time) + { + return Mathf.Clamp01(time / 0.5f); + } + + float GetX2Time(float time) + { + return Mathf.Clamp01((time - 0.5f) / 0.5f); + } + } } } From 4e7ceed7c11273d81b1670cb34b4ef7557782d74 Mon Sep 17 00:00:00 2001 From: {} Date: Wed, 23 Apr 2025 15:21:02 +0900 Subject: [PATCH 03/55] Bugfix: Endless exception loop when exiting prefab mode --- .../Editor/LitMotionAnimationEditor.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs b/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs index e9bcd1cd..72b2dcfa 100644 --- a/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs +++ b/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs @@ -3,6 +3,7 @@ using UnityEditor.UIElements; using System.Collections.Generic; using UnityEngine; +using UnityEditor.SceneManagement; namespace LitMotion.Animation.Editor { @@ -192,7 +193,10 @@ VisualElement CreateDebugPanel() flexGrow = 1f, } }; - var playButton = new Button(() => ((LitMotionAnimation)target).Play()) + var playButton = new Button(() => { + ((LitMotionAnimation)target).Play(); + PrefabStage.prefabStageClosing += OnPrefabStageClosing; + }) { text = "Play", style = { @@ -345,5 +349,14 @@ bool IsActive() { return !((LitMotionAnimation)target).IsActive; } + + void OnPrefabStageClosing(PrefabStage stage) + { + PrefabStage.prefabStageClosing -= OnPrefabStageClosing; + foreach (var i in stage.prefabContentsRoot.GetComponentsInChildren(true)) + { + i.Stop(); + } + } } -} \ No newline at end of file +} From 2e21d8181831943a6521cff7d1b74252c82c7086 Mon Sep 17 00:00:00 2001 From: {} Date: Thu, 24 Apr 2025 00:16:26 +0900 Subject: [PATCH 04/55] Prevent duplicate event registration --- .../Editor/LitMotionAnimationEditor.cs | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs b/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs index 72b2dcfa..55576579 100644 --- a/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs +++ b/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs @@ -194,9 +194,13 @@ VisualElement CreateDebugPanel() } }; var playButton = new Button(() => { - ((LitMotionAnimation)target).Play(); - PrefabStage.prefabStageClosing += OnPrefabStageClosing; - }) + ((LitMotionAnimation)target).Play(); + if (PrefabStageUtility.GetCurrentPrefabStage() != null) + { + PrefabStage.prefabStageClosing -= OnPrefabStageClosing; + PrefabStage.prefabStageClosing += OnPrefabStageClosing; + } + }) { text = "Play", style = { @@ -350,13 +354,13 @@ bool IsActive() return !((LitMotionAnimation)target).IsActive; } - void OnPrefabStageClosing(PrefabStage stage) - { - PrefabStage.prefabStageClosing -= OnPrefabStageClosing; - foreach (var i in stage.prefabContentsRoot.GetComponentsInChildren(true)) - { - i.Stop(); - } - } + void OnPrefabStageClosing(PrefabStage stage) + { + PrefabStage.prefabStageClosing -= OnPrefabStageClosing; + foreach (var i in stage.prefabContentsRoot.GetComponentsInChildren(true)) + { + i.Stop(); + } + } } } From 20a6c3fb67090c72a1d0cfa27b7a2cce8f38f933 Mon Sep 17 00:00:00 2001 From: {} Date: Wed, 25 Jun 2025 11:38:51 +0900 Subject: [PATCH 05/55] Feature: color change for sprite SubMeshUI --- .../Runtime/Components/TextMeshProComponents.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/TextMeshProComponents.cs b/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/TextMeshProComponents.cs index 9da1e06d..f0ed189d 100644 --- a/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/TextMeshProComponents.cs +++ b/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/TextMeshProComponents.cs @@ -82,6 +82,19 @@ protected override void SetValue(TMP_Text target, in float value) target.color = c; } } + [Serializable] + [LitMotionAnimationComponentMenu("UI/TextMesh Pro/Color (For Sprite)")] + public sealed class TMPTextColorCanvasRendererAnimation : ColorPropertyAnimationComponent + { + protected override Color GetValue(TextMeshProUGUI target) => target.canvasRenderer.GetColor(); + protected override void SetValue(TextMeshProUGUI target, in Color value) + { + var c = target.color; + c.a = value.a; + target.color = c; + target.canvasRenderer.SetColor(value); + } + } } #endif \ No newline at end of file From 1cdd9e30441b7cd5041c47dd0578b648982aa1cf Mon Sep 17 00:00:00 2001 From: {} Date: Wed, 25 Jun 2025 13:09:51 +0900 Subject: [PATCH 06/55] Fix: "Duplicate Array Element" in the context menu of LitMotionAnimation caused shared references --- .../Editor/LitMotionAnimationEditor.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs b/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs index e9bcd1cd..560fe496 100644 --- a/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs +++ b/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs @@ -145,6 +145,27 @@ VisualElement CreateComponentsPanel() { if (componentsProperty.arraySize != prevArraySize) { + if (prevArraySize < componentsProperty.arraySize) + { + var last_prop = componentsProperty.GetArrayElementAtIndex(componentsProperty.arraySize - 1); + var last = last_prop.managedReferenceValue; + object src = null; + for (int i = 0; i < componentsProperty.arraySize - 1; ++i) + { + var value = componentsProperty.GetArrayElementAtIndex(i).managedReferenceValue; + if (value == last) + { + src = value; + break; + } + } + if (src != null) + { + var cloned = JsonUtility.FromJson(JsonUtility.ToJson(src), src.GetType()); + last_prop.managedReferenceValue = cloned; + serializedObject.ApplyModifiedProperties(); + } + } RefleshComponentsView(true); prevArraySize = componentsProperty.arraySize; } From 15016d8ff1f7535c12311110da52f6e4bc1131aa Mon Sep 17 00:00:00 2001 From: {} Date: Wed, 25 Jun 2025 13:44:58 +0900 Subject: [PATCH 07/55] Fix: Color doesn't reset after pressing the Stop button --- .../Runtime/Components/TextMeshProComponents.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/TextMeshProComponents.cs b/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/TextMeshProComponents.cs index f0ed189d..484d848a 100644 --- a/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/TextMeshProComponents.cs +++ b/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/TextMeshProComponents.cs @@ -89,9 +89,7 @@ public sealed class TMPTextColorCanvasRendererAnimation : ColorPropertyAnimation protected override Color GetValue(TextMeshProUGUI target) => target.canvasRenderer.GetColor(); protected override void SetValue(TextMeshProUGUI target, in Color value) { - var c = target.color; - c.a = value.a; - target.color = c; + target.havePropertiesChanged = true; target.canvasRenderer.SetColor(value); } } From 651d216057ca5853e40e90366c2f8bee1e9414fc Mon Sep 17 00:00:00 2001 From: {} Date: Wed, 25 Jun 2025 15:18:14 +0900 Subject: [PATCH 08/55] Add feature solo-playing --- .../Editor/LitMotionAnimationEditor.cs | 17 +++++++++++ .../Runtime/LitMotionAnimation.cs | 28 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs b/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs index e9bcd1cd..ba82b397 100644 --- a/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs +++ b/src/LitMotion/Assets/LitMotion.Animation/Editor/LitMotionAnimationEditor.cs @@ -95,6 +95,23 @@ VisualElement CreateSettingsPanel() var box = CreateBox("Settings"); box.Add(new PropertyField(serializedObject.FindProperty("playOnAwake"))); box.Add(new PropertyField(serializedObject.FindProperty("animationMode"))); + box.Add(new PropertyField(serializedObject.FindProperty("solo"))); + var row = new VisualElement(); + row.style.flexDirection = FlexDirection.Row; + row.Add(new PropertyField(serializedObject.FindProperty("GroupId"), "Group ID, Source") + { + style = { + flexGrow = 1, + marginRight = 4 + } + }); + row.Add(new PropertyField(serializedObject.FindProperty("groupIdSource")) + { + style = { + flexGrow = 1, + } + }); + box.Add(row); return box; } diff --git a/src/LitMotion/Assets/LitMotion.Animation/Runtime/LitMotionAnimation.cs b/src/LitMotion/Assets/LitMotion.Animation/Runtime/LitMotionAnimation.cs index 4351b75a..caf53892 100644 --- a/src/LitMotion/Assets/LitMotion.Animation/Runtime/LitMotionAnimation.cs +++ b/src/LitMotion/Assets/LitMotion.Animation/Runtime/LitMotionAnimation.cs @@ -16,17 +16,24 @@ enum AnimationMode [SerializeField] bool playOnAwake = true; [SerializeField] AnimationMode animationMode; + [SerializeField] bool solo; + public string GroupId; + [SerializeField] GameObject groupIdSource; + [SerializeReference] LitMotionAnimationComponent[] components; Queue queue = new(); FastListCore playingComponents; + static HashSet playingLitMotionAnimations = new(); public IReadOnlyList Components => components; void Start() { + if (groupIdSource != null) + GroupId += groupIdSource.GetInstanceID(); if (playOnAwake) Play(); } @@ -79,6 +86,14 @@ public void Play() if (isPlaying) return; playingComponents.Clear(); + if (solo) + { + foreach (var i in playingLitMotionAnimations) + if (i != null) + i.StopByGroupId(GroupId); + playingLitMotionAnimations.RemoveWhere(e => e == null || !e.IsPlaying); + } + playingLitMotionAnimations.Add(this); switch (animationMode) { @@ -148,6 +163,12 @@ public void Stop() queue.Clear(); } + public void StopByGroupId(string id) + { + if (GroupId == id || string.IsNullOrEmpty(id)) + Stop(); + } + public void Restart() { Stop(); @@ -190,5 +211,12 @@ void OnDestroy() { Stop(); } + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + static void OnDomainReload() + { + playingLitMotionAnimations = new(); + } + } } \ No newline at end of file From d713b92636b16ae5975dea4c14addbed47408151 Mon Sep 17 00:00:00 2001 From: {} Date: Thu, 26 Jun 2025 13:40:11 +0900 Subject: [PATCH 09/55] Changed the timing of GroupID calculation to Awake --- .../LitMotion.Animation/Runtime/LitMotionAnimation.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/LitMotion/Assets/LitMotion.Animation/Runtime/LitMotionAnimation.cs b/src/LitMotion/Assets/LitMotion.Animation/Runtime/LitMotionAnimation.cs index caf53892..e62fc5f6 100644 --- a/src/LitMotion/Assets/LitMotion.Animation/Runtime/LitMotionAnimation.cs +++ b/src/LitMotion/Assets/LitMotion.Animation/Runtime/LitMotionAnimation.cs @@ -30,10 +30,14 @@ enum AnimationMode public IReadOnlyList Components => components; - void Start() + void Awake() { if (groupIdSource != null) GroupId += groupIdSource.GetInstanceID(); + } + + void Start() + { if (playOnAwake) Play(); } From 43df1ba98730b303ad573c08edbb6f8ed162ec4a Mon Sep 17 00:00:00 2001 From: {} Date: Thu, 26 Jun 2025 22:45:09 +0900 Subject: [PATCH 10/55] bugfix --- .../Runtime/LitMotionAnimation.cs | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/LitMotion/Assets/LitMotion.Animation/Runtime/LitMotionAnimation.cs b/src/LitMotion/Assets/LitMotion.Animation/Runtime/LitMotionAnimation.cs index e62fc5f6..a34163b5 100644 --- a/src/LitMotion/Assets/LitMotion.Animation/Runtime/LitMotionAnimation.cs +++ b/src/LitMotion/Assets/LitMotion.Animation/Runtime/LitMotionAnimation.cs @@ -26,7 +26,7 @@ enum AnimationMode Queue queue = new(); FastListCore playingComponents; - static HashSet playingLitMotionAnimations = new(); + static List playingLitMotionAnimations = new(); public IReadOnlyList Components => components; @@ -92,12 +92,15 @@ public void Play() playingComponents.Clear(); if (solo) { - foreach (var i in playingLitMotionAnimations) - if (i != null) - i.StopByGroupId(GroupId); - playingLitMotionAnimations.RemoveWhere(e => e == null || !e.IsPlaying); + for (int i = playingLitMotionAnimations.Count - 1; 0 <= i; --i) + { + var anim = playingLitMotionAnimations[i]; + if (anim == null || anim.StopByGroupId(GroupId)) + playingLitMotionAnimations.RemoveAt(i); + } } - playingLitMotionAnimations.Add(this); + if (!playingLitMotionAnimations.Contains(this)) + playingLitMotionAnimations.Add(this); switch (animationMode) { @@ -167,10 +170,14 @@ public void Stop() queue.Clear(); } - public void StopByGroupId(string id) + public bool StopByGroupId(string id) { if (GroupId == id || string.IsNullOrEmpty(id)) + { Stop(); + return true; + } + return false; } public void Restart() From c1ef320b56217dc675280e62d0da602ed047dd99 Mon Sep 17 00:00:00 2001 From: Rotanticu <1410722798@qq.com> Date: Thu, 17 Jul 2025 04:35:56 +0800 Subject: [PATCH 11/55] ignore .meta file --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 09bd2548..3c3fe90e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.DS_Store # Project for Asset Store -src/LitMotion.AssetStore/* \ No newline at end of file +src/LitMotion.AssetStore/* +*.meta From 365cd4550ffe8c3c5b937ecc7d818e9ff62ad0f0 Mon Sep 17 00:00:00 2001 From: Rotanticu <1410722798@qq.com> Date: Thu, 17 Jul 2025 04:36:10 +0800 Subject: [PATCH 12/55] fix error --- .../Assets/Samples/0. Basic/7. Coroutine/Sample_0_Coroutine.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/samples/LitMotion.Samples/Assets/Samples/0. Basic/7. Coroutine/Sample_0_Coroutine.cs b/samples/LitMotion.Samples/Assets/Samples/0. Basic/7. Coroutine/Sample_0_Coroutine.cs index d0d7c077..287b89d3 100644 --- a/samples/LitMotion.Samples/Assets/Samples/0. Basic/7. Coroutine/Sample_0_Coroutine.cs +++ b/samples/LitMotion.Samples/Assets/Samples/0. Basic/7. Coroutine/Sample_0_Coroutine.cs @@ -16,8 +16,7 @@ IEnumerator Start() var direction = i % 2 == 0 ? 1 : -1; yield return LMotion.Create(-5f * direction, 5f * direction, 2f) .WithEase(Ease.InOutSine) - .BindToPositionX(targets[i]) - .ToYieldInteraction(); + .BindToPositionX(targets[i]); } } } From dd1ee2182d6014550d4eae78d4231150ef24e7cf Mon Sep 17 00:00:00 2001 From: Rotanticu <1410722798@qq.com> Date: Thu, 17 Jul 2025 04:39:56 +0800 Subject: [PATCH 13/55] Declaration of fork target --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index bea3f6ee..3ef4f02b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +# Main modifications +Vectorize the animation target values to support different animation algorithms such as Tween and Spring. + # LitMotion Lightning-fast and Zero Allocation Tween Library for Unity. From 9093b861521648221cd999bb211aedf5d8f44183 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Thu, 17 Jul 2025 15:15:56 +0800 Subject: [PATCH 14/55] Add animation spec base classes and interfaces Introduces DurationBasedAnimationSpec, LoopBasedAnimationSpec, SpringAnimationSpec, TweenAnimationSpec, and IVectorizedAnimationSpec to define and implement various animation behaviors and interfaces for LitMotion. These additions provide a foundation for duration-based, loop-based, spring, and tween animations with vectorized support. --- .../DurationBasedAnimationSpec.cs | 33 ++ .../AnimationSpec/LoopBasedAnimationSpec.cs | 29 ++ .../AnimationSpec/SpringAnimationSpec.cs | 64 ++++ .../AnimationSpec/TweenAnimationSpec.cs | 314 ++++++++++++++++++ .../AnimationSpec/VectorizedAnimationSpec.cs | 20 ++ 5 files changed, 460 insertions(+) create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/DurationBasedAnimationSpec.cs create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/LoopBasedAnimationSpec.cs create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/SpringAnimationSpec.cs create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/TweenAnimationSpec.cs create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/VectorizedAnimationSpec.cs diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/DurationBasedAnimationSpec.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/DurationBasedAnimationSpec.cs new file mode 100644 index 00000000..53e9b756 --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/DurationBasedAnimationSpec.cs @@ -0,0 +1,33 @@ +using System; +using UnityEngine; + +namespace LitMotion +{ + /// + /// 基于时长的动画规范抽象基类,适用于Tween、Keyframes等有限时长动画。 + /// + public abstract class DurationBasedAnimationSpec : IVectorizedAnimationSpec + where TValue : unmanaged + where TOptions : unmanaged, IMotionOptions + { + public abstract MotionTimeKind TimeKind { get; set; } + + public abstract long DelayNanos { get; set; } + public abstract long DurationNanos { get; set; } + + public abstract bool IsInfinite { get; } + public bool IsDurationBased => true; + + public abstract TValue GetValueFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) + where TAdapter : unmanaged, IMotionAdapter; + public abstract TValue GetVelocityFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) + where TAdapter : unmanaged, IMotionAdapter; + public virtual long GetDurationNanos(TValue startValue, TValue targetValue, TValue startVelocity) + where TAdapter : unmanaged, IMotionAdapter + { + return DurationNanos; + } + public abstract TValue GetEndVelocity(TValue startValue, TValue targetValue, TValue startVelocity) + where TAdapter : unmanaged, IMotionAdapter; + } +} \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/LoopBasedAnimationSpec.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/LoopBasedAnimationSpec.cs new file mode 100644 index 00000000..24332469 --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/LoopBasedAnimationSpec.cs @@ -0,0 +1,29 @@ +using System; +using UnityEngine; + +namespace LitMotion +{ + public abstract class LoopBasedAnimationSpec : DurationBasedAnimationSpec + where TValue : unmanaged + where TOptions : unmanaged, IMotionOptions + { + public abstract int LoopCount { get; set; } + public abstract DelayType DelayType { get; set; } + public abstract LoopType LoopType { get; set; } + + public override bool IsInfinite => LoopCount < 0; + + public long GetDurationNanos() + { + if (IsInfinite) return long.MaxValue; + return DelayNanos * (DelayType == DelayType.EveryLoop ? LoopCount : 1) + DurationNanos * LoopCount; + } + + public override long GetDurationNanos(TValue startValue, TValue targetValue, TValue startVelocity) + { + return GetDurationNanos(); + } + } +} + + \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/SpringAnimationSpec.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/SpringAnimationSpec.cs new file mode 100644 index 00000000..dfa27db0 --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/SpringAnimationSpec.cs @@ -0,0 +1,64 @@ +using System; +using UnityEngine; + +namespace LitMotion +{ + /// + /// 弹簧动画规范,实现基于物理的弹性动画。 + /// + /// 动画值类型 + public class SpringAnimationSpec : IVectorizedAnimationSpec + where TValue : unmanaged + where TOptions : unmanaged, IMotionOptions + { + private MotionTimeKind timeKind; + public MotionTimeKind TimeKind + { + get => timeKind; + set => timeKind = value; + } + + public long _delayNanos; + public long DelayNanos + { + get => _delayNanos; + set => _delayNanos = value < 0 ? 0 : value; + } + + public long DelayMillis + { + get => _delayNanos / AnimationConstants.MillisToNanos; + set => DelayNanos = value * AnimationConstants.MillisToNanos; + } + + public int DelaySeconds + { + get => (int)(_delayNanos / AnimationConstants.SecendsToNanos); + set => DelayNanos = value * AnimationConstants.SecendsToNanos; + } + private bool _isInfinite; + public bool IsInfinite => _isInfinite; + + public bool IsDurationBased => false; + + public TValue GetValueFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) where TAdapter : unmanaged, IMotionAdapter + { + throw new NotImplementedException(); + } + + public TValue GetVelocityFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) where TAdapter : unmanaged, IMotionAdapter + { + throw new NotImplementedException(); + } + + public long GetDurationNanos(TValue startValue, TValue targetValue, TValue startVelocity) where TAdapter : unmanaged, IMotionAdapter + { + throw new NotImplementedException(); + } + + public TValue GetEndVelocity(TValue startValue, TValue targetValue, TValue startVelocity) where TAdapter : unmanaged, IMotionAdapter + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/TweenAnimationSpec.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/TweenAnimationSpec.cs new file mode 100644 index 00000000..86bdc61b --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/TweenAnimationSpec.cs @@ -0,0 +1,314 @@ +using System; +using System.Runtime.CompilerServices; +using Unity.Mathematics; +using UnityEngine; +using Unity.Burst.CompilerServices; +using LitMotion.Collections; + +namespace LitMotion +{ + internal struct TweenAnimationSpec + { +public struct AnimationState + { + public MotionStatus Status; + public MotionStatus PrevStatus; + public bool IsPreserved; + public bool IsInSequence; + + public ushort CompletedLoops; + public ushort PrevCompletedLoops; + + public long playTimeNanos; + public float PlaybackSpeed; + + public readonly bool WasStatusChanged => Status != PrevStatus; + public readonly bool WasLoopCompleted => CompletedLoops > PrevCompletedLoops; + + } + public struct TweenSpecParameters + { + public MotionTimeKind TimeKind; + public long DurationNanos; + public long DelayNanos; + public DelayType DelayType; + public Ease Ease; + public int Loops; + public LoopType LoopType; + +#if LITMOTION_COLLECTIONS_2_0_OR_NEWER + public NativeAnimationCurve AnimationCurve; +#else + public UnsafeAnimationCurve AnimationCurve; +#endif + } + public AnimationState State; + public TweenSpecParameters Parameters; + public Ease Ease + { + get => Parameters.Ease; + set => Parameters.Ease = value; + } + public long TimeSinceStart => State.playTimeNanos - Parameters.DelayNanos; + + // MotionData interface - Update method + public void Update(long playTimeNanos, out float progress) + { + State.PrevCompletedLoops = State.CompletedLoops; + State.PrevStatus = State.Status; + + State.playTimeNanos = playTimeNanos; + playTimeNanos = Math.Max(playTimeNanos, 0); + + double t; + bool isCompleted; + bool isDelayed; + int completedLoops; + int clampedCompletedLoops; + + if (Hint.Unlikely(Parameters.DurationNanos <= 0)) + { + if (Parameters.DelayType == DelayType.FirstLoop || Parameters.DelayNanos == 0f) + { + isCompleted = Parameters.Loops >= 0 && TimeSinceStart > 0f; + if (isCompleted) + { + t = 1f; + completedLoops = Parameters.Loops; + } + else + { + t = 0f; + completedLoops = TimeSinceStart < 0f ? -1 : 0; + } + clampedCompletedLoops = GetClampedCompletedLoops(completedLoops); + isDelayed = TimeSinceStart < 0; + } + else + { + completedLoops = (int)Math.Floor((decimal)(playTimeNanos / Parameters.DelayNanos)); + clampedCompletedLoops = GetClampedCompletedLoops(completedLoops); + isCompleted = Parameters.Loops >= 0 && clampedCompletedLoops > Parameters.Loops - 1; + isDelayed = !isCompleted; + t = isCompleted ? 1f : 0f; + } + } + else + { + if (Parameters.DelayType == DelayType.FirstLoop) + { + completedLoops = (int)Math.Floor((decimal)(TimeSinceStart / Parameters.DurationNanos)); + clampedCompletedLoops = GetClampedCompletedLoops(completedLoops); + isCompleted = Parameters.Loops >= 0 && clampedCompletedLoops > Parameters.Loops - 1; + isDelayed = TimeSinceStart < 0f; + + if (isCompleted) + { + t = 1f; + } + else + { + var currentLoopTime = TimeSinceStart - Parameters.DurationNanos * clampedCompletedLoops; + t = Math.Clamp(currentLoopTime / Parameters.DurationNanos, 0f, 1f); + } + } + else + { + var currentLoopTime = (playTimeNanos % (Parameters.DurationNanos + Parameters.DelayNanos)) - Parameters.DelayNanos; + completedLoops = (int)Math.Floor((decimal)(playTimeNanos / (Parameters.DurationNanos + Parameters.DelayNanos))); + clampedCompletedLoops = GetClampedCompletedLoops(completedLoops); + isCompleted = Parameters.Loops >= 0 && clampedCompletedLoops > Parameters.Loops - 1; + isDelayed = currentLoopTime < 0; + + if (isCompleted) + { + t = 1f; + } + else + { + t = math.clamp(currentLoopTime / Parameters.DurationNanos, 0f, 1f); + } + } + } + State.CompletedLoops = (ushort)clampedCompletedLoops; + + switch (Parameters.LoopType) + { + default: + case LoopType.Restart: + progress = GetEasedValue((float)t); + break; + case LoopType.Flip: + progress = GetEasedValue((float)t); + if ((clampedCompletedLoops + (int)t) % 2 == 1) progress = 1f - progress; + break; + case LoopType.Incremental: + progress = GetEasedValue(1f) * clampedCompletedLoops + GetEasedValue((float)math.fmod(t, 1f)); + break; + case LoopType.Yoyo: + progress = (clampedCompletedLoops + (int)t) % 2 == 1 + ? GetEasedValue((float)(1f - t)) + : GetEasedValue((float)t); + break; + } + + if (isCompleted) + { + State.Status = MotionStatus.Completed; + } + else if (isDelayed || State.playTimeNanos < 0) + { + State.Status = MotionStatus.Delayed; + } + else + { + State.Status = MotionStatus.Playing; + } + } + + // MotionData interface - Complete method + public void Complete(out float progress) + { + State.Status = MotionStatus.Completed; + State.playTimeNanos = Parameters.DurationNanos; + State.CompletedLoops = (ushort)Parameters.Loops; + + progress = GetEasedValue(Parameters.LoopType switch + { + LoopType.Restart => 1f, + LoopType.Flip or LoopType.Yoyo => Parameters.Loops % 2 == 0 ? 0f : 1f, + LoopType.Incremental => Parameters.Loops, + _ => 1f + }); + } + int GetClampedCompletedLoops(int completedLoops) + { + return Parameters.Loops < 0 + ? math.max(0, completedLoops) + : math.clamp(completedLoops, 0, Parameters.Loops); + } + + float GetEasedValue(float value) + { + return Parameters.Ease switch + { + Ease.CustomAnimationCurve => Parameters.AnimationCurve.Evaluate(value), + _ => EaseUtility.Evaluate(value, Parameters.Ease) + }; + } + } + /// + /// Tween animation specification that combines MotionData functionality with vectorized animation support. + /// + /// Type of the animation vector + internal class TweenAnimationSpec : LoopBasedAnimationSpec + where TValue : unmanaged + where TOptions : unmanaged, IMotionOptions + { + // Because of pointer casting, this field must always be placed at the beginning. + public TweenAnimationSpec Core; + + public TValue StartValue; + public TValue EndValue; + public TOptions Options; + + + public override MotionTimeKind TimeKind + { + get => Core.Parameters.TimeKind; + set => Core.Parameters.TimeKind = value; + } + + public override long DelayNanos + { + get => Core.Parameters.DelayNanos; + set => Core.Parameters.DelayNanos = value < 0 ? 0 : value; + } + + public long DelayMillis + { + get => DelayNanos / AnimationConstants.MillisToNanos; + set => DelayNanos = value * AnimationConstants.MillisToNanos; + } + + public int DelaySeconds + { + get => (int)(DelayNanos / AnimationConstants.SecendsToNanos); + set => DelayNanos = value * AnimationConstants.SecendsToNanos; + } + + public override long DurationNanos + { + get => Core.Parameters.DurationNanos; + set => Core.Parameters.DurationNanos = value < 0 ? 0 : value; + } + + public long DurationMillis + { + get => DurationNanos / AnimationConstants.MillisToNanos; + set => DurationNanos = value * AnimationConstants.MillisToNanos; + } + + public int DurationSeconds + { + get => (int)(DurationNanos / AnimationConstants.SecendsToNanos); + set => DurationNanos = value * AnimationConstants.SecendsToNanos; + } + + public override int LoopCount + { + get => Core.Parameters.Loops; + set => Core.Parameters.Loops = value < 0 ? -1 : value; // -1 for infinite loops + } + public override DelayType DelayType + { + get => Core.Parameters.DelayType; + set => Core.Parameters.DelayType = value; + } + public override LoopType LoopType + { + get => Core.Parameters.LoopType; + set => Core.Parameters.LoopType = value; + } + public override TValue GetValueFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) + { + long clampedPlayTimeNanos = Math.Clamp(playTimeNanos, 0, DurationNanos); + Core.Update(clampedPlayTimeNanos, out float fraction); + return default(TAdapter).Evaluate(ref StartValue, ref EndValue, ref Options, new MotionEvaluationContext() + { + Progress = fraction, + Time = clampedPlayTimeNanos, + }); + } + + public override TValue GetVelocityFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) + { + throw new NotImplementedException(); + } + + public override TValue GetEndVelocity(TValue startValue, TValue targetValue, TValue startVelocity) + { + throw new NotImplementedException(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Complete(out TValue result) + where TAdapter : unmanaged, IMotionAdapter + { + Core.Complete(out var progress); + + result = default(TAdapter).Evaluate( + ref StartValue, + ref EndValue, + ref Options, + new() + { + Progress = progress, + Time = Core.State.playTimeNanos, + } + ); + } + } +} + + \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/VectorizedAnimationSpec.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/VectorizedAnimationSpec.cs new file mode 100644 index 00000000..b276014a --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/VectorizedAnimationSpec.cs @@ -0,0 +1,20 @@ +using System; +using UnityEngine; + +namespace LitMotion +{ + public interface IVectorizedAnimationSpec + where TValue : unmanaged + where TOptions : unmanaged, IMotionOptions + { + TValue GetValueFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) + where TAdapter : unmanaged, IMotionAdapter; + TValue GetVelocityFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) + where TAdapter : unmanaged, IMotionAdapter; + long GetDurationNanos(TValue startValue, TValue targetValue, TValue startVelocity) + where TAdapter : unmanaged, IMotionAdapter; + TValue GetEndVelocity(TValue startValue, TValue targetValue, TValue startVelocity) + where TAdapter : unmanaged, IMotionAdapter; + + } +} \ No newline at end of file From f614063a7edb7376f34ba9f46c71c45919e86185 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Thu, 17 Jul 2025 15:18:31 +0800 Subject: [PATCH 15/55] IAnimationSpec and AnimationVector I initially wrote these two, but now I think they may not be necessary. Using IVectorizedAnimationSpec and VectorX should suffice as replacements. Anyway, I'll submit them first, and wait until I decide whether they are needed before pushing them --- .../Runtime/AnimationSpec/AnimationVector.cs | 256 ++++++++++++++++++ .../Runtime/AnimationSpec/IAnimationSpec.cs | 55 ++++ 2 files changed, 311 insertions(+) create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/AnimationVector.cs create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IAnimationSpec.cs diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/AnimationVector.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/AnimationVector.cs new file mode 100644 index 00000000..730ba772 --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/AnimationVector.cs @@ -0,0 +1,256 @@ +using System; +using UnityEngine; + +namespace LitMotion +{ + /// + /// 动画向量接口,所有向量化动画值的基类接口。 + /// + public interface AnimationVector + { + public bool isInitialized + { + get; + protected set; + } + float this[int index] { get; set; } + AnimationVector NewVector(); + void Reset(); + } + + /// + /// 一维动画向量(用float),适用于单通道动画(如透明度、单轴移动等)。 + /// + public struct AnimationVector1D : AnimationVector + { + /// + /// 动画值 + /// + public float Value + { + get; + internal set; + } + private bool _isInitialized; + bool AnimationVector.isInitialized + { + get + { + return _isInitialized; + } + set + { + _isInitialized = value; + } + } + public float this[int index] + { + get => index == 0 ? Value : throw new IndexOutOfRangeException(); + set { if (index == 0) Value = value; else throw new IndexOutOfRangeException(); } + } + public AnimationVector NewVector() => new AnimationVector1D(0f); + public void Reset() { Value = 0f; } + + public AnimationVector1D(float value = 0f) + { + Value = value; + _isInitialized = true; + } + + /// + /// 创建全零新实例 + /// + public static AnimationVector1D NewInstance() => new AnimationVector1D(0f); + /// + /// 深拷贝 + /// + public static AnimationVector1D Copy(AnimationVector1D v) => new AnimationVector1D(v.Value); + /// + /// 从source拷贝到target + /// + public static void CopyFrom(ref AnimationVector1D target, in AnimationVector1D source) => target.Value = source.Value; + } + + /// + /// 二维动画向量(用Vector2),适用于2D平面动画(如位置、缩放等)。 + /// + public struct AnimationVector2D : AnimationVector + { + private bool _isInitialized; + bool AnimationVector.isInitialized + { + get + { + return _isInitialized; + } + set + { + _isInitialized = value; + } + } + /// + /// 动画值(x, y) + /// + [SerializeField] + private Vector2 _value; + public AnimationVector2D(float x = 0f, float y = 0f) + { + _value = new Vector2(x, y); + _isInitialized = true; + } + public AnimationVector2D(Vector2 v) + { + _value = v; + _isInitialized = true; + } + public float this[int index] + { + get => index == 0 ? _value.x : index == 1 ? _value.y : throw new IndexOutOfRangeException(); + set { if (index == 0) _value.x = value; else if (index == 1) _value.y = value; else throw new IndexOutOfRangeException(); } + } + public AnimationVector NewVector() => new AnimationVector2D(0f, 0f); + public void Reset() { _value.x = 0f; _value.y = 0f; } + + /// + /// 创建全零新实例 + /// + public static AnimationVector2D NewInstance() => new AnimationVector2D(0f, 0f); + /// + /// 深拷贝 + /// + public static AnimationVector2D Copy(AnimationVector2D v) => new AnimationVector2D(v._value); + /// + /// 从source拷贝到target + /// + public static void CopyFrom(ref AnimationVector2D target, in AnimationVector2D source) { target._value.x = source._value.x; target._value.y = source._value.y; } + } + + /// + /// 三维动画向量(用Vector3),适用于3D空间动画(如位置、缩放、旋转等)。 + /// + public struct AnimationVector3D : AnimationVector + { + private bool _isInitialized; + bool AnimationVector.isInitialized + { + get + { + return _isInitialized; + } + set + { + _isInitialized = value; + } + } + /// + /// 动画值(x, y, z) + /// + [SerializeField] + private Vector3 _value; + public AnimationVector3D(float x = 0f, float y = 0f, float z = 0f) + { + _value = new Vector3(x, y, z); + _isInitialized = true; + } + public AnimationVector3D(Vector3 v) + { + _value = v; + _isInitialized = true; + } + public float this[int index] + { + get => index == 0 ? _value.x : index == 1 ? _value.y : index == 2 ? _value.z : throw new IndexOutOfRangeException(); + set { if (index == 0) _value.x = value; else if (index == 1) _value.y = value; else if (index == 2) _value.z = value; else throw new IndexOutOfRangeException(); } + } + public AnimationVector NewVector() => new AnimationVector3D(0f, 0f, 0f); + public void Reset() { _value.x = 0f; _value.y = 0f; _value.z = 0f; } + + /// + /// 创建全零新实例 + /// + public static AnimationVector3D NewInstance() => new AnimationVector3D(0f, 0f, 0f); + /// + /// 深拷贝 + /// + public static AnimationVector3D Copy(AnimationVector3D v) => new AnimationVector3D(v._value); + /// + /// 从source拷贝到target + /// + public static void CopyFrom(ref AnimationVector3D target, in AnimationVector3D source) { target._value.x = source._value.x; target._value.y = source._value.y; target._value.z = source._value.z; } + } + + /// + /// 四维动画向量(用Vector4),适用于颜色、四元数等四通道动画。 + /// + public struct AnimationVector4D : AnimationVector + { + private bool _isInitialized; + bool AnimationVector.isInitialized + { + get + { + return _isInitialized; + } + set + { + _isInitialized = value; + } + } + /// + /// 动画值(x, y, z, w) + /// + [SerializeField] + private Vector4 _value; + + public AnimationVector4D(float x = 0f, float y = 0f, float z = 0f, float w = 0f) + { + _value = new Vector4(x, y, z, w); + _isInitialized = true; + } + public AnimationVector4D(Vector4 v) + { + _value = v; + _isInitialized = true; + } + public float this[int index] + { + get + { + switch (index) + { + case 0: return _value.x; + case 1: return _value.y; + case 2: return _value.z; + case 3: return _value.w; + default: throw new IndexOutOfRangeException(); + } + } + set + { + switch (index) + { + case 0: _value.x = value; break; + case 1: _value.y = value; break; + case 2: _value.z = value; break; + case 3: _value.w = value; break; + default: throw new IndexOutOfRangeException(); + } + } + } + public AnimationVector NewVector() => new AnimationVector4D(0f, 0f, 0f, 0f); + public void Reset() { _value.x = 0f; _value.y = 0f; _value.z = 0f; _value.w = 0f; } + + /// + /// 创建全零新实例 + /// + public static AnimationVector4D NewInstance() => new AnimationVector4D(0f, 0f, 0f, 0f); + /// + /// 深拷贝 + /// + public static AnimationVector4D Copy(AnimationVector4D v) => new AnimationVector4D(v._value); + /// + /// 从source拷贝到target + /// + public static void CopyFrom(ref AnimationVector4D target, in AnimationVector4D source) { target._value.x = source._value.x; target._value.y = source._value.y; target._value.z = source._value.z; target._value.w = source._value.w; } + } +} \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IAnimationSpec.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IAnimationSpec.cs new file mode 100644 index 00000000..3cd362c3 --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IAnimationSpec.cs @@ -0,0 +1,55 @@ +using System; + +namespace LitMotion +{ + public static class AnimationConstants + { + /// + /// 默认动画持续时间,单位为毫秒。used in [VectorizedAnimationSpec]s and [AnimationSpec] + /// + public const int DefaultDurationMillis = 300; + + /// + /// 未指定的时间常量,表示动画时间尚未设置。 + /// + public const long UnspecifiedTime = long.MinValue; + + internal const long MillisToNanos = 1_000_000L; + + internal const long SecendsToNanos = 1_000_000_000L; +} + /// + /// 动画规范接口,描述如何从起点到终点进行动画。 + /// + /// 动画值类型 + public interface IAnimationSpec + where TValue : unmanaged + where TOptions : unmanaged, IMotionOptions + { + + /// + /// 使用给定的双向转换器创建一个向量化动画规范。 + /// 底层动画系统基于 AnimationVector 进行操作。 + /// T 类型的动画值会被转换为 AnimationVector 进行动画处理。VectorizedAnimationSpec 描述了转换后的 AnimationVector 应该如何被动画化。 + /// 例如:动画可以简单地在起始值和结束值之间插值(如 TweenSpec),也可以应用弹簧物理效果产生运动(如 SpringSpec)等。 + /// + /// + /// 用于在 T 类型和 AnimationVector 类型之间转换的转换器 + /// + IVectorizedAnimationSpec vectorize(ITwoWayConverter converter) + where TVector : unmanaged; + } + + /// + /// 动画值与向量的双向转换器 + /// + /// 动画值类型 + /// 向量类型 + public interface ITwoWayConverter + where TValue : unmanaged + where TVector : unmanaged + { + TVector ConvertToVector(TValue value); + TValue ConvertFromVector(TVector vector); + } +} \ No newline at end of file From 9682924ba3ce235b6932e9c77ddbfa545081fe78 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Thu, 18 Sep 2025 21:42:17 +0800 Subject: [PATCH 16/55] =?UTF-8?q?=E7=AC=AC=E4=B8=80=E6=AC=A1=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=20=E6=94=BE=E5=BC=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现在来看,我受compose影响太大了。 游戏开发不需要像移动端的函数式编程那样,搞一堆类出来 也不需要什么VectorXD,C#有Vector和结构体,不需要这些东西 我应该只需要改动最核心的Update,增加速度向量就好了 这次的修改作为废弃分支,从新开始做第二次重构 --- .../Components/Rigidbody2DComponents.cs | 24 +- .../Runtime/Components/RigidbodyComponents.cs | 24 +- .../Runtime/Components/TransformComponents.cs | 36 +- .../Runtime/Components/ValueComponents.cs | 27 +- .../Runtime/PropertyAnimationComponent.cs | 31 +- .../Editor/EditorUpdateMotionScheduler.cs | 9 +- .../LitMotion/Editor/MotionDebuggerWindow.cs | 31 +- .../Adapters/FixedStringMotionAdapters.cs | 71 +- .../Adapters/PrimitiveMotionAdapters.cs | 34 +- .../Runtime/Adapters/PunchMotionAdapters.cs | 22 +- .../Runtime/Adapters/ShakeMotionAdapters.cs | 22 +- .../Runtime/Adapters/UnityMotionAdapter.cs | 63 +- .../Runtime/AnimationSpec/AnimationVector.cs | 67 +- .../DurationBasedAnimationSpec.cs | 58 +- .../FloatingTweenAnimationSpec.cs | 177 ++ .../Runtime/AnimationSpec/IAnimationSpec.cs | 48 +- .../Runtime/AnimationSpec/IMotion.cs | 65 + .../Runtime/AnimationSpec/ITwoWayConverter.cs | 26 + .../AnimationSpec/IntegerAnimationSpec.cs | 180 ++ .../AnimationSpec/LoopBasedAnimationSpec.cs | 41 +- .../AnimationSpec/SpringAnimationSpec.cs | 70 +- .../AnimationSpec/TargetBasedAnimation.cs | 205 ++ .../AnimationSpec/TweenAnimationSpec.cs | 433 ++-- .../AnimationSpec/VectorizedAnimationSpec.cs | 43 +- .../General/LitMotionAudioExtensions.cs | 18 +- .../General/LitMotionCameraExtensions.cs | 48 +- .../General/LitMotionLoggerExtensions.cs | 28 +- .../General/LitMotionMaterialExtensions.cs | 36 +- .../General/LitMotionProgressExtensions.cs | 7 +- .../General/LitMotionRigidbody2DExtensions.cs | 24 +- .../General/LitMotionRigidbodyExtensions.cs | 48 +- .../LitMotionSpriteRendererExtensions.cs | 30 +- .../General/LitMotionTransformExtensions.cs | 222 +- .../Rendering/LitMotionVolumeExtensions.cs | 54 +- .../LitMotionTextMeshProExtensions.cs | 2096 ++++++++--------- .../TextMeshPro/TextMeshProMotionAnimator.cs | 588 ++--- .../UIToolkit/LitMotionUIToolkitExtensions.cs | 1524 ++++++------ .../LitMotionVisualEffectExtensions.cs | 386 +-- .../uGUI/LitMotionRectTransformExtensions.cs | 90 +- .../uGUI/LitMotionUGUIExtensions.cs | 114 +- .../External/R3/LitMotionR3Extensions.cs | 22 +- .../LitMotion/Runtime/IMotionAdapter.cs | 4 +- .../LitMotion/Runtime/IMotionScheduler.cs | 10 +- .../Runtime/Internal/ManagedMotionData.cs | 31 + .../LitMotion/Runtime/Internal/MotionData.cs | 30 +- .../Runtime/Internal/MotionManager.cs | 10 +- .../Runtime/Internal/MotionStatus.cs | 2 +- .../Runtime/Internal/MotionStorage.cs | 191 +- .../Internal/PlayerLoopMotionScheduler.cs | 7 +- .../Runtime/Internal/UpdateRunner.cs | 29 +- .../Runtime/LMotion.Create.FromSettings.cs | 39 +- .../LitMotion/Runtime/LMotion.Create.cs | 172 +- .../LitMotion/Runtime/LMotion.CreateString.cs | 65 +- .../Assets/LitMotion/Runtime/LMotion.Punch.cs | 48 +- .../Assets/LitMotion/Runtime/LMotion.Shake.cs | 48 +- .../Runtime/ManualMotionDispatcher.cs | 29 +- .../Assets/LitMotion/Runtime/MotionBuilder.cs | 82 +- .../Runtime/MotionBuilderExtensions.cs | 87 +- .../LitMotion/Runtime/MotionDebugger.cs | 2 +- .../LitMotion/Runtime/MotionDispatcher.cs | 131 +- .../Assets/LitMotion/Runtime/MotionHandle.cs | 78 +- .../Runtime/MotionHandleExtensions.cs | 2 +- .../Runtime/MotionSequenceBuilder.cs | 4 +- .../LitMotion/Runtime/MotionSequenceSource.cs | 2 +- .../LitMotion/Runtime/MotionUpdateJob.cs | 35 +- .../Runtime/Options/ITweenOptions.cs | 50 + .../Runtime/Options/IntegerOptions.cs | 63 +- .../LitMotion/Runtime/Options/NoOptions.cs | 26 - .../Runtime/Options/NoOptions.cs.meta | 11 - .../LitMotion/Runtime/Options/PunchOptions.cs | 67 +- .../LitMotion/Runtime/Options/ShakeOptions.cs | 72 +- .../Runtime/Options/StringOptions.cs | 76 +- .../LitMotion/Runtime/Options/TweenOption.cs | 46 + .../Tests/Benchmark/BindBenchmark.cs | 2 +- .../Tests/Runtime/ExternalExtensions.cs | 7 +- .../Tests/Runtime/MotionSettingsTest.cs | 2 +- 76 files changed, 5080 insertions(+), 3622 deletions(-) create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/FloatingTweenAnimationSpec.cs create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IMotion.cs create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/ITwoWayConverter.cs create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IntegerAnimationSpec.cs create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/TargetBasedAnimation.cs create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/Options/ITweenOptions.cs delete mode 100644 src/LitMotion/Assets/LitMotion/Runtime/Options/NoOptions.cs delete mode 100644 src/LitMotion/Assets/LitMotion/Runtime/Options/NoOptions.cs.meta create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/Options/TweenOption.cs diff --git a/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/Rigidbody2DComponents.cs b/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/Rigidbody2DComponents.cs index 1e22eb65..4eecc7f4 100644 --- a/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/Rigidbody2DComponents.cs +++ b/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/Rigidbody2DComponents.cs @@ -6,9 +6,9 @@ namespace LitMotion.Animation.Components { - public abstract class Rigidbody2DPositionAnimationBase : PropertyAnimationComponent - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public abstract class Rigidbody2DPositionAnimationBase : PropertyAnimationComponent + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { [SerializeField] bool useMovePosition = true; @@ -31,19 +31,19 @@ protected override Vector2 GetRelativeValue(in Vector2 startValue, in Vector2 re [Serializable] [LitMotionAnimationComponentMenu("Rigidbody2D/Position")] - public sealed class Rigidbody2DPositionAnimation : Rigidbody2DPositionAnimationBase { } + public sealed class Rigidbody2DPositionAnimation : Rigidbody2DPositionAnimationBase> { } [Serializable] [LitMotionAnimationComponentMenu("Rigidbody2D/Position (Punch)")] - public sealed class Rigidbody2DPositionPunchAnimation : Rigidbody2DPositionAnimationBase { } + public sealed class Rigidbody2DPositionPunchAnimation : Rigidbody2DPositionAnimationBase> { } [Serializable] [LitMotionAnimationComponentMenu("Rigidbody2D/Position (Shake)")] - public sealed class Rigidbody2DPositionShakeAnimation : Rigidbody2DPositionAnimationBase { } + public sealed class Rigidbody2DPositionShakeAnimation : Rigidbody2DPositionAnimationBase> { } - public abstract class Rigidbody2DRotationAnimationBase : PropertyAnimationComponent - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public abstract class Rigidbody2DRotationAnimationBase : PropertyAnimationComponent + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { [SerializeField] bool useMoveRotation; @@ -66,15 +66,15 @@ protected override float GetRelativeValue(in float startValue, in float relative [Serializable] [LitMotionAnimationComponentMenu("Rigidbody2D/Rotation")] - public sealed class Rigidbody2DRotationAnimation : Rigidbody2DRotationAnimationBase { } + public sealed class Rigidbody2DRotationAnimation : Rigidbody2DRotationAnimationBase> { } [Serializable] [LitMotionAnimationComponentMenu("Rigidbody2D/Rotation (Punch)")] - public sealed class Rigidbody2DRotationPunchAnimation : Rigidbody2DRotationAnimationBase { } + public sealed class Rigidbody2DRotationPunchAnimation : Rigidbody2DRotationAnimationBase> { } [Serializable] [LitMotionAnimationComponentMenu("Rigidbody2D/Rotation (Shake)")] - public sealed class Rigidbody2DRotationShakeAnimation : Rigidbody2DRotationAnimationBase { } + public sealed class Rigidbody2DRotationShakeAnimation : Rigidbody2DRotationAnimationBase> { } } #endif \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/RigidbodyComponents.cs b/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/RigidbodyComponents.cs index fb6c12be..0a86e6b2 100644 --- a/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/RigidbodyComponents.cs +++ b/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/RigidbodyComponents.cs @@ -6,9 +6,9 @@ namespace LitMotion.Animation.Components { - public abstract class RigidbodyPositionAnimationBase : PropertyAnimationComponent - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public abstract class RigidbodyPositionAnimationBase : PropertyAnimationComponent + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { [SerializeField] bool useMovePosition = true; @@ -31,19 +31,19 @@ protected override Vector3 GetRelativeValue(in Vector3 startValue, in Vector3 re [Serializable] [LitMotionAnimationComponentMenu("Rigidbody/Position")] - public sealed class RigidbodyPositionAnimation : RigidbodyPositionAnimationBase { } + public sealed class RigidbodyPositionAnimation : RigidbodyPositionAnimationBase> { } [Serializable] [LitMotionAnimationComponentMenu("Rigidbody/Position (Punch)")] - public sealed class RigidbodyPositionPunchAnimation : RigidbodyPositionAnimationBase { } + public sealed class RigidbodyPositionPunchAnimation : RigidbodyPositionAnimationBase> { } [Serializable] [LitMotionAnimationComponentMenu("Rigidbody/Position (Shake)")] - public sealed class RigidbodyPositionShakeAnimation : RigidbodyPositionAnimationBase { } + public sealed class RigidbodyPositionShakeAnimation : RigidbodyPositionAnimationBase> { } - public abstract class RigidbodyRotationAnimationBase : PropertyAnimationComponent - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public abstract class RigidbodyRotationAnimationBase : PropertyAnimationComponent + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { [SerializeField] bool useMoveRotation; @@ -66,15 +66,15 @@ protected override Vector3 GetRelativeValue(in Vector3 startValue, in Vector3 re [Serializable] [LitMotionAnimationComponentMenu("Rigidbody/Rotation")] - public sealed class RigidbodyRotationAnimation : RigidbodyRotationAnimationBase { } + public sealed class RigidbodyRotationAnimation : RigidbodyRotationAnimationBase> { } [Serializable] [LitMotionAnimationComponentMenu("Rigidbody/Rotation (Punch)")] - public sealed class RigidbodyRotationPunchAnimation : RigidbodyRotationAnimationBase { } + public sealed class RigidbodyRotationPunchAnimation : RigidbodyRotationAnimationBase> { } [Serializable] [LitMotionAnimationComponentMenu("Rigidbody/Rotation (Shake)")] - public sealed class RigidbodyRotationShakeAnimation : RigidbodyRotationAnimationBase { } + public sealed class RigidbodyRotationShakeAnimation : RigidbodyRotationAnimationBase> { } } #endif \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/TransformComponents.cs b/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/TransformComponents.cs index 4e4c64fa..ee5b5ee9 100644 --- a/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/TransformComponents.cs +++ b/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/TransformComponents.cs @@ -5,9 +5,9 @@ namespace LitMotion.Animation.Components { - public abstract class TransformPositionAnimationBase : PropertyAnimationComponent - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public abstract class TransformPositionAnimationBase : PropertyAnimationComponent + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { [SerializeField] bool useWorldSpace; @@ -30,19 +30,19 @@ protected override Vector3 GetRelativeValue(in Vector3 startValue, in Vector3 re [Serializable] [LitMotionAnimationComponentMenu("Transform/Position")] - public sealed class TransformPositionAnimation : TransformPositionAnimationBase { } + public sealed class TransformPositionAnimation : TransformPositionAnimationBase> { } [Serializable] [LitMotionAnimationComponentMenu("Transform/Position (Punch)")] - public sealed class TransformPositionPunchAnimation : TransformPositionAnimationBase { } + public sealed class TransformPositionPunchAnimation : TransformPositionAnimationBase> { } [Serializable] [LitMotionAnimationComponentMenu("Transform/Position (Shake)")] - public sealed class TransformPositionShakeAnimation : TransformPositionAnimationBase { } + public sealed class TransformPositionShakeAnimation : TransformPositionAnimationBase> { } - public abstract class TransformRotationAnimationBase : PropertyAnimationComponent - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public abstract class TransformRotationAnimationBase : PropertyAnimationComponent + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { [SerializeField] bool useWorldSpace; @@ -65,19 +65,19 @@ protected override Vector3 GetRelativeValue(in Vector3 startValue, in Vector3 re [Serializable] [LitMotionAnimationComponentMenu("Transform/Rotation")] - public sealed class TransformRotationAnimation : TransformRotationAnimationBase { } + public sealed class TransformRotationAnimation : TransformRotationAnimationBase> { } [Serializable] [LitMotionAnimationComponentMenu("Transform/Rotation (Punch)")] - public sealed class TransformRotationPunchAnimation : TransformRotationAnimationBase { } + public sealed class TransformRotationPunchAnimation : TransformRotationAnimationBase> { } [Serializable] [LitMotionAnimationComponentMenu("Transform/Rotation (Shake)")] - public sealed class TransformRotationShakeAnimation : TransformRotationAnimationBase { } + public sealed class TransformRotationShakeAnimation : TransformRotationAnimationBase> { } - public abstract class TransformScaleAnimationBase : PropertyAnimationComponent - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public abstract class TransformScaleAnimationBase : PropertyAnimationComponent + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { protected override Vector3 GetValue(Transform target) { @@ -97,13 +97,13 @@ protected override Vector3 GetRelativeValue(in Vector3 startValue, in Vector3 re [Serializable] [LitMotionAnimationComponentMenu("Transform/Scale")] - public sealed class TransformScaleAnimation : TransformScaleAnimationBase { } + public sealed class TransformScaleAnimation : TransformScaleAnimationBase> { } [Serializable] [LitMotionAnimationComponentMenu("Transform/Scale (Punch)")] - public sealed class TransformScalePunchAnimation : TransformScaleAnimationBase { } + public sealed class TransformScalePunchAnimation : TransformScaleAnimationBase> { } [Serializable] [LitMotionAnimationComponentMenu("Transform/Scale (Shake)")] - public sealed class TransformScaleShakeAnimation : TransformScaleAnimationBase { } + public sealed class TransformScaleShakeAnimation : TransformScaleAnimationBase> { } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/ValueComponents.cs b/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/ValueComponents.cs index b90789dd..f3e0ba7d 100644 --- a/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/ValueComponents.cs +++ b/src/LitMotion/Assets/LitMotion.Animation/Runtime/Components/ValueComponents.cs @@ -6,17 +6,18 @@ namespace LitMotion.Animation.Components { - public abstract class ValueAnimationComponent : LitMotionAnimationComponent + public abstract class ValueAnimationComponent : LitMotionAnimationComponent where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { [SerializeField] SerializableMotionSettings settings; [SerializeField] UnityEvent onValueChanged; public override MotionHandle Play() { - return LMotion.Create(settings) + return LMotion.Create(settings) .Bind(this, (x, state) => { state.onValueChanged.Invoke(x); @@ -28,35 +29,35 @@ public override void OnStop() { } [Serializable] [LitMotionAnimationComponentMenu("Value/Float")] - public sealed class FloatValueAnimation : ValueAnimationComponent { } + public sealed class FloatValueAnimation : ValueAnimationComponent> { } [Serializable] [LitMotionAnimationComponentMenu("Value/Double")] - public sealed class DoubleValueAnimation : ValueAnimationComponent { } + public sealed class DoubleValueAnimation : ValueAnimationComponent> { } [Serializable] [LitMotionAnimationComponentMenu("Value/Int")] - public sealed class IntValueAnimation : ValueAnimationComponent { } + public sealed class IntValueAnimation : ValueAnimationComponent> { } [Serializable] [LitMotionAnimationComponentMenu("Value/Long")] - public sealed class LongValueAnimation : ValueAnimationComponent { } + public sealed class LongValueAnimation : ValueAnimationComponent> { } [Serializable] [LitMotionAnimationComponentMenu("Value/Vector2")] - public sealed class Vector2ValueAnimation : ValueAnimationComponent { } + public sealed class Vector2ValueAnimation : ValueAnimationComponent> { } [Serializable] [LitMotionAnimationComponentMenu("Value/Vector3")] - public sealed class Vector3ValueAnimation : ValueAnimationComponent { } + public sealed class Vector3ValueAnimation : ValueAnimationComponent> { } [Serializable] [LitMotionAnimationComponentMenu("Value/Vector4")] - public sealed class Vector4ValueAnimation : ValueAnimationComponent { } + public sealed class Vector4ValueAnimation : ValueAnimationComponent> { } [Serializable] [LitMotionAnimationComponentMenu("Value/Color")] - public sealed class ColorValueAnimation : ValueAnimationComponent { } + public sealed class ColorValueAnimation : ValueAnimationComponent> { } [Serializable] [LitMotionAnimationComponentMenu("Value/String")] @@ -67,7 +68,7 @@ public sealed class StringValueAnimation : LitMotionAnimationComponent public override MotionHandle Play() { - return LMotion.Create(settings) + return LMotion.Create>(settings) .Bind(this, static (x, state) => { // TODO: avoid allocation diff --git a/src/LitMotion/Assets/LitMotion.Animation/Runtime/PropertyAnimationComponent.cs b/src/LitMotion/Assets/LitMotion.Animation/Runtime/PropertyAnimationComponent.cs index 8ef4cb83..68fef3e8 100644 --- a/src/LitMotion/Assets/LitMotion.Animation/Runtime/PropertyAnimationComponent.cs +++ b/src/LitMotion/Assets/LitMotion.Animation/Runtime/PropertyAnimationComponent.cs @@ -5,11 +5,12 @@ namespace LitMotion.Animation { - public abstract class PropertyAnimationComponent : LitMotionAnimationComponent + public abstract class PropertyAnimationComponent : LitMotionAnimationComponent where TObject : UnityEngine.Object where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { [SerializeField] TObject target; [SerializeField] SerializableMotionSettings settings; @@ -31,7 +32,7 @@ public override MotionHandle Play() if (relative) { - handle = LMotion.Create(settings) + handle = LMotion.Create(settings) .Bind(this, (x, state) => { state.SetValue(target, state.GetRelativeValue(state.startValue, x)); @@ -39,7 +40,7 @@ public override MotionHandle Play() } else { - handle = LMotion.Create(settings) + handle = LMotion.Create(settings) .Bind(this, (x, state) => { state.SetValue(target, x); @@ -56,7 +57,7 @@ public override MotionHandle Play() // I wish we could use Generic Math in Unity... :( - public abstract class FloatPropertyAnimationComponent : PropertyAnimationComponent + public abstract class FloatPropertyAnimationComponent : PropertyAnimationComponent> where TObject : UnityEngine.Object { protected sealed override float GetRelativeValue(in float startValue, in float relativeValue) @@ -65,7 +66,7 @@ protected sealed override float GetRelativeValue(in float startValue, in float r } } - public abstract class DoublePropertyAnimationComponent : PropertyAnimationComponent + public abstract class DoublePropertyAnimationComponent : PropertyAnimationComponent> where TObject : UnityEngine.Object { protected sealed override double GetRelativeValue(in double startValue, in double relativeValue) @@ -74,7 +75,7 @@ protected sealed override double GetRelativeValue(in double startValue, in doubl } } - public abstract class IntPropertyAnimationComponent : PropertyAnimationComponent + public abstract class IntPropertyAnimationComponent : PropertyAnimationComponent> where TObject : UnityEngine.Object { protected sealed override int GetRelativeValue(in int startValue, in int relativeValue) @@ -83,7 +84,7 @@ protected sealed override int GetRelativeValue(in int startValue, in int relativ } } - public abstract class LongPropertyAnimationComponent : PropertyAnimationComponent + public abstract class LongPropertyAnimationComponent : PropertyAnimationComponent> where TObject : UnityEngine.Object { protected sealed override long GetRelativeValue(in long startValue, in long relativeValue) @@ -92,7 +93,7 @@ protected sealed override long GetRelativeValue(in long startValue, in long rela } } - public abstract class Vector2PropertyAnimationComponent : PropertyAnimationComponent + public abstract class Vector2PropertyAnimationComponent : PropertyAnimationComponent> where TObject : UnityEngine.Object { protected sealed override Vector2 GetRelativeValue(in Vector2 startValue, in Vector2 relativeValue) @@ -101,7 +102,7 @@ protected sealed override Vector2 GetRelativeValue(in Vector2 startValue, in Vec } } - public abstract class Vector3PropertyAnimationComponent : PropertyAnimationComponent + public abstract class Vector3PropertyAnimationComponent : PropertyAnimationComponent> where TObject : UnityEngine.Object { protected sealed override Vector3 GetRelativeValue(in Vector3 startValue, in Vector3 relativeValue) @@ -110,7 +111,7 @@ protected sealed override Vector3 GetRelativeValue(in Vector3 startValue, in Vec } } - public abstract class Vector4PropertyAnimationComponent : PropertyAnimationComponent + public abstract class Vector4PropertyAnimationComponent : PropertyAnimationComponent> where TObject : UnityEngine.Object { protected sealed override Vector4 GetRelativeValue(in Vector4 startValue, in Vector4 relativeValue) @@ -119,7 +120,7 @@ protected sealed override Vector4 GetRelativeValue(in Vector4 startValue, in Vec } } - public abstract class ColorPropertyAnimationComponent : PropertyAnimationComponent + public abstract class ColorPropertyAnimationComponent : PropertyAnimationComponent> where TObject : UnityEngine.Object { protected sealed override Color GetRelativeValue(in Color startValue, in Color relativeValue) @@ -128,7 +129,7 @@ protected sealed override Color GetRelativeValue(in Color startValue, in Color r } } - public abstract class RectPropertyAnimationComponent : PropertyAnimationComponent + public abstract class RectPropertyAnimationComponent : PropertyAnimationComponent> where TObject : UnityEngine.Object { protected sealed override Rect GetRelativeValue(in Rect startValue, in Rect relativeValue) @@ -137,7 +138,7 @@ protected sealed override Rect GetRelativeValue(in Rect startValue, in Rect rela } } - public abstract class FixedString512BytesPropertyAnimationComponent : PropertyAnimationComponent + public abstract class FixedString512BytesPropertyAnimationComponent : PropertyAnimationComponent> where TObject : UnityEngine.Object { protected sealed override FixedString512Bytes GetRelativeValue(in FixedString512Bytes startValue, in FixedString512Bytes relativeValue) diff --git a/src/LitMotion/Assets/LitMotion/Editor/EditorUpdateMotionScheduler.cs b/src/LitMotion/Assets/LitMotion/Editor/EditorUpdateMotionScheduler.cs index bb51b299..379194c9 100644 --- a/src/LitMotion/Assets/LitMotion/Editor/EditorUpdateMotionScheduler.cs +++ b/src/LitMotion/Assets/LitMotion/Editor/EditorUpdateMotionScheduler.cs @@ -6,12 +6,13 @@ internal sealed class EditorUpdateMotionScheduler : IMotionScheduler { public double Time => EditorApplication.timeSinceStartup; - public MotionHandle Schedule(ref MotionBuilder builder) + public MotionHandle Schedule(ref MotionBuilder builder) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { - return EditorMotionDispatcher.Schedule(ref builder); + return EditorMotionDispatcher.Schedule(ref builder); } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Editor/MotionDebuggerWindow.cs b/src/LitMotion/Assets/LitMotion/Editor/MotionDebuggerWindow.cs index 743a18f1..4e81f7e3 100644 --- a/src/LitMotion/Assets/LitMotion/Editor/MotionDebuggerWindow.cs +++ b/src/LitMotion/Assets/LitMotion/Editor/MotionDebuggerWindow.cs @@ -146,13 +146,10 @@ void RenderDetailsPanel() var selected = treeView.state.selectedIDs; if (selected.Count > 0 && treeView.CurrentBindingItems.FirstOrDefault(x => x.id == selected[0]) is MotionDebuggerViewItem item) { - ref var dataRef = ref MotionManager.GetDataRef(item.Handle, false); + ref var state = ref MotionManager.GetStateRef(item.Handle, false); ref var managedDataRef = ref MotionManager.GetManagedDataRef(item.Handle, false); var debugInfo = MotionManager.GetDebugInfo(item.Handle); - ref var state = ref dataRef.State; - ref var parameters = ref dataRef.Parameters; - using (new EditorGUILayout.VerticalScope(GUI.skin.box)) { EditorGUILayout.LabelField("Motion Handle", EditorStyles.boldLabel); @@ -175,19 +172,19 @@ void RenderDetailsPanel() GenericField("Start Value", debugInfo.StartValue); GenericField("End Value", debugInfo.EndValue); - EditorGUILayout.Space(4); - GenericField("Duration", parameters.Duration); - GenericField("Delay", parameters.Delay); - GenericField("Delay Type", parameters.DelayType); - GenericField("Loops", parameters.Loops); - GenericField("Loop Type", parameters.LoopType); - - EditorGUILayout.Space(4); - GenericField("Ease", parameters.Ease); - if (parameters.Ease is Ease.CustomAnimationCurve) - { - GenericField("Custom Ease Curve", parameters.AnimationCurve); - } + // EditorGUILayout.Space(4); + // GenericField("Duration", parameters.Duration); + // GenericField("Delay", parameters.Delay); + // GenericField("Delay Type", parameters.DelayType); + // GenericField("Loops", parameters.Loops); + // GenericField("Loop Type", parameters.LoopType); + + // EditorGUILayout.Space(4); + // GenericField("Ease", parameters.Ease); + // if (parameters.Ease is Ease.CustomAnimationCurve) + // { + // GenericField("Custom Ease Curve", parameters.AnimationCurve); + // } EditorGUILayout.Space(4); GenericField("Cancel On Error", managedDataRef.CancelOnError); diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/FixedStringMotionAdapters.cs b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/FixedStringMotionAdapters.cs index 27623b1b..54aa5892 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/FixedStringMotionAdapters.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/FixedStringMotionAdapters.cs @@ -3,16 +3,27 @@ using LitMotion; using LitMotion.Adapters; -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] +// TODO: 需要实现支持StringOptions的AnimationSpec后取消注释 +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] namespace LitMotion.Adapters { - public readonly struct FixedString32BytesMotionAdapter : IMotionAdapter + public readonly struct FixedString32BytesMotionAdapter : IMotionAdapter { + public FixedString32Bytes ConvertToVector(FixedString32Bytes value) + { + return value; + } + + public FixedString32Bytes ConvertFromVector(FixedString32Bytes value) + { + return value; + } + public FixedString32Bytes Evaluate(ref FixedString32Bytes startValue, ref FixedString32Bytes endValue, ref StringOptions options, in MotionEvaluationContext context) { var start = startValue; @@ -24,8 +35,18 @@ public FixedString32Bytes Evaluate(ref FixedString32Bytes startValue, ref FixedS } } - public readonly struct FixedString64BytesMotionAdapter : IMotionAdapter + public readonly struct FixedString64BytesMotionAdapter : IMotionAdapter { + public FixedString64Bytes ConvertToVector(FixedString64Bytes value) + { + return value; + } + + public FixedString64Bytes ConvertFromVector(FixedString64Bytes value) + { + return value; + } + public FixedString64Bytes Evaluate(ref FixedString64Bytes startValue, ref FixedString64Bytes endValue, ref StringOptions options, in MotionEvaluationContext context) { var start = startValue; @@ -37,8 +58,18 @@ public FixedString64Bytes Evaluate(ref FixedString64Bytes startValue, ref FixedS } } - public readonly struct FixedString128BytesMotionAdapter : IMotionAdapter + public readonly struct FixedString128BytesMotionAdapter : IMotionAdapter { + public FixedString128Bytes ConvertToVector(FixedString128Bytes value) + { + return value; + } + + public FixedString128Bytes ConvertFromVector(FixedString128Bytes value) + { + return value; + } + public FixedString128Bytes Evaluate(ref FixedString128Bytes startValue, ref FixedString128Bytes endValue, ref StringOptions options, in MotionEvaluationContext context) { var start = startValue; @@ -50,8 +81,18 @@ public FixedString128Bytes Evaluate(ref FixedString128Bytes startValue, ref Fixe } } - public readonly struct FixedString512BytesMotionAdapter : IMotionAdapter + public readonly struct FixedString512BytesMotionAdapter : IMotionAdapter { + public FixedString512Bytes ConvertToVector(FixedString512Bytes value) + { + return value; + } + + public FixedString512Bytes ConvertFromVector(FixedString512Bytes value) + { + return value; + } + public FixedString512Bytes Evaluate(ref FixedString512Bytes startValue, ref FixedString512Bytes endValue, ref StringOptions options, in MotionEvaluationContext context) { var start = startValue; @@ -63,8 +104,18 @@ public FixedString512Bytes Evaluate(ref FixedString512Bytes startValue, ref Fixe } } - public readonly struct FixedString4096BytesMotionAdapter : IMotionAdapter + public readonly struct FixedString4096BytesMotionAdapter : IMotionAdapter { + public FixedString4096Bytes ConvertToVector(FixedString4096Bytes value) + { + return value; + } + + public FixedString4096Bytes ConvertFromVector(FixedString4096Bytes value) + { + return value; + } + public FixedString4096Bytes Evaluate(ref FixedString4096Bytes startValue, ref FixedString4096Bytes endValue, ref StringOptions options, in MotionEvaluationContext context) { var start = startValue; diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/PrimitiveMotionAdapters.cs b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/PrimitiveMotionAdapters.cs index 43576f4c..9f0d6ec3 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/PrimitiveMotionAdapters.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/PrimitiveMotionAdapters.cs @@ -3,31 +3,41 @@ using LitMotion; using LitMotion.Adapters; -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] +// TODO: 需要实现支持IntegerOptions的AnimationSpec后取消注释 +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] namespace LitMotion.Adapters { - public readonly struct FloatMotionAdapter : IMotionAdapter + public readonly struct FloatMotionAdapter : IMotionAdapter { - public float Evaluate(ref float startValue, ref float endValue, ref NoOptions options, in MotionEvaluationContext context) + public float ConvertToVector(float value) => value; + public float ConvertFromVector(float value) => value; + + public float Evaluate(ref float startValue, ref float endValue, ref TweenOption options, in MotionEvaluationContext context) { return math.lerp(startValue, endValue, context.Progress); } } - public readonly struct DoubleMotionAdapter : IMotionAdapter + public readonly struct DoubleMotionAdapter : IMotionAdapter { - public double Evaluate(ref double startValue, ref double endValue, ref NoOptions options, in MotionEvaluationContext context) + public double ConvertToVector(double value) => value; + public double ConvertFromVector(double value) => value; + + public double Evaluate(ref double startValue, ref double endValue, ref TweenOption options, in MotionEvaluationContext context) { return math.lerp(startValue, endValue, context.Progress); } } - public readonly struct IntMotionAdapter : IMotionAdapter + public readonly struct IntMotionAdapter : IMotionAdapter { + public int ConvertToVector(int value) => value; + public int ConvertFromVector(int value) => value; + public int Evaluate(ref int startValue, ref int endValue, ref IntegerOptions options, in MotionEvaluationContext context) { var value = math.lerp(startValue, endValue, context.Progress); @@ -42,8 +52,12 @@ public int Evaluate(ref int startValue, ref int endValue, ref IntegerOptions opt }; } } - public readonly struct LongMotionAdapter : IMotionAdapter + + public readonly struct LongMotionAdapter : IMotionAdapter { + public long ConvertToVector(long value) => value; + public long ConvertFromVector(long value) => value; + public long Evaluate(ref long startValue, ref long endValue, ref IntegerOptions options, in MotionEvaluationContext context) { var value = math.lerp((double)startValue, endValue, context.Progress); diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/PunchMotionAdapters.cs b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/PunchMotionAdapters.cs index dab10756..375ef82a 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/PunchMotionAdapters.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/PunchMotionAdapters.cs @@ -3,16 +3,20 @@ using LitMotion; using LitMotion.Adapters; -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] +// TODO: 需要实现支持PunchOptions的AnimationSpec后取消注释 +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] namespace LitMotion.Adapters { // Note: Punch motion uses startValue as offset and endValue as vibration strength. - public readonly struct FloatPunchMotionAdapter : IMotionAdapter + public readonly struct FloatPunchMotionAdapter : IMotionAdapter { + public float ConvertToVector(float value) => value; + public float ConvertFromVector(float value) => value; + public float Evaluate(ref float startValue, ref float endValue, ref PunchOptions options, in MotionEvaluationContext context) { VibrationHelper.EvaluateStrength(endValue, options.Frequency, options.DampingRatio, context.Progress, out var result); @@ -20,8 +24,11 @@ public float Evaluate(ref float startValue, ref float endValue, ref PunchOptions } } - public readonly struct Vector2PunchMotionAdapter : IMotionAdapter + public readonly struct Vector2PunchMotionAdapter : IMotionAdapter { + public Vector2 ConvertToVector(Vector2 value) => value; + public Vector2 ConvertFromVector(Vector2 value) => value; + public Vector2 Evaluate(ref Vector2 startValue, ref Vector2 endValue, ref PunchOptions options, in MotionEvaluationContext context) { VibrationHelper.EvaluateStrength(endValue, options.Frequency, options.DampingRatio, context.Progress, out var result); @@ -29,8 +36,11 @@ public Vector2 Evaluate(ref Vector2 startValue, ref Vector2 endValue, ref PunchO } } - public readonly struct Vector3PunchMotionAdapter : IMotionAdapter + public readonly struct Vector3PunchMotionAdapter : IMotionAdapter { + public Vector3 ConvertToVector(Vector3 value) => value; + public Vector3 ConvertFromVector(Vector3 value) => value; + public Vector3 Evaluate(ref Vector3 startValue, ref Vector3 endValue, ref PunchOptions options, in MotionEvaluationContext context) { VibrationHelper.EvaluateStrength(endValue, options.Frequency, options.DampingRatio, context.Progress, out var result); diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/ShakeMotionAdapters.cs b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/ShakeMotionAdapters.cs index 3c878f9c..e3d2de92 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/ShakeMotionAdapters.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/ShakeMotionAdapters.cs @@ -4,16 +4,20 @@ using LitMotion.Adapters; using Unity.Mathematics; -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] +// TODO: 需要实现支持ShakeOptions的AnimationSpec后取消注释 +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] namespace LitMotion.Adapters { // Note: Shake motion uses startValue as offset and endValue as vibration strength. - public readonly struct FloatShakeMotionAdapter : IMotionAdapter + public readonly struct FloatShakeMotionAdapter : IMotionAdapter { + public float ConvertToVector(float value) => value; + public float ConvertFromVector(float value) => value; + public float Evaluate(ref float startValue, ref float endValue, ref ShakeOptions options, in MotionEvaluationContext context) { VibrationHelper.EvaluateStrength(endValue, options.Frequency, options.DampingRatio, context.Progress, out var s); @@ -22,8 +26,11 @@ public float Evaluate(ref float startValue, ref float endValue, ref ShakeOptions } } - public readonly struct Vector2ShakeMotionAdapter : IMotionAdapter + public readonly struct Vector2ShakeMotionAdapter : IMotionAdapter { + public Vector2 ConvertToVector(Vector2 value) => value; + public Vector2 ConvertFromVector(Vector2 value) => value; + public Vector2 Evaluate(ref Vector2 startValue, ref Vector2 endValue, ref ShakeOptions options, in MotionEvaluationContext context) { VibrationHelper.EvaluateStrength(endValue, options.Frequency, options.DampingRatio, context.Progress, out var s); @@ -32,8 +39,11 @@ public Vector2 Evaluate(ref Vector2 startValue, ref Vector2 endValue, ref ShakeO } } - public readonly struct Vector3ShakeMotionAdapter : IMotionAdapter + public readonly struct Vector3ShakeMotionAdapter : IMotionAdapter { + public Vector3 ConvertToVector(Vector3 value) => value; + public Vector3 ConvertFromVector(Vector3 value) => value; + public Vector3 Evaluate(ref Vector3 startValue, ref Vector3 endValue, ref ShakeOptions options, in MotionEvaluationContext context) { VibrationHelper.EvaluateStrength(endValue, options.Frequency, options.DampingRatio, context.Progress, out var s); diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/UnityMotionAdapter.cs b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/UnityMotionAdapter.cs index 63a110e4..ba157842 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/UnityMotionAdapter.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/UnityMotionAdapter.cs @@ -4,58 +4,85 @@ using LitMotion; using LitMotion.Adapters; -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] -[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] +// [assembly: RegisterGenericJobType(typeof(MotionUpdateJob>))] namespace LitMotion.Adapters { - public readonly struct Vector2MotionAdapter : IMotionAdapter + public readonly struct Vector2MotionAdapter : IMotionAdapter { - public Vector2 Evaluate(ref Vector2 startValue, ref Vector2 endValue, ref NoOptions options, in MotionEvaluationContext context) + public Vector2 ConvertToVector(Vector2 value) => value; + public Vector2 ConvertFromVector(Vector2 value) => value; + + public Vector2 Evaluate(ref Vector2 startValue, ref Vector2 endValue, ref TweenOption options, in MotionEvaluationContext context) { return Vector2.LerpUnclamped(startValue, endValue, context.Progress); } } - public readonly struct Vector3MotionAdapter : IMotionAdapter + public readonly struct Vector3MotionAdapter : IMotionAdapter { - public Vector3 Evaluate(ref Vector3 startValue, ref Vector3 endValue, ref NoOptions options, in MotionEvaluationContext context) + public Vector3 ConvertToVector(Vector3 value) => value; + public Vector3 ConvertFromVector(Vector3 value) => value; + + public Vector3 Evaluate(ref Vector3 startValue, ref Vector3 endValue, ref TweenOption options, in MotionEvaluationContext context) { return Vector3.LerpUnclamped(startValue, endValue, context.Progress); } } - public readonly struct Vector4MotionAdapter : IMotionAdapter + public readonly struct Vector4MotionAdapter : IMotionAdapter { - public Vector4 Evaluate(ref Vector4 startValue, ref Vector4 endValue, ref NoOptions options, in MotionEvaluationContext context) + public Vector4 ConvertToVector(Vector4 value) => value; + public Vector4 ConvertFromVector(Vector4 value) => value; + + public Vector4 Evaluate(ref Vector4 startValue, ref Vector4 endValue, ref TweenOption options, in MotionEvaluationContext context) { return Vector4.LerpUnclamped(startValue, endValue, context.Progress); } } - public readonly struct QuaternionMotionAdapter : IMotionAdapter + public readonly struct QuaternionMotionAdapter : IMotionAdapter { - public Quaternion Evaluate(ref Quaternion startValue, ref Quaternion endValue, ref NoOptions options, in MotionEvaluationContext context) + public Quaternion ConvertToVector(Quaternion value) => value; + public Quaternion ConvertFromVector(Quaternion value) => value; + + public Quaternion Evaluate(ref Quaternion startValue, ref Quaternion endValue, ref TweenOption options, in MotionEvaluationContext context) { return Quaternion.LerpUnclamped(startValue, endValue, context.Progress); } } - public readonly struct ColorMotionAdapter : IMotionAdapter + public readonly struct ColorMotionAdapter : IMotionAdapter { - public Color Evaluate(ref Color startValue, ref Color endValue, ref NoOptions options, in MotionEvaluationContext context) + public Color ConvertToVector(Color value) => value; + public Color ConvertFromVector(Color value) => value; + + public Color Evaluate(ref Color startValue, ref Color endValue, ref TweenOption options, in MotionEvaluationContext context) { return Color.LerpUnclamped(startValue, endValue, context.Progress); } } - public readonly struct RectMotionAdapter : IMotionAdapter + + + public readonly struct RectMotionAdapter : IMotionAdapter { - public Rect Evaluate(ref Rect startValue, ref Rect endValue, ref NoOptions options, in MotionEvaluationContext context) + public Vector4 ConvertToVector(Rect value) + { + return new Vector4(value.x, value.y, value.width, value.height); + } + + public Rect ConvertFromVector(Vector4 value) + { + return new Rect(value.x, value.y, value.z, value.w); + } + + public Rect Evaluate(ref Rect startValue, ref Rect endValue, ref TweenOption options, in MotionEvaluationContext context) { var x = math.lerp(startValue.x, endValue.x, context.Progress); var y = math.lerp(startValue.y, endValue.y, context.Progress); diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/AnimationVector.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/AnimationVector.cs index 730ba772..85c79bd4 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/AnimationVector.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/AnimationVector.cs @@ -4,7 +4,7 @@ namespace LitMotion { /// - /// 动画向量接口,所有向量化动画值的基类接口。 + /// Animation vector interface, base interface for all vectorized animation values. /// public interface AnimationVector { @@ -19,12 +19,12 @@ public bool isInitialized } /// - /// 一维动画向量(用float),适用于单通道动画(如透明度、单轴移动等)。 + /// 1D animation vector (float), suitable for single-channel animation (e.g., opacity, single-axis movement). /// public struct AnimationVector1D : AnimationVector { /// - /// 动画值 + /// Animation value /// public float Value { @@ -58,21 +58,21 @@ public AnimationVector1D(float value = 0f) } /// - /// 创建全零新实例 + /// Create a new instance with zero value /// public static AnimationVector1D NewInstance() => new AnimationVector1D(0f); /// - /// 深拷贝 + /// Deep copy /// public static AnimationVector1D Copy(AnimationVector1D v) => new AnimationVector1D(v.Value); /// - /// 从source拷贝到target + /// Copy from source to target /// public static void CopyFrom(ref AnimationVector1D target, in AnimationVector1D source) => target.Value = source.Value; } /// - /// 二维动画向量(用Vector2),适用于2D平面动画(如位置、缩放等)。 + /// 2D animation vector (Vector2), suitable for 2D plane animation (e.g., position, scale). /// public struct AnimationVector2D : AnimationVector { @@ -89,7 +89,7 @@ bool AnimationVector.isInitialized } } /// - /// 动画值(x, y) + /// Animation value (x, y) /// [SerializeField] private Vector2 _value; @@ -112,21 +112,21 @@ public float this[int index] public void Reset() { _value.x = 0f; _value.y = 0f; } /// - /// 创建全零新实例 + /// Create a new instance with zero value /// public static AnimationVector2D NewInstance() => new AnimationVector2D(0f, 0f); /// - /// 深拷贝 + /// Deep copy /// public static AnimationVector2D Copy(AnimationVector2D v) => new AnimationVector2D(v._value); /// - /// 从source拷贝到target + /// Copy from source to target /// public static void CopyFrom(ref AnimationVector2D target, in AnimationVector2D source) { target._value.x = source._value.x; target._value.y = source._value.y; } } /// - /// 三维动画向量(用Vector3),适用于3D空间动画(如位置、缩放、旋转等)。 + /// 3D animation vector (Vector3), suitable for 3D space animation (e.g., position, scale, rotation). /// public struct AnimationVector3D : AnimationVector { @@ -143,7 +143,7 @@ bool AnimationVector.isInitialized } } /// - /// 动画值(x, y, z) + /// Animation value (x, y, z) /// [SerializeField] private Vector3 _value; @@ -166,21 +166,21 @@ public float this[int index] public void Reset() { _value.x = 0f; _value.y = 0f; _value.z = 0f; } /// - /// 创建全零新实例 + /// Create a new instance with zero value /// public static AnimationVector3D NewInstance() => new AnimationVector3D(0f, 0f, 0f); /// - /// 深拷贝 + /// Deep copy /// public static AnimationVector3D Copy(AnimationVector3D v) => new AnimationVector3D(v._value); /// - /// 从source拷贝到target + /// Copy from source to target /// public static void CopyFrom(ref AnimationVector3D target, in AnimationVector3D source) { target._value.x = source._value.x; target._value.y = source._value.y; target._value.z = source._value.z; } } /// - /// 四维动画向量(用Vector4),适用于颜色、四元数等四通道动画。 + /// 4D animation vector (Vector4), suitable for color, quaternion, and other four-channel animations. /// public struct AnimationVector4D : AnimationVector { @@ -197,11 +197,10 @@ bool AnimationVector.isInitialized } } /// - /// 动画值(x, y, z, w) + /// Animation value (x, y, z, w) /// [SerializeField] private Vector4 _value; - public AnimationVector4D(float x = 0f, float y = 0f, float z = 0f, float w = 0f) { _value = new Vector4(x, y, z, w); @@ -214,42 +213,22 @@ public AnimationVector4D(Vector4 v) } public float this[int index] { - get - { - switch (index) - { - case 0: return _value.x; - case 1: return _value.y; - case 2: return _value.z; - case 3: return _value.w; - default: throw new IndexOutOfRangeException(); - } - } - set - { - switch (index) - { - case 0: _value.x = value; break; - case 1: _value.y = value; break; - case 2: _value.z = value; break; - case 3: _value.w = value; break; - default: throw new IndexOutOfRangeException(); - } - } + get => index == 0 ? _value.x : index == 1 ? _value.y : index == 2 ? _value.z : index == 3 ? _value.w : throw new IndexOutOfRangeException(); + set { if (index == 0) _value.x = value; else if (index == 1) _value.y = value; else if (index == 2) _value.z = value; else if (index == 3) _value.w = value; else throw new IndexOutOfRangeException(); } } public AnimationVector NewVector() => new AnimationVector4D(0f, 0f, 0f, 0f); public void Reset() { _value.x = 0f; _value.y = 0f; _value.z = 0f; _value.w = 0f; } /// - /// 创建全零新实例 + /// Create a new instance with zero value /// public static AnimationVector4D NewInstance() => new AnimationVector4D(0f, 0f, 0f, 0f); /// - /// 深拷贝 + /// Deep copy /// public static AnimationVector4D Copy(AnimationVector4D v) => new AnimationVector4D(v._value); /// - /// 从source拷贝到target + /// Copy from source to target /// public static void CopyFrom(ref AnimationVector4D target, in AnimationVector4D source) { target._value.x = source._value.x; target._value.y = source._value.y; target._value.z = source._value.z; target._value.w = source._value.w; } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/DurationBasedAnimationSpec.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/DurationBasedAnimationSpec.cs index 53e9b756..d0796809 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/DurationBasedAnimationSpec.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/DurationBasedAnimationSpec.cs @@ -3,31 +3,41 @@ namespace LitMotion { - /// - /// 基于时长的动画规范抽象基类,适用于Tween、Keyframes等有限时长动画。 - /// - public abstract class DurationBasedAnimationSpec : IVectorizedAnimationSpec - where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - { - public abstract MotionTimeKind TimeKind { get; set; } + // /// + // /// Abstract base class for duration-based animation specifications, suitable for Tween, Keyframes and other finite duration animations. + // /// + // /// Internal vectorized value type + // /// Animation options type + // public abstract class DurationBasedAnimationSpec : IVectorizedAnimationSpec + // where VValue : unmanaged + // where TOptions : unmanaged, IMotionOptions + // { + // public abstract long DelayNanos { get; set; } + // public abstract long DurationNanos { get; set; } - public abstract long DelayNanos { get; set; } - public abstract long DurationNanos { get; set; } + // public abstract bool IsInfinite { get; } + // public bool IsDurationBased => true; - public abstract bool IsInfinite { get; } - public bool IsDurationBased => true; + // public abstract unsafe AnimationState* State { get; set; } + // public abstract unsafe TOptions* Options { get; set; } + // public abstract MotionTimeKind TimeKind { get; set; } - public abstract TValue GetValueFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) - where TAdapter : unmanaged, IMotionAdapter; - public abstract TValue GetVelocityFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) - where TAdapter : unmanaged, IMotionAdapter; - public virtual long GetDurationNanos(TValue startValue, TValue targetValue, TValue startVelocity) - where TAdapter : unmanaged, IMotionAdapter - { - return DurationNanos; - } - public abstract TValue GetEndVelocity(TValue startValue, TValue targetValue, TValue startVelocity) - where TAdapter : unmanaged, IMotionAdapter; - } + // public abstract void Initialize(TOptions options); + + // public abstract VValue GetValueFromNanos(long playTimeNanos, VValue startValue, VValue targetValue, VValue startVelocity) + // where TValue : unmanaged + // where TAdapter : unmanaged, IMotionAdapter; + // public abstract VValue GetVelocityFromNanos(long playTimeNanos, VValue startValue, VValue targetValue, VValue startVelocity) + // where TValue : unmanaged + // where TAdapter : unmanaged, IMotionAdapter; + // public virtual long GetDurationNanos(VValue startValue, VValue targetValue, VValue startVelocity) + // where TValue : unmanaged + // where TAdapter : unmanaged, IMotionAdapter + // { + // return DurationNanos; + // } + // public abstract VValue GetEndVelocity(VValue startValue, VValue targetValue, VValue startVelocity) + // where TValue : unmanaged + // where TAdapter : unmanaged, IMotionAdapter; + // } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/FloatingTweenAnimationSpec.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/FloatingTweenAnimationSpec.cs new file mode 100644 index 00000000..b8fef55c --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/FloatingTweenAnimationSpec.cs @@ -0,0 +1,177 @@ +using System; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace LitMotion +{ + /// + /// Float tween animation specification that implements vectorized animation support for float values. + /// This replaces the FloatMotionAdapter functionality. + /// + public struct FloatingTweenAnimationSpec : IVectorizedAnimationSpec + { + private TweenAnimationSpec core; + + public unsafe AnimationState* State + { + get => core.State; + set => core.State = value; + } + + public unsafe TweenOption* Options + { + get => core.Options; + set => core.Options = value; + } + + public MotionTimeKind TimeKind + { + get => core.TimeKind; + set => core.TimeKind = value; + } + + public unsafe long DelayNanos + { + get => core.DelayNanos; + set => core.DelayNanos = value; + } + + public long DelayMillis + { + get => core.DelayMillis; + set => core.DelayMillis = value; + } + + public int DelaySeconds + { + get => core.DelaySeconds; + set => core.DelaySeconds = value; + } + + public unsafe long DurationNanos + { + get => core.DurationNanos; + set => core.DurationNanos = value; + } + + public long DurationMillis + { + get => core.DurationMillis; + set => core.DurationMillis = value; + } + + public int DurationSeconds + { + get => core.DurationSeconds; + set => core.DurationSeconds = value; + } + + public unsafe int LoopCount + { + get => core.LoopCount; + set => core.LoopCount = value; + } + + public unsafe DelayType DelayType + { + get => core.DelayType; + set => core.DelayType = value; + } + + public unsafe LoopType LoopType + { + get => core.LoopType; + set => core.LoopType = value; + } + + public bool IsInfinite => core.IsInfinite; + + public bool IsDurationBased => core.IsDurationBased; + + public long GetDurationNanos() + { + return core.GetDurationNanos(); + } + + // 重写动画计算方法 + public float GetValueFromNanos(long playTimeNanos, float startValue, float targetValue, float startVelocity) + where TValue : unmanaged + { + // 处理延迟 + if (playTimeNanos < DelayNanos) + { + return startValue; + } + + var adjustedTime = playTimeNanos - DelayNanos; + var durationNanos = DurationNanos; + + if (durationNanos <= 0) + { + return targetValue; + } + + // 计算进度 + var progress = (float)(adjustedTime / (double)durationNanos); + + // 应用缓动 + var easedProgress = GetEasedValue(progress); + + // 线性插值 + return Mathf.LerpUnclamped(startValue, targetValue, easedProgress); + } + + public float GetVelocityFromNanos(long playTimeNanos, float startValue, float targetValue, float startVelocity) + where TValue : unmanaged + { + // 处理延迟 + if (playTimeNanos < DelayNanos) + { + return 0f; + } + + var adjustedTime = playTimeNanos - DelayNanos; + var durationNanos = DurationNanos; + + if (durationNanos <= 0) + { + return 0f; + } + + // 计算进度 + var progress = (float)(adjustedTime / (double)durationNanos); + + // 应用缓动导数 + var easedProgress = GetEasedValue(progress); + var velocity = (targetValue - startValue) / durationNanos * AnimationConstants.NanosToSeconds; + + return velocity; + } + + public float GetEndVelocity(float startValue, float targetValue, float startVelocity) + where TValue : unmanaged + { + return 0f; // Tween动画结束时速度为0 + } + + public long GetDurationNanos(float startValue, float targetValue, float startVelocity) + where TValue : unmanaged + { + return DurationNanos; + } + + public unsafe long TimeSinceStart => core.TimeSinceStart; + + public unsafe void Complete(out float progress) + { + core.Complete(out progress); + } + + private unsafe float GetEasedValue(float value) + { + // 从core获取缓动函数并应用 + // 这里需要根据Options中的缓动设置来计算 + return value; // 暂时返回线性值 + } + } +} \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IAnimationSpec.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IAnimationSpec.cs index 3cd362c3..0870a18c 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IAnimationSpec.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IAnimationSpec.cs @@ -5,51 +5,41 @@ namespace LitMotion public static class AnimationConstants { /// - /// 默认动画持续时间,单位为毫秒。used in [VectorizedAnimationSpec]s and [AnimationSpec] + /// Default animation duration in milliseconds. Used in [VectorizedAnimationSpec]s and [AnimationSpec] /// public const int DefaultDurationMillis = 300; /// - /// 未指定的时间常量,表示动画时间尚未设置。 + /// Unspecified time constant, indicating that animation time has not been set. /// public const long UnspecifiedTime = long.MinValue; internal const long MillisToNanos = 1_000_000L; - internal const long SecendsToNanos = 1_000_000_000L; -} + internal const long NanosToSeconds = 1_000_000_000L; + + internal const long SecondsToNanos = 1_000_000_000L; + } + /// - /// 动画规范接口,描述如何从起点到终点进行动画。 + /// Animation specification interface that describes how to animate from start to end. /// - /// 动画值类型 + /// Animation value type + /// Animation options type public interface IAnimationSpec where TValue : unmanaged where TOptions : unmanaged, IMotionOptions { - /// - /// 使用给定的双向转换器创建一个向量化动画规范。 - /// 底层动画系统基于 AnimationVector 进行操作。 - /// T 类型的动画值会被转换为 AnimationVector 进行动画处理。VectorizedAnimationSpec 描述了转换后的 AnimationVector 应该如何被动画化。 - /// 例如:动画可以简单地在起始值和结束值之间插值(如 TweenSpec),也可以应用弹簧物理效果产生运动(如 SpringSpec)等。 + /// Create a vectorized animation specification using the given two-way converter. + /// The underlying animation system operates on VValue. + /// TValue animation values are converted to VValue for animation processing. IVectorizedAnimationSpec describes how the converted VValue should be animated. + /// For example: animations can simply interpolate between start and end values (like TweenSpec), or apply spring physics effects to generate motion (like SpringSpec), etc. /// - /// - /// 用于在 T 类型和 AnimationVector 类型之间转换的转换器 - /// - IVectorizedAnimationSpec vectorize(ITwoWayConverter converter) - where TVector : unmanaged; - } - - /// - /// 动画值与向量的双向转换器 - /// - /// 动画值类型 - /// 向量类型 - public interface ITwoWayConverter - where TValue : unmanaged - where TVector : unmanaged - { - TVector ConvertToVector(TValue value); - TValue ConvertFromVector(TVector vector); + /// Vectorized value type + /// Converter used to convert between TValue type and VValue type + /// Vectorized animation specification + IVectorizedAnimationSpec Vectorize(ITwoWayConverter converter) + where VValue : unmanaged; } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IMotion.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IMotion.cs new file mode 100644 index 00000000..cd5a2b4e --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IMotion.cs @@ -0,0 +1,65 @@ +namespace LitMotion +{ + /// + /// Interface for motion animations that support both user-facing values (TValue) and internal vectorized values (VValue). + /// + /// User-facing animation value type + /// Internal vectorized value type + public interface IMotion + where TValue : unmanaged + where VValue : unmanaged + { + /// + /// The time kind for this motion (scaled, unscaled, or realtime). + /// + public MotionTimeKind MotionTimeKind + { + get; + set; + } + + /// + /// Whether this motion is infinite (loops indefinitely). + /// + public bool IsInfinite + { + get; + } + + /// + /// The duration of this motion in nanoseconds. + /// + public long DurationNanos + { + get; + } + + + /// + /// Get the current value at the specified play time. + /// + /// Play time in nanoseconds + /// Current value + public void GetValueFromNanos(long playTimeNanos,out TValue currentValue); + + /// + /// Get the current velocity vector at the specified play time. + /// + /// Play time in nanoseconds + /// Current velocity vector + public void GetVelocityVectorFromNanos(long playTimeNanos,out VValue currentVelocity); + + /// + /// Check if the motion is finished at the specified play time. + /// + /// Play time in nanoseconds + /// True if the motion is finished + public void IsFinishedFromNanos(long playTimeNanos,out bool isFinished); + + /// + /// Complete the motion and return the final value. + /// + /// Final value + public void Complete(out TValue currentValue); + } +} \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/ITwoWayConverter.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/ITwoWayConverter.cs new file mode 100644 index 00000000..61d823b9 --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/ITwoWayConverter.cs @@ -0,0 +1,26 @@ +namespace LitMotion +{ + /// + /// Two-way converter between animation values and vectorized values. + /// + /// Animation value type + /// Vectorized value type + public interface ITwoWayConverter + where TValue : unmanaged + where VValue : unmanaged + { + /// + /// Defines how a type TValue should be converted to a vectorized type VValue. + /// + /// The value to convert + /// The vectorized value + VValue ConvertToVector(TValue tValue); + + /// + /// Defines how to convert a vectorized type VValue back to type TValue. + /// + /// The vectorized value to convert + /// The converted value + TValue ConvertFromVector(VValue vectorizedValue); + } +} diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IntegerAnimationSpec.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IntegerAnimationSpec.cs new file mode 100644 index 00000000..1bebd305 --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/IntegerAnimationSpec.cs @@ -0,0 +1,180 @@ +using System; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace LitMotion +{ + /// + /// Integer tween animation specification that implements vectorized animation support for int values. + /// This replaces the IntMotionAdapter functionality. + /// + public struct IntegerTweenAnimationSpec : IVectorizedAnimationSpec + { + private TweenAnimationSpec core; + + public unsafe AnimationState* State + { + get => core.State; + set => core.State = value; + } + + public unsafe IntegerOptions* Options + { + get => core.Options; + set => core.Options = value; + } + + public MotionTimeKind TimeKind + { + get => core.TimeKind; + set => core.TimeKind = value; + } + + public unsafe long DelayNanos + { + get => core.DelayNanos; + set => core.DelayNanos = value; + } + + public long DelayMillis + { + get => core.DelayMillis; + set => core.DelayMillis = value; + } + + public int DelaySeconds + { + get => core.DelaySeconds; + set => core.DelaySeconds = value; + } + + public unsafe long DurationNanos + { + get => core.DurationNanos; + set => core.DurationNanos = value; + } + + public long DurationMillis + { + get => core.DurationMillis; + set => core.DurationMillis = value; + } + + public int DurationSeconds + { + get => core.DurationSeconds; + set => core.DurationSeconds = value; + } + + public unsafe int LoopCount + { + get => core.LoopCount; + set => core.LoopCount = value; + } + + public unsafe DelayType DelayType + { + get => core.DelayType; + set => core.DelayType = value; + } + + public unsafe LoopType LoopType + { + get => core.LoopType; + set => core.LoopType = value; + } + + public bool IsInfinite => core.IsInfinite; + + public bool IsDurationBased => core.IsDurationBased; + + public long GetDurationNanos() + { + return core.GetDurationNanos(); + } + + + + // 重写动画计算方法 + public int GetValueFromNanos(long playTimeNanos, int startValue, int targetValue, int startVelocity) + where TValue : unmanaged + { + // 处理延迟 + if (playTimeNanos < DelayNanos) + { + return startValue; + } + + var adjustedTime = playTimeNanos - DelayNanos; + var durationNanos = DurationNanos; + + if (durationNanos <= 0) + { + return targetValue; + } + + // 计算进度 + var progress = (float)(adjustedTime / (double)durationNanos); + + // 应用缓动 + var easedProgress = GetEasedValue(progress); + + // 线性插值并四舍五入到整数 + var interpolatedValue = Mathf.LerpUnclamped(startValue, targetValue, easedProgress); + return Mathf.RoundToInt(interpolatedValue); + } + + public int GetVelocityFromNanos(long playTimeNanos, int startValue, int targetValue, int startVelocity) + where TValue : unmanaged + { + // 处理延迟 + if (playTimeNanos < DelayNanos) + { + return 0; + } + + var adjustedTime = playTimeNanos - DelayNanos; + var durationNanos = DurationNanos; + + if (durationNanos <= 0) + { + return 0; + } + + // 计算进度 + var progress = (float)(adjustedTime / (double)durationNanos); + + // 应用缓动导数 + var easedProgress = GetEasedValue(progress); + var velocity = (targetValue - startValue) / durationNanos * AnimationConstants.NanosToSeconds; + + return Mathf.RoundToInt(velocity); + } + + public int GetEndVelocity(int startValue, int targetValue, int startVelocity) + where TValue : unmanaged + { + return 0; // Tween动画结束时速度为0 + } + + public long GetDurationNanos(int startValue, int targetValue, int startVelocity) + where TValue : unmanaged + { + return DurationNanos; + } + + public unsafe long TimeSinceStart => core.TimeSinceStart; + + public unsafe void Complete(out float progress) + { + core.Complete(out progress); + } + + private unsafe float GetEasedValue(float value) + { + // 从core获取缓动函数并应用 + // 这里需要根据Options中的缓动设置来计算 + return value; // 暂时返回线性值 + } + } +} \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/LoopBasedAnimationSpec.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/LoopBasedAnimationSpec.cs index 24332469..580366df 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/LoopBasedAnimationSpec.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/LoopBasedAnimationSpec.cs @@ -3,27 +3,32 @@ namespace LitMotion { - public abstract class LoopBasedAnimationSpec : DurationBasedAnimationSpec - where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - { - public abstract int LoopCount { get; set; } - public abstract DelayType DelayType { get; set; } - public abstract LoopType LoopType { get; set; } + // /// + // /// Abstract base class for loop-based animation specifications that support repeating animations. + // /// + // /// Internal vectorized value type + // /// Animation options type + // public abstract class LoopBasedAnimationSpec : DurationBasedAnimationSpec + // where VValue : unmanaged + // where TOptions : unmanaged, IMotionOptions + // { + // public abstract int LoopCount { get; set; } + // public abstract DelayType DelayType { get; set; } + // public abstract LoopType LoopType { get; set; } - public override bool IsInfinite => LoopCount < 0; + // public override bool IsInfinite => LoopCount < 0; - public long GetDurationNanos() - { - if (IsInfinite) return long.MaxValue; - return DelayNanos * (DelayType == DelayType.EveryLoop ? LoopCount : 1) + DurationNanos * LoopCount; - } + // public long GetDurationNanos() + // { + // if (IsInfinite) return long.MaxValue; + // return DelayNanos * (DelayType == DelayType.EveryLoop ? LoopCount : 1) + DurationNanos * LoopCount; + // } - public override long GetDurationNanos(TValue startValue, TValue targetValue, TValue startVelocity) - { - return GetDurationNanos(); - } - } + // public override long GetDurationNanos(VValue startValue, VValue targetValue, VValue startVelocity) + // { + // return GetDurationNanos(); + // } + // } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/SpringAnimationSpec.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/SpringAnimationSpec.cs index dfa27db0..b4dadd0e 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/SpringAnimationSpec.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/SpringAnimationSpec.cs @@ -4,59 +4,67 @@ namespace LitMotion { /// - /// 弹簧动画规范,实现基于物理的弹性动画。 + /// Spring animation specification that implements physics-based elastic animations. /// - /// 动画值类型 - public class SpringAnimationSpec : IVectorizedAnimationSpec - where TValue : unmanaged + /// Internal vectorized value type + /// Animation options type + public class SpringAnimationSpec : IVectorizedAnimationSpec + where VValue : unmanaged where TOptions : unmanaged, IMotionOptions { - private MotionTimeKind timeKind; - public MotionTimeKind TimeKind - { - get => timeKind; - set => timeKind = value; - } + // public long _delayNanos; + // public long DelayNanos + // { + // get => _delayNanos; + // set => _delayNanos = value < 0 ? 0 : value; + // } - public long _delayNanos; - public long DelayNanos - { - get => _delayNanos; - set => _delayNanos = value < 0 ? 0 : value; - } - - public long DelayMillis - { - get => _delayNanos / AnimationConstants.MillisToNanos; - set => DelayNanos = value * AnimationConstants.MillisToNanos; - } + // public long DelayMillis + // { + // get => _delayNanos / AnimationConstants.MillisToNanos; + // set => DelayNanos = value * AnimationConstants.MillisToNanos; + // } - public int DelaySeconds - { - get => (int)(_delayNanos / AnimationConstants.SecendsToNanos); - set => DelayNanos = value * AnimationConstants.SecendsToNanos; - } + // public int DelaySeconds + // { + // get => (int)(_delayNanos / AnimationConstants.SecondsToNanos); + // set => DelayNanos = value * AnimationConstants.SecondsToNanos; + // } private bool _isInfinite; public bool IsInfinite => _isInfinite; public bool IsDurationBased => false; - public TValue GetValueFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) where TAdapter : unmanaged, IMotionAdapter + public unsafe AnimationState* State { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public unsafe TOptions* Options { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public MotionTimeKind TimeKind { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + //public AnimationState State { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public void Initialize(TOptions options) + { + throw new NotImplementedException(); + } + public VValue GetValueFromNanos(long playTimeNanos, VValue startValue, VValue targetValue, VValue startVelocity) + where TValue : unmanaged { throw new NotImplementedException(); } - public TValue GetVelocityFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) where TAdapter : unmanaged, IMotionAdapter + public VValue GetVelocityFromNanos(long playTimeNanos, VValue startValue, VValue targetValue, VValue startVelocity) + where TValue : unmanaged { throw new NotImplementedException(); } - public long GetDurationNanos(TValue startValue, TValue targetValue, TValue startVelocity) where TAdapter : unmanaged, IMotionAdapter + public long GetDurationNanos(VValue startValue, VValue targetValue, VValue startVelocity) + where TValue : unmanaged { throw new NotImplementedException(); } - public TValue GetEndVelocity(TValue startValue, TValue targetValue, TValue startVelocity) where TAdapter : unmanaged, IMotionAdapter + public VValue GetEndVelocity(VValue startValue, VValue targetValue, VValue startVelocity) + where TValue : unmanaged { throw new NotImplementedException(); } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/TargetBasedAnimation.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/TargetBasedAnimation.cs new file mode 100644 index 00000000..6a1bec22 --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/TargetBasedAnimation.cs @@ -0,0 +1,205 @@ +using System; +using System.Runtime.CompilerServices; +using Unity.Burst.CompilerServices; + +namespace LitMotion +{ + public struct AnimationState + { + public MotionStatus Status; + public MotionStatus PrevStatus; + public bool IsPreserved; + public bool IsInSequence; + + public ushort CompletedLoops; + public ushort PrevCompletedLoops; + + public long playTimeNanos; + + public double Time + { + get + { + return playTimeNanos / AnimationConstants.NanosToSeconds; + } + set + { + playTimeNanos = (long)(value * AnimationConstants.SecondsToNanos); + } + } + public float PlaybackSpeed; + + public readonly bool WasStatusChanged => Status != PrevStatus; + public readonly bool WasLoopCompleted => CompletedLoops > PrevCompletedLoops; + } + + public struct TargetBasedAnimation : IMotion + where TValue : unmanaged + where VValue : unmanaged + where TOptions : unmanaged, IMotionOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + { + + public TAnimationSpec Core; + + // 移除接口依赖,改为使用函数指针或泛型约束 + // 暂时使用简单的转换逻辑,后续可以通过泛型约束或函数指针优化 + + private TValue _mutableTargetValue; + private TValue _mutableInitialValue; + + private VValue initialValueVector; + private VValue targetValueVector; + private VValue initialVelocityVector; + + //private long _durationNanos; + private VValue _endVelocity; + + public MotionTimeKind MotionTimeKind + { + get => Core.TimeKind; + set => Core.TimeKind = value; + } + + public unsafe void Initialize(TOptions options, TValue startValue, TValue targetValue, VValue startVelocityVector = default) + { + Core.State->Status = MotionStatus.Scheduled; + Core.State->Time = 0; + Core.State->PlaybackSpeed = 1f; + Core.State->IsPreserved = false; + + Core.Options = &options; + _mutableInitialValue = startValue; + _mutableTargetValue = targetValue; + ConvertToVector(startValue,out initialValueVector); + ConvertToVector(targetValue,out targetValueVector); + initialVelocityVector = startVelocityVector; + _endVelocity = default; + } + + // 简单的转换方法,假设TValue和VValue是相同的类型 + private static void ConvertToVector(in TValue value,out VValue vectorValue) + { + // 这里需要根据具体类型实现转换逻辑 + // 暂时使用unsafe转换,假设内存布局相同 + vectorValue = default; + } + + private static void ConvertFromVector(in VValue vectorValue, out TValue value) + { + value = default; + } + + public TValue StartValue + { + get => _mutableInitialValue; + set + { + if (!Equals(_mutableInitialValue, value)) + { + _mutableInitialValue = value; + ConvertToVector(value,out initialValueVector); + _endVelocity = default; + } + } + } + + public TValue TargetValue + { + get => _mutableTargetValue; + set + { + if (!Equals(_mutableTargetValue, value)) + { + _mutableTargetValue = value; + ConvertToVector(value,out targetValueVector); + _endVelocity = default; + } + } + } + + public bool IsInfinite => Core.IsInfinite; + + public void IsFinishedFromNanos(long playTimeNanos,out bool isFinished) + { + isFinished = Hint.Unlikely(playTimeNanos >= DurationNanos); + } + + public void GetValueFromNanos(long playTimeNanos,out TValue currentValue) + { + IsFinishedFromNanos(playTimeNanos,out bool isFinished); + if (Hint.Likely(!isFinished)) + { + var vec = Core.GetValueFromNanos( + playTimeNanos, + initialValueVector, + targetValueVector, + initialVelocityVector + ); + ConvertFromVector(vec,out currentValue); + } + else + { + currentValue = TargetValue; + } + } + public long DurationNanos + { + get + { + return Core.GetDurationNanos( + initialValueVector, + targetValueVector, + initialVelocityVector); + } + } + + private VValue EndVelocity + { + get + { + if (_endVelocity.Equals(default(VValue))) + { + _endVelocity = Core.GetEndVelocity( + initialValueVector, + targetValueVector, + initialVelocityVector + ); + } + return _endVelocity; + } + } + public void GetVelocityVectorFromNanos(long playTimeNanos,out VValue currentVelocity) + { + IsFinishedFromNanos(playTimeNanos,out bool isFinished); + if (Hint.Likely(!isFinished)) + { + currentVelocity = Core.GetVelocityFromNanos( + playTimeNanos, + initialValueVector, + targetValueVector, + initialVelocityVector + ); + } + else + { + currentVelocity = EndVelocity; + } + } + + public void Complete(out TValue currentValue) + { + ConvertFromVector(Core.GetValueFromNanos( + DurationNanos, + initialValueVector, + targetValueVector, + initialVelocityVector + ),out currentValue); + } + + public override string ToString() + { + return $"TargetBasedAnimation: {StartValue} -> {TargetValue}, initial velocity: {initialVelocityVector}, duration: {DurationNanos / 1_000_000} ms, animationSpec: {Core}"; + } + } +} \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/TweenAnimationSpec.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/TweenAnimationSpec.cs index 86bdc61b..ac5db47e 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/TweenAnimationSpec.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/TweenAnimationSpec.cs @@ -7,58 +7,137 @@ namespace LitMotion { - internal struct TweenAnimationSpec + /// + /// Tween animation specification that combines MotionData functionality with vectorized animation support. + /// + /// Internal vectorized value type + /// Animation options type + public struct TweenAnimationSpec : IVectorizedAnimationSpec + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions { -public struct AnimationState + private unsafe AnimationState state; + private unsafe TOptions options; + private MotionTimeKind timeKind; + + + public unsafe AnimationState* State + { + get + { + fixed (AnimationState* statePtr = &state) + { + return statePtr; + } + } + set => state = *value; + } + public unsafe TOptions* Options + { + get + { + fixed (TOptions* optionsPtr = &options) + { + return optionsPtr; + } + } + set => options = *value; + } + public MotionTimeKind TimeKind { get => timeKind; set => timeKind = value; } + + public unsafe long DelayNanos { - public MotionStatus Status; - public MotionStatus PrevStatus; - public bool IsPreserved; - public bool IsInSequence; + readonly get => options.DelayNanos; + set => options.DelayNanos = value < 0 ? 0 : value; + } - public ushort CompletedLoops; - public ushort PrevCompletedLoops; + public long DelayMillis + { + readonly get => DelayNanos / AnimationConstants.MillisToNanos; + set => DelayNanos = value * AnimationConstants.MillisToNanos; + } + + public int DelaySeconds + { + readonly get => (int)(DelayNanos / AnimationConstants.SecondsToNanos); + set => DelayNanos = value * AnimationConstants.SecondsToNanos; + } + + public unsafe long DurationNanos + { + readonly get => options.DurationNanos; + set => options.DurationNanos = value < 0 ? 0 : value; + } - public long playTimeNanos; - public float PlaybackSpeed; + public long DurationMillis + { + readonly get => DurationNanos / AnimationConstants.MillisToNanos; + set => DurationNanos = value * AnimationConstants.MillisToNanos; + } - public readonly bool WasStatusChanged => Status != PrevStatus; - public readonly bool WasLoopCompleted => CompletedLoops > PrevCompletedLoops; + public int DurationSeconds + { + get => (int)(DurationNanos / AnimationConstants.SecondsToNanos); + set => DurationNanos = value * AnimationConstants.SecondsToNanos; + } + public unsafe int LoopCount + { + readonly get => options.Loops; + set => options.Loops = value < 0 ? -1 : value; // -1 for infinite loops } - public struct TweenSpecParameters + public unsafe DelayType DelayType { - public MotionTimeKind TimeKind; - public long DurationNanos; - public long DelayNanos; - public DelayType DelayType; - public Ease Ease; - public int Loops; - public LoopType LoopType; + readonly get => options.DelayType; + set => options.DelayType = value; + } + public unsafe LoopType LoopType + { + readonly get => options.LoopType; + set => options.LoopType = value; + } + public Ease Ease + { + readonly get => options.Ease; + set => options.Ease = value; + } #if LITMOTION_COLLECTIONS_2_0_OR_NEWER - public NativeAnimationCurve AnimationCurve; -#else - public UnsafeAnimationCurve AnimationCurve; -#endif + public NativeAnimationCurve AnimationCurve + { + readonly get => options.AnimationCurve; + set => options.AnimationCurve = value; } - public AnimationState State; - public TweenSpecParameters Parameters; - public Ease Ease +#else + public UnsafeAnimationCurve AnimationCurve { - get => Parameters.Ease; - set => Parameters.Ease = value; + readonly get => options.AnimationCurve; + set => options.AnimationCurve = value; } - public long TimeSinceStart => State.playTimeNanos - Parameters.DelayNanos; +#endif + + public bool IsInfinite => LoopCount < 0; - // MotionData interface - Update method - public void Update(long playTimeNanos, out float progress) + public readonly bool IsDurationBased => true; + + public long GetDurationNanos() { - State.PrevCompletedLoops = State.CompletedLoops; - State.PrevStatus = State.Status; + if (IsInfinite) return long.MaxValue; + return DelayNanos * (DelayType == DelayType.EveryLoop ? LoopCount : 1) + DurationNanos * LoopCount; + } - State.playTimeNanos = playTimeNanos; - playTimeNanos = Math.Max(playTimeNanos, 0); + + + public VValue GetValueFromNanos(long playTimeNanos, VValue startValue, VValue targetValue, VValue startVelocity) + where TValue : unmanaged + { + // 更新状态 + state.PrevCompletedLoops = state.CompletedLoops; + state.PrevStatus = state.Status; + state.playTimeNanos = playTimeNanos; + + // 确保时间不为负数 + playTimeNanos = math.max(playTimeNanos, 0L); double t; bool isCompleted; @@ -66,73 +145,79 @@ public void Update(long playTimeNanos, out float progress) int completedLoops; int clampedCompletedLoops; - if (Hint.Unlikely(Parameters.DurationNanos <= 0)) + // 处理瞬时动画(Duration <= 0) + if (Hint.Unlikely(DurationNanos <= 0L)) { - if (Parameters.DelayType == DelayType.FirstLoop || Parameters.DelayNanos == 0f) + if (DelayType == DelayType.FirstLoop || DelayNanos == 0L) { - isCompleted = Parameters.Loops >= 0 && TimeSinceStart > 0f; + isCompleted = LoopCount >= 0 && TimeSinceStart > 0L; if (isCompleted) { - t = 1f; - completedLoops = Parameters.Loops; + t = 1.0; + completedLoops = LoopCount; } else { - t = 0f; - completedLoops = TimeSinceStart < 0f ? -1 : 0; + t = 0.0; + completedLoops = TimeSinceStart < 0L ? -1 : 0; } clampedCompletedLoops = GetClampedCompletedLoops(completedLoops); - isDelayed = TimeSinceStart < 0; + isDelayed = TimeSinceStart < 0L; } else { - completedLoops = (int)Math.Floor((decimal)(playTimeNanos / Parameters.DelayNanos)); + completedLoops = (int)math.floor(playTimeNanos / DelayNanos); clampedCompletedLoops = GetClampedCompletedLoops(completedLoops); - isCompleted = Parameters.Loops >= 0 && clampedCompletedLoops > Parameters.Loops - 1; + isCompleted = LoopCount >= 0 && clampedCompletedLoops > LoopCount - 1; isDelayed = !isCompleted; - t = isCompleted ? 1f : 0f; + t = isCompleted ? 1.0 : 0.0; } } else { - if (Parameters.DelayType == DelayType.FirstLoop) + // 处理正常动画 + if (DelayType == DelayType.FirstLoop) { - completedLoops = (int)Math.Floor((decimal)(TimeSinceStart / Parameters.DurationNanos)); + completedLoops = (int)math.floor(TimeSinceStart / DurationNanos); clampedCompletedLoops = GetClampedCompletedLoops(completedLoops); - isCompleted = Parameters.Loops >= 0 && clampedCompletedLoops > Parameters.Loops - 1; - isDelayed = TimeSinceStart < 0f; + isCompleted = LoopCount >= 0 && clampedCompletedLoops > LoopCount - 1; + isDelayed = TimeSinceStart < 0L; if (isCompleted) { - t = 1f; + t = 1.0; } else { - var currentLoopTime = TimeSinceStart - Parameters.DurationNanos * clampedCompletedLoops; - t = Math.Clamp(currentLoopTime / Parameters.DurationNanos, 0f, 1f); + var currentLoopTime = TimeSinceStart - DurationNanos * clampedCompletedLoops; + t = math.clamp(currentLoopTime / (double)DurationNanos, 0.0, 1.0); } } else { - var currentLoopTime = (playTimeNanos % (Parameters.DurationNanos + Parameters.DelayNanos)) - Parameters.DelayNanos; - completedLoops = (int)Math.Floor((decimal)(playTimeNanos / (Parameters.DurationNanos + Parameters.DelayNanos))); + var currentLoopTime = math.fmod(playTimeNanos, DurationNanos + DelayNanos) - DelayNanos; + completedLoops = (int)math.floor(playTimeNanos / (DurationNanos + DelayNanos)); clampedCompletedLoops = GetClampedCompletedLoops(completedLoops); - isCompleted = Parameters.Loops >= 0 && clampedCompletedLoops > Parameters.Loops - 1; - isDelayed = currentLoopTime < 0; + isCompleted = LoopCount >= 0 && clampedCompletedLoops > LoopCount - 1; + isDelayed = currentLoopTime < 0L; if (isCompleted) { - t = 1f; + t = 1.0; } else { - t = math.clamp(currentLoopTime / Parameters.DurationNanos, 0f, 1f); + t = math.clamp(currentLoopTime / (double)DurationNanos, 0.0, 1.0); } } } - State.CompletedLoops = (ushort)clampedCompletedLoops; - switch (Parameters.LoopType) + // 更新完成循环数 + state.CompletedLoops = (ushort)clampedCompletedLoops; + + // 计算最终进度值(float 类型,用于缓动计算) + float progress; + switch (LoopType) { default: case LoopType.Restart: @@ -140,10 +225,12 @@ public void Update(long playTimeNanos, out float progress) break; case LoopType.Flip: progress = GetEasedValue((float)t); - if ((clampedCompletedLoops + (int)t) % 2 == 1) progress = 1f - progress; + if ((clampedCompletedLoops + (int)t) % 2 == 1) + progress = 1f - progress; // 翻转时反转进度 break; case LoopType.Incremental: - progress = GetEasedValue(1f) * clampedCompletedLoops + GetEasedValue((float)math.fmod(t, 1f)); + var incrementalProgress = GetEasedValue(1f) * clampedCompletedLoops + GetEasedValue((float)math.fmod(t, 1f)); + progress = incrementalProgress; break; case LoopType.Yoyo: progress = (clampedCompletedLoops + (int)t) % 2 == 1 @@ -152,162 +239,154 @@ public void Update(long playTimeNanos, out float progress) break; } + // 更新状态 if (isCompleted) { - State.Status = MotionStatus.Completed; + state.Status = MotionStatus.Completed; } - else if (isDelayed || State.playTimeNanos < 0) + else if (isDelayed || state.playTimeNanos < 0L) { - State.Status = MotionStatus.Delayed; + state.Status = MotionStatus.Delayed; } else { - State.Status = MotionStatus.Playing; + state.Status = MotionStatus.Playing; } - } - // MotionData interface - Complete method - public void Complete(out float progress) - { - State.Status = MotionStatus.Completed; - State.playTimeNanos = Parameters.DurationNanos; - State.CompletedLoops = (ushort)Parameters.Loops; - - progress = GetEasedValue(Parameters.LoopType switch - { - LoopType.Restart => 1f, - LoopType.Flip or LoopType.Yoyo => Parameters.Loops % 2 == 0 ? 0f : 1f, - LoopType.Incremental => Parameters.Loops, - _ => 1f - }); - } - int GetClampedCompletedLoops(int completedLoops) - { - return Parameters.Loops < 0 - ? math.max(0, completedLoops) - : math.clamp(completedLoops, 0, Parameters.Loops); + // 使用计算出的进度值进行向量插值 + return Lerp(startValue, targetValue, progress); } - float GetEasedValue(float value) + // 通用的线性插值方法,支持常见的 Unity 类型 + private VValue Lerp(VValue start, VValue end, float t) { - return Parameters.Ease switch + // 使用泛型约束和类型检查来实现类型安全的插值 + if (typeof(VValue) == typeof(float)) { - Ease.CustomAnimationCurve => Parameters.AnimationCurve.Evaluate(value), - _ => EaseUtility.Evaluate(value, Parameters.Ease) - }; + var startFloat = Unsafe.As(ref start); + var endFloat = Unsafe.As(ref end); + var result = math.lerp(startFloat, endFloat, t); + return Unsafe.As(ref result); + } + else if (typeof(VValue) == typeof(float2)) + { + var startFloat2 = Unsafe.As(ref start); + var endFloat2 = Unsafe.As(ref end); + var result = math.lerp(startFloat2, endFloat2, t); + return Unsafe.As(ref result); + } + else if (typeof(VValue) == typeof(float3)) + { + var startFloat3 = Unsafe.As(ref start); + var endFloat3 = Unsafe.As(ref end); + var result = math.lerp(startFloat3, endFloat3, t); + return Unsafe.As(ref result); + } + else if (typeof(VValue) == typeof(float4)) + { + var startFloat4 = Unsafe.As(ref start); + var endFloat4 = Unsafe.As(ref end); + var result = math.lerp(startFloat4, endFloat4, t); + return Unsafe.As(ref result); + } + else if (typeof(VValue) == typeof(quaternion)) + { + var startQuat = Unsafe.As(ref start); + var endQuat = Unsafe.As(ref end); + var result = math.nlerp(startQuat, endQuat, t); + return Unsafe.As(ref result); + } + else + { + // 对于不支持的类型,返回默认值 + // 在实际使用中,应该为每种 VValue 类型创建专门的 TweenAnimationSpec 实现 + return default; + } } - } - /// - /// Tween animation specification that combines MotionData functionality with vectorized animation support. - /// - /// Type of the animation vector - internal class TweenAnimationSpec : LoopBasedAnimationSpec - where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - { - // Because of pointer casting, this field must always be placed at the beginning. - public TweenAnimationSpec Core; - - public TValue StartValue; - public TValue EndValue; - public TOptions Options; - - public override MotionTimeKind TimeKind + public VValue GetVelocityFromNanos(long playTimeNanos, VValue startValue, VValue targetValue, VValue startVelocity) + where TValue : unmanaged { - get => Core.Parameters.TimeKind; - set => Core.Parameters.TimeKind = value; + throw new NotImplementedException(); } - public override long DelayNanos + public VValue GetEndVelocity(VValue startValue, VValue targetValue, VValue startVelocity) + where TValue : unmanaged { - get => Core.Parameters.DelayNanos; - set => Core.Parameters.DelayNanos = value < 0 ? 0 : value; + throw new NotImplementedException(); } - public long DelayMillis + public long GetDurationNanos(VValue startValue, VValue targetValue, VValue startVelocity) + where TValue : unmanaged { - get => DelayNanos / AnimationConstants.MillisToNanos; - set => DelayNanos = value * AnimationConstants.MillisToNanos; + return GetDurationNanos(); } - public int DelaySeconds + public VValue ConvertToVector(TValue value) where TValue : unmanaged { - get => (int)(DelayNanos / AnimationConstants.SecendsToNanos); - set => DelayNanos = value * AnimationConstants.SecendsToNanos; + // 对于TweenAnimationSpec,我们需要根据VValue类型来实现转换 + // 这是一个抽象方法,具体的转换逻辑应该在具体的实现中 + throw new NotImplementedException("ConvertToVector should be implemented in concrete TweenAnimationSpec implementations"); } - public override long DurationNanos + public TValue ConvertFromVector(VValue vector) where TValue : unmanaged { - get => Core.Parameters.DurationNanos; - set => Core.Parameters.DurationNanos = value < 0 ? 0 : value; + // 对于TweenAnimationSpec,我们需要根据VValue类型来实现转换 + // 这是一个抽象方法,具体的转换逻辑应该在具体的实现中 + throw new NotImplementedException("ConvertFromVector should be implemented in concrete TweenAnimationSpec implementations"); } - public long DurationMillis - { - get => DurationNanos / AnimationConstants.MillisToNanos; - set => DurationNanos = value * AnimationConstants.MillisToNanos; - } + public unsafe long TimeSinceStart => state.playTimeNanos - options.DelayNanos; - public int DurationSeconds + // MotionData interface - Complete method + public unsafe void Complete(out float progress) { - get => (int)(DurationNanos / AnimationConstants.SecendsToNanos); - set => DurationNanos = value * AnimationConstants.SecendsToNanos; - } + state.Status = MotionStatus.Completed; + state.playTimeNanos = DurationNanos; + state.CompletedLoops = (ushort)LoopCount; - public override int LoopCount - { - get => Core.Parameters.Loops; - set => Core.Parameters.Loops = value < 0 ? -1 : value; // -1 for infinite loops - } - public override DelayType DelayType - { - get => Core.Parameters.DelayType; - set => Core.Parameters.DelayType = value; - } - public override LoopType LoopType - { - get => Core.Parameters.LoopType; - set => Core.Parameters.LoopType = value; - } - public override TValue GetValueFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) - { - long clampedPlayTimeNanos = Math.Clamp(playTimeNanos, 0, DurationNanos); - Core.Update(clampedPlayTimeNanos, out float fraction); - return default(TAdapter).Evaluate(ref StartValue, ref EndValue, ref Options, new MotionEvaluationContext() + progress = GetEasedValue(LoopType switch { - Progress = fraction, - Time = clampedPlayTimeNanos, + LoopType.Restart => 1f, + LoopType.Flip or LoopType.Yoyo => LoopCount % 2 == 0 ? 0f : 1f, + LoopType.Incremental => LoopCount, + _ => 1f }); } - - public override TValue GetVelocityFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) + unsafe int GetClampedCompletedLoops(int completedLoops) { - throw new NotImplementedException(); + return LoopCount < 0 + ? math.max(0, completedLoops) + : math.clamp(completedLoops, 0, LoopCount); } - public override TValue GetEndVelocity(TValue startValue, TValue targetValue, TValue startVelocity) + // 获取缓动后的标量值 + private float GetEasedValue(float t) { - throw new NotImplementedException(); + return Ease switch + { + Ease.CustomAnimationCurve => AnimationCurve.Evaluate(t), + _ => EaseUtility.Evaluate(t, Ease) + }; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Complete(out TValue result) - where TAdapter : unmanaged, IMotionAdapter - { - Core.Complete(out var progress); + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // public void Complete(out TValue result) + // where TAdapter : unmanaged, IMotionAdapter + // { + // Core.Complete(out var progress); - result = default(TAdapter).Evaluate( - ref StartValue, - ref EndValue, - ref Options, - new() - { - Progress = progress, - Time = Core.State.playTimeNanos, - } - ); - } + // result = default(TAdapter).Evaluate( + // ref StartValue, + // ref EndValue, + // ref Options, + // new() + // { + // Progress = progress, + // Time = Core.State.playTimeNanos, + // } + // ); + // } } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/VectorizedAnimationSpec.cs b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/VectorizedAnimationSpec.cs index b276014a..6c31d64c 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/VectorizedAnimationSpec.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/AnimationSpec/VectorizedAnimationSpec.cs @@ -3,18 +3,41 @@ namespace LitMotion { - public interface IVectorizedAnimationSpec - where TValue : unmanaged + public interface IVectorizedAnimationSpec + where VValue : unmanaged where TOptions : unmanaged, IMotionOptions { - TValue GetValueFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) - where TAdapter : unmanaged, IMotionAdapter; - TValue GetVelocityFromNanos(long playTimeNanos, TValue startValue, TValue targetValue, TValue startVelocity) - where TAdapter : unmanaged, IMotionAdapter; - long GetDurationNanos(TValue startValue, TValue targetValue, TValue startVelocity) - where TAdapter : unmanaged, IMotionAdapter; - TValue GetEndVelocity(TValue startValue, TValue targetValue, TValue startVelocity) - where TAdapter : unmanaged, IMotionAdapter; + public unsafe AnimationState* State + { + get; + set; + } + public unsafe TOptions* Options + { + get; + set; + } + public MotionTimeKind TimeKind + { + get; + set; + } + + public bool IsInfinite { get; } + + // // 类型转换方法 + // VValue ConvertToVector(TValue value) where TValue : unmanaged; + // TValue ConvertFromVector(VValue vector) where TValue : unmanaged; + + // 动画计算方法 + VValue GetValueFromNanos(long playTimeNanos, VValue startValue, VValue targetValue, VValue startVelocity) + where TValue : unmanaged; + VValue GetVelocityFromNanos(long playTimeNanos, VValue startValue, VValue targetValue, VValue startVelocity) + where TValue : unmanaged; + long GetDurationNanos(VValue startValue, VValue targetValue, VValue startVelocity) + where TValue : unmanaged; + VValue GetEndVelocity(VValue startValue, VValue targetValue, VValue startVelocity) + where TValue : unmanaged; } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionAudioExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionAudioExtensions.cs index fb8ef2d8..c5554835 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionAudioExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionAudioExtensions.cs @@ -17,9 +17,9 @@ public static class LitMotionAudioExtensions /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToVolume(this MotionBuilder builder, AudioSource audioSource) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToVolume(this MotionBuilder builder, AudioSource audioSource) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(audioSource); return builder.Bind(audioSource, static (x, target) => @@ -36,9 +36,9 @@ public static MotionHandle BindToVolume(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToPitch(this MotionBuilder builder, AudioSource audioSource) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPitch(this MotionBuilder builder, AudioSource audioSource) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(audioSource); return builder.Bind(audioSource, static (x, target) => @@ -55,9 +55,9 @@ public static MotionHandle BindToPitch(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToAudioMixerFloat(this MotionBuilder builder, AudioMixer audioMixer, string name) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToAudioMixerFloat(this MotionBuilder builder, AudioMixer audioMixer, string name) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(audioMixer); return builder.Bind(audioMixer, name, static (x, audioMixer, name) => diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionCameraExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionCameraExtensions.cs index d0b93604..0153dada 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionCameraExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionCameraExtensions.cs @@ -15,9 +15,9 @@ public static class LitMotionCameraExtensions /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToAspect(this MotionBuilder builder, Camera camera) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToAspect(this MotionBuilder builder, Camera camera) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(camera); return builder.Bind(camera, static (x, camera) => @@ -34,9 +34,9 @@ public static MotionHandle BindToAspect(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToNearClipPlane(this MotionBuilder builder, Camera camera) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToNearClipPlane(this MotionBuilder builder, Camera camera) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(camera); return builder.Bind(camera, static (x, camera) => @@ -53,9 +53,9 @@ public static MotionHandle BindToNearClipPlane(this MotionBu /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToFarClipPlane(this MotionBuilder builder, Camera camera) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToFarClipPlane(this MotionBuilder builder, Camera camera) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(camera); return builder.Bind(camera, static (x, camera) => @@ -72,9 +72,9 @@ public static MotionHandle BindToFarClipPlane(this MotionBui /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToFieldOfView(this MotionBuilder builder, Camera camera) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToFieldOfView(this MotionBuilder builder, Camera camera) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(camera); return builder.Bind(camera, static (x, camera) => @@ -91,9 +91,9 @@ public static MotionHandle BindToFieldOfView(this MotionBuil /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToOrthographicSize(this MotionBuilder builder, Camera camera) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToOrthographicSize(this MotionBuilder builder, Camera camera) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(camera); return builder.Bind(camera, static (x, camera) => @@ -110,9 +110,9 @@ public static MotionHandle BindToOrthographicSize(this Motio /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToRect(this MotionBuilder builder, Camera camera) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToRect(this MotionBuilder builder, Camera camera) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(camera); return builder.Bind(camera, static (x, camera) => @@ -129,9 +129,9 @@ public static MotionHandle BindToRect(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToPixelRect(this MotionBuilder builder, Camera camera) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPixelRect(this MotionBuilder builder, Camera camera) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(camera); return builder.Bind(camera, static (x, camera) => @@ -148,9 +148,9 @@ public static MotionHandle BindToPixelRect(this MotionBuilde /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToBackgroundColor(this MotionBuilder builder, Camera camera) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToBackgroundColor(this MotionBuilder builder, Camera camera) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(camera); return builder.Bind(camera, static (x, camera) => diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionLoggerExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionLoggerExtensions.cs index d8606805..909386c4 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionLoggerExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionLoggerExtensions.cs @@ -19,10 +19,11 @@ public static class LitMotionLoggerExtensions /// The type of adapter that support value animation /// This builder /// Handle of the created motion data. - public static MotionHandle BindToUnityLogger(this MotionBuilder builder) + public static MotionHandle BindToUnityLogger(this MotionBuilder builder) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { return builder.Bind(static x => Debug.unityLogger.Log(x)); } @@ -36,10 +37,11 @@ public static MotionHandle BindToUnityLogger(this Mo /// This builder /// Log format /// Handle of the created motion data. - public static MotionHandle BindToUnityLogger(this MotionBuilder builder, string format) + public static MotionHandle BindToUnityLogger(this MotionBuilder builder, string format) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { return builder.Bind(format, static (x, format) => { @@ -60,10 +62,11 @@ public static MotionHandle BindToUnityLogger(this Mo /// The type of adapter that support value animation /// This builder /// Handle of the created motion data. - public static MotionHandle BindToUnityLogger(this MotionBuilder builder, ILogger logger) + public static MotionHandle BindToUnityLogger(this MotionBuilder builder, ILogger logger) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(logger); return builder.Bind(logger, static (x, logger) => logger.Log(x)); @@ -79,10 +82,11 @@ public static MotionHandle BindToUnityLogger(this Mo /// Logger /// Log format /// Handle of the created motion data. - public static MotionHandle BindToUnityLogger(this MotionBuilder builder, ILogger logger, string format) + public static MotionHandle BindToUnityLogger(this MotionBuilder builder, ILogger logger, string format) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(logger); return builder.Bind(logger, format, static (x, logger, format) => diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionMaterialExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionMaterialExtensions.cs index 762ef85e..ee981106 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionMaterialExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionMaterialExtensions.cs @@ -15,9 +15,9 @@ public static class LitMotionMaterialExtensions /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToMaterialFloat(this MotionBuilder builder, Material material, string name) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToMaterialFloat(this MotionBuilder builder, Material material, string name) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(material); return builder.Bind(material, name, static (x, material, name) => @@ -34,9 +34,9 @@ public static MotionHandle BindToMaterialFloat(this MotionBu /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToMaterialFloat(this MotionBuilder builder, Material material, int nameID) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToMaterialFloat(this MotionBuilder builder, Material material, int nameID) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(material); return builder.Bind(material, Box.Create(nameID), static (x, material, nameID) => @@ -53,9 +53,9 @@ public static MotionHandle BindToMaterialFloat(this MotionBu /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToMaterialInt(this MotionBuilder builder, Material material, string name) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToMaterialInt(this MotionBuilder builder, Material material, string name) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(material); return builder.Bind(material, name, static (x, material, name) => @@ -72,9 +72,9 @@ public static MotionHandle BindToMaterialInt(this MotionBuil /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToMaterialInt(this MotionBuilder builder, Material material, int nameID) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToMaterialInt(this MotionBuilder builder, Material material, int nameID) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(material); return builder.Bind(material, Box.Create(nameID), static (x, material, nameID) => @@ -91,9 +91,9 @@ public static MotionHandle BindToMaterialInt(this MotionBuil /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToMaterialColor(this MotionBuilder builder, Material material, string name) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToMaterialColor(this MotionBuilder builder, Material material, string name) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(material); return builder.Bind(material, name, static (x, material, name) => @@ -110,9 +110,9 @@ public static MotionHandle BindToMaterialColor(this MotionBu /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToMaterialColor(this MotionBuilder builder, Material material, int nameID) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToMaterialColor(this MotionBuilder builder, Material material, int nameID) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(material); return builder.Bind(material, Box.Create(nameID), static (x, material, nameID) => diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionProgressExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionProgressExtensions.cs index b343158b..f2c1c7b1 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionProgressExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionProgressExtensions.cs @@ -16,10 +16,11 @@ public static class LitMotionProgressExtensions /// This builder /// Target object that implements IProgress /// Handle of the created motion data. - public static MotionHandle BindToProgress(this MotionBuilder builder, IProgress progress) + public static MotionHandle BindToProgress(this MotionBuilder builder, IProgress progress) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(progress); return builder.Bind(progress, static (x, progress) => progress.Report(x)); diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionRigidbody2DExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionRigidbody2DExtensions.cs index cb66cfec..2c18762b 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionRigidbody2DExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionRigidbody2DExtensions.cs @@ -15,9 +15,9 @@ public static class LitMotionRigidbody2DExtensions /// Target component /// Whether to use rigidbody2d.MovePosition() /// Handle of the created motion data. - public static MotionHandle BindToPosition(this MotionBuilder builder, Rigidbody2D rigidbody2d, bool useMovePosition = true) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPosition(this MotionBuilder builder, Rigidbody2D rigidbody2d, bool useMovePosition = true) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rigidbody2d); @@ -46,9 +46,9 @@ public static MotionHandle BindToPosition(this MotionBuilder /// Target component /// Whether to use rigidbody2d.MovePosition() /// Handle of the created motion data. - public static MotionHandle BindToPositionX(this MotionBuilder builder, Rigidbody2D rigidbody2d, bool useMovePosition = true) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPositionX(this MotionBuilder builder, Rigidbody2D rigidbody2d, bool useMovePosition = true) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rigidbody2d); @@ -81,9 +81,9 @@ public static MotionHandle BindToPositionX(this MotionBuilde /// Target component /// Whether to use rigidbody2d.MovePosition() /// Handle of the created motion data. - public static MotionHandle BindToPositionY(this MotionBuilder builder, Rigidbody2D rigidbody2d, bool useMovePosition = true) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPositionY(this MotionBuilder builder, Rigidbody2D rigidbody2d, bool useMovePosition = true) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rigidbody2d); @@ -116,9 +116,9 @@ public static MotionHandle BindToPositionY(this MotionBuilde /// Target component /// Whether to use rigidbody2d.MoveRotation() /// Handle of the created motion data. - public static MotionHandle BindToRotation(this MotionBuilder builder, Rigidbody2D rigidbody2d, bool useMovePosition = true) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToRotation(this MotionBuilder builder, Rigidbody2D rigidbody2d, bool useMovePosition = true) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rigidbody2d); diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionRigidbodyExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionRigidbodyExtensions.cs index 306f5da9..f2a50064 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionRigidbodyExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionRigidbodyExtensions.cs @@ -18,9 +18,9 @@ public static class LitMotionRigidbodyExtensions /// Target component /// Whether to use rigidbody.MovePosition() /// Handle of the created motion data. - public static MotionHandle BindToPosition(this MotionBuilder builder, Rigidbody rigidbody, bool useMovePosition = true) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPosition(this MotionBuilder builder, Rigidbody rigidbody, bool useMovePosition = true) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rigidbody); @@ -49,9 +49,9 @@ public static MotionHandle BindToPosition(this MotionBuilder /// Target component /// Whether to use rigidbody.MovePosition() /// Handle of the created motion data. - public static MotionHandle BindToPositionX(this MotionBuilder builder, Rigidbody rigidbody, bool useMovePosition = true) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPositionX(this MotionBuilder builder, Rigidbody rigidbody, bool useMovePosition = true) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rigidbody); @@ -84,9 +84,9 @@ public static MotionHandle BindToPositionX(this MotionBuilde /// Target component /// Whether to use rigidbody.MovePosition() /// Handle of the created motion data. - public static MotionHandle BindToPositionY(this MotionBuilder builder, Rigidbody rigidbody, bool useMovePosition = true) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPositionY(this MotionBuilder builder, Rigidbody rigidbody, bool useMovePosition = true) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rigidbody); @@ -119,9 +119,9 @@ public static MotionHandle BindToPositionY(this MotionBuilde /// Target component /// Whether to use rigidbody.MovePosition() /// Handle of the created motion data. - public static MotionHandle BindToPositionZ(this MotionBuilder builder, Rigidbody rigidbody, bool useMovePosition = true) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPositionZ(this MotionBuilder builder, Rigidbody rigidbody, bool useMovePosition = true) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rigidbody); @@ -154,9 +154,9 @@ public static MotionHandle BindToPositionZ(this MotionBuilde /// Target component /// Whether to use rigidbody.MovePosition() /// Handle of the created motion data. - public static MotionHandle BindToPositionXY(this MotionBuilder builder, Rigidbody rigidbody, bool useMovePosition = true) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPositionXY(this MotionBuilder builder, Rigidbody rigidbody, bool useMovePosition = true) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rigidbody); @@ -191,9 +191,9 @@ public static MotionHandle BindToPositionXY(this MotionBuild /// Target component /// Whether to use rigidbody.MovePosition() /// Handle of the created motion data. - public static MotionHandle BindToPositionYZ(this MotionBuilder builder, Rigidbody rigidbody, bool useMovePosition = true) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPositionYZ(this MotionBuilder builder, Rigidbody rigidbody, bool useMovePosition = true) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rigidbody); @@ -229,9 +229,9 @@ public static MotionHandle BindToPositionYZ(this MotionBuild /// Target component /// Whether to use rigidbody.MovePosition() /// Handle of the created motion data. - public static MotionHandle BindToPositionXZ(this MotionBuilder builder, Rigidbody rigidbody, bool useMovePosition = true) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPositionXZ(this MotionBuilder builder, Rigidbody rigidbody, bool useMovePosition = true) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rigidbody); @@ -266,9 +266,9 @@ public static MotionHandle BindToPositionXZ(this MotionBuild /// Target component /// Whether to use rigidbody.MoveRotation() /// Handle of the created motion data. - public static MotionHandle BindToRotation(this MotionBuilder builder, Rigidbody rigidbody, bool useMoveRotation = true) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToRotation(this MotionBuilder builder, Rigidbody rigidbody, bool useMoveRotation = true) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rigidbody); diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionSpriteRendererExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionSpriteRendererExtensions.cs index f7d4b4a8..8b2b30a0 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionSpriteRendererExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionSpriteRendererExtensions.cs @@ -15,9 +15,9 @@ public static class LitMotionSpriteRendererExtensions /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToColor(this MotionBuilder builder, SpriteRenderer spriteRenderer) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToColor(this MotionBuilder builder, SpriteRenderer spriteRenderer) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(spriteRenderer); return builder.Bind(spriteRenderer, static (x, m) => @@ -34,9 +34,9 @@ public static MotionHandle BindToColor(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToColorR(this MotionBuilder builder, SpriteRenderer spriteRenderer) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToColorR(this MotionBuilder builder, SpriteRenderer spriteRenderer) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(spriteRenderer); return builder.Bind(spriteRenderer, static (x, m) => @@ -55,9 +55,9 @@ public static MotionHandle BindToColorR(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToColorG(this MotionBuilder builder, SpriteRenderer spriteRenderer) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToColorG(this MotionBuilder builder, SpriteRenderer spriteRenderer) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(spriteRenderer); return builder.Bind(spriteRenderer, static (x, m) => @@ -76,9 +76,9 @@ public static MotionHandle BindToColorG(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToColorB(this MotionBuilder builder, SpriteRenderer spriteRenderer) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToColorB(this MotionBuilder builder, SpriteRenderer spriteRenderer) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(spriteRenderer); return builder.Bind(spriteRenderer, static (x, m) => @@ -97,9 +97,9 @@ public static MotionHandle BindToColorB(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToColorA(this MotionBuilder builder, SpriteRenderer spriteRenderer) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToColorA(this MotionBuilder builder, SpriteRenderer spriteRenderer) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(spriteRenderer); return builder.Bind(spriteRenderer, static (x, m) => diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionTransformExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionTransformExtensions.cs index 7a941a7e..88b9ffca 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionTransformExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/General/LitMotionTransformExtensions.cs @@ -15,9 +15,9 @@ public static class LitMotionTransformExtensions /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToPosition(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPosition(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -34,9 +34,9 @@ public static MotionHandle BindToPosition(this MotionBuilder /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToPositionX(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPositionX(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -55,9 +55,9 @@ public static MotionHandle BindToPositionX(this MotionBuilde /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToPositionY(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPositionY(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -76,9 +76,9 @@ public static MotionHandle BindToPositionY(this MotionBuilde /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToPositionZ(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPositionZ(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -97,9 +97,9 @@ public static MotionHandle BindToPositionZ(this MotionBuilde /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToPositionXY(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPositionXY(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -119,9 +119,9 @@ public static MotionHandle BindToPositionXY(this MotionBuild /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToPositionXZ(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPositionXZ(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -141,9 +141,9 @@ public static MotionHandle BindToPositionXZ(this MotionBuild /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToPositionYZ(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPositionYZ(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -163,9 +163,9 @@ public static MotionHandle BindToPositionYZ(this MotionBuild /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalPosition(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalPosition(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -182,9 +182,9 @@ public static MotionHandle BindToLocalPosition(this MotionBu /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalPositionX(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalPositionX(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -204,9 +204,9 @@ public static MotionHandle BindToLocalPositionX(this MotionB /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalPositionY(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalPositionY(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -225,9 +225,9 @@ public static MotionHandle BindToLocalPositionY(this MotionB /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalPositionZ(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalPositionZ(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -246,9 +246,9 @@ public static MotionHandle BindToLocalPositionZ(this MotionB /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalPositionXY(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalPositionXY(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -268,9 +268,9 @@ public static MotionHandle BindToLocalPositionXY(this Motion /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalPositionXZ(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalPositionXZ(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -290,9 +290,9 @@ public static MotionHandle BindToLocalPositionXZ(this Motion /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalPositionYZ(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalPositionYZ(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -312,9 +312,9 @@ public static MotionHandle BindToLocalPositionYZ(this Motion /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToRotation(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToRotation(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -331,9 +331,9 @@ public static MotionHandle BindToRotation(this MotionBuilder /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalRotation(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalRotation(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -350,9 +350,9 @@ public static MotionHandle BindToLocalRotation(this MotionBu /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToEulerAngles(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToEulerAngles(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -369,9 +369,9 @@ public static MotionHandle BindToEulerAngles(this MotionBuil /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToEulerAnglesX(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToEulerAnglesX(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -390,9 +390,9 @@ public static MotionHandle BindToEulerAnglesX(this MotionBui /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToEulerAnglesY(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToEulerAnglesY(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -411,9 +411,9 @@ public static MotionHandle BindToEulerAnglesY(this MotionBui /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToEulerAnglesZ(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToEulerAnglesZ(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -432,9 +432,9 @@ public static MotionHandle BindToEulerAnglesZ(this MotionBui /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToEulerAnglesXY(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToEulerAnglesXY(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -454,9 +454,9 @@ public static MotionHandle BindToEulerAnglesXY(this MotionBu /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToEulerAnglesXZ(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToEulerAnglesXZ(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -476,9 +476,9 @@ public static MotionHandle BindToEulerAnglesXZ(this MotionBu /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToEulerAnglesYZ(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToEulerAnglesYZ(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -498,9 +498,9 @@ public static MotionHandle BindToEulerAnglesYZ(this MotionBu /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalEulerAngles(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalEulerAngles(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -517,9 +517,9 @@ public static MotionHandle BindToLocalEulerAngles(this Motio /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalEulerAnglesX(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalEulerAnglesX(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -538,9 +538,9 @@ public static MotionHandle BindToLocalEulerAnglesX(this Moti /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalEulerAnglesY(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalEulerAnglesY(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -559,9 +559,9 @@ public static MotionHandle BindToLocalEulerAnglesY(this Moti /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalEulerAnglesZ(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalEulerAnglesZ(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -580,9 +580,9 @@ public static MotionHandle BindToLocalEulerAnglesZ(this Moti /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalEulerAnglesXY(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalEulerAnglesXY(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -602,9 +602,9 @@ public static MotionHandle BindToLocalEulerAnglesXY(this Mot /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalEulerAnglesXZ(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalEulerAnglesXZ(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -624,9 +624,9 @@ public static MotionHandle BindToLocalEulerAnglesXZ(this Mot /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalEulerAnglesYZ(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalEulerAnglesYZ(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -646,9 +646,9 @@ public static MotionHandle BindToLocalEulerAnglesYZ(this Mot /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalScale(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalScale(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -665,9 +665,9 @@ public static MotionHandle BindToLocalScale(this MotionBuild /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalScaleX(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalScaleX(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -686,9 +686,9 @@ public static MotionHandle BindToLocalScaleX(this MotionBuil /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalScaleY(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalScaleY(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -707,9 +707,9 @@ public static MotionHandle BindToLocalScaleY(this MotionBuil /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalScaleZ(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalScaleZ(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -728,9 +728,9 @@ public static MotionHandle BindToLocalScaleZ(this MotionBuil /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalScaleXY(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalScaleXY(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -750,9 +750,9 @@ public static MotionHandle BindToLocalScaleXY(this MotionBui /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalScaleXZ(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalScaleXZ(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => @@ -772,9 +772,9 @@ public static MotionHandle BindToLocalScaleXZ(this MotionBui /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToLocalScaleYZ(this MotionBuilder builder, Transform transform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToLocalScaleYZ(this MotionBuilder builder, Transform transform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(transform); return builder.Bind(transform, static (x, t) => diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/Rendering/LitMotionVolumeExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/Rendering/LitMotionVolumeExtensions.cs index 84961ea5..ed879aa4 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/Rendering/LitMotionVolumeExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/Rendering/LitMotionVolumeExtensions.cs @@ -1,30 +1,30 @@ -#if LITMOTION_SUPPORT_RENDER_PIPELINES +// #if LITMOTION_SUPPORT_RENDER_PIPELINES -using UnityEngine.Rendering; +// using UnityEngine.Rendering; -namespace LitMotion.Extensions -{ - /// - /// Provides binding extension methods for Volume. - /// - public static class LitMotionVolumeExtensions - { - /// - /// Create a motion data and bind it to Volume.weight - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target component - /// Handle of the created motion data. - public static MotionHandle BindToWeight(this MotionBuilder builder, Volume volume) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(volume); - return builder.Bind(volume, static (x, volume) => volume.weight = x); - } - } -} +// namespace LitMotion.Extensions +// { +// /// +// /// Provides binding extension methods for Volume. +// /// +// public static class LitMotionVolumeExtensions +// { +// /// +// /// Create a motion data and bind it to Volume.weight +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target component +// /// Handle of the created motion data. +// public static MotionHandle BindToWeight(this MotionBuilder builder, Volume volume) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(volume); +// return builder.Bind(volume, static (x, volume) => volume.weight = x); +// } +// } +// } -#endif \ No newline at end of file +// #endif \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/TextMeshPro/LitMotionTextMeshProExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/TextMeshPro/LitMotionTextMeshProExtensions.cs index 41048b1b..57f0a235 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/TextMeshPro/LitMotionTextMeshProExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/TextMeshPro/LitMotionTextMeshProExtensions.cs @@ -1,1048 +1,1048 @@ -#if LITMOTION_SUPPORT_TMP -using System.Buffers; -using UnityEngine; -using Unity.Collections; -using TMPro; - -#if LITMOTION_SUPPORT_ZSTRING -using Cysharp.Text; -#endif - -namespace LitMotion.Extensions -{ - /// - /// Provides binding extension methods for TMP_Text - /// - public static class LitMotionTextMeshProExtensions - { - /// - /// Create a motion data and bind it to TMP_Text.fontSize - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public static MotionHandle BindToFontSize(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - target.fontSize = x; - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.maxVisibleCharacters - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public static MotionHandle BindToMaxVisibleCharacters(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - target.maxVisibleCharacters = x; - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.maxVisibleLines - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public static MotionHandle BindToMaxVisibleLines(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - target.maxVisibleLines = x; - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.characterSpacing - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public static MotionHandle BindToCharacterSpacing(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - target.characterSpacing = x; - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.wordSpacing - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public static MotionHandle BindToWordSpacing(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - target.wordSpacing = x; - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.paragraphSpacing - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public static MotionHandle BindToParagraphSpacing(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - target.paragraphSpacing = x; - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.lineSpacing - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public static MotionHandle BindToLineSpacing(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - target.lineSpacing = x; - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.maxVisibleWords - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public static MotionHandle BindToMaxVisibleWords(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - target.maxVisibleWords = x; - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.color - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public static MotionHandle BindToColor(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - target.color = x; - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.color.r - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public static MotionHandle BindToColorR(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - var c = target.color; - c.r = x; - target.color = c; - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.color.g - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public static MotionHandle BindToColorG(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - var c = target.color; - c.g = x; - target.color = c; - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.color.b - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public static MotionHandle BindToColorB(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - var c = target.color; - c.b = x; - target.color = c; - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.color.a - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public static MotionHandle BindToColorA(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - var c = target.color; - c.a = x; - target.color = c; - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.text. - /// - /// - /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - var enumerator = x.GetEnumerator(); - var length = 0; - var buffer = ArrayPool.Shared.Rent(64); - fixed (char* c = buffer) - { - Unicode.Utf8ToUtf16(x.GetUnsafePtr(), x.Length, c, out length, x.Length * 2); - } - target.SetText(buffer, 0, length); - ArrayPool.Shared.Return(buffer); - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.text. - /// - /// - /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - var enumerator = x.GetEnumerator(); - var length = 0; - var buffer = ArrayPool.Shared.Rent(128); - fixed (char* c = buffer) - { - Unicode.Utf8ToUtf16(x.GetUnsafePtr(), x.Length, c, out length, x.Length * 2); - } - target.SetText(buffer, 0, length); - ArrayPool.Shared.Return(buffer); - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.text. - /// - /// - /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - var enumerator = x.GetEnumerator(); - var length = 0; - var buffer = ArrayPool.Shared.Rent(256); - fixed (char* c = buffer) - { - Unicode.Utf8ToUtf16(x.GetUnsafePtr(), x.Length, c, out length, x.Length * 2); - } - target.SetText(buffer, 0, length); - ArrayPool.Shared.Return(buffer); - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.text. - /// - /// - /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - var enumerator = x.GetEnumerator(); - var length = 0; - var buffer = ArrayPool.Shared.Rent(1024); - fixed (char* c = buffer) - { - Unicode.Utf8ToUtf16(x.GetUnsafePtr(), x.Length, c, out length, x.Length * 2); - } - target.SetText(buffer, 0, length); - ArrayPool.Shared.Return(buffer); - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.text. - /// - /// - /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Handle of the created motion data. - public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - var enumerator = x.GetEnumerator(); - var length = 0; - var buffer = ArrayPool.Shared.Rent(8192); - fixed (char* c = buffer) - { - Unicode.Utf8ToUtf16(x.GetUnsafePtr(), x.Length, c, out length, x.Length * 2); - } - target.SetText(buffer, 0, length); - ArrayPool.Shared.Return(buffer); - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.text. - /// - /// - /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Handle of the created motion data. - public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - - var buffer = ArrayPool.Shared.Rent(128); - var bufferOffset = 0; - Utf16StringHelper.WriteInt32(ref buffer, ref bufferOffset, x); - target.SetText(buffer, 0, bufferOffset); - ArrayPool.Shared.Return(buffer); - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.text. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Format string - /// Handle of the created motion data. - public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text, string format) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, format, static (x, text, format) => - { -#if LITMOTION_SUPPORT_ZSTRING - text.SetTextFormat(format, x); -#else - text.text = string.Format(format, x); -#endif - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.text. - /// - /// - /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Handle of the created motion data. - public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { - - var buffer = ArrayPool.Shared.Rent(128); - var bufferOffset = 0; - Utf16StringHelper.WriteInt64(ref buffer, ref bufferOffset, x); - target.SetText(buffer, 0, bufferOffset); - ArrayPool.Shared.Return(buffer); - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.text. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Format string - /// Handle of the created motion data. - public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text, string format) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, format, static (x, text, format) => - { -#if LITMOTION_SUPPORT_ZSTRING - text.SetTextFormat(format, x); -#else - text.text = string.Format(format, x); -#endif - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.text. - /// - /// - /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Handle of the created motion data. - public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - const string format = "{0}"; - Error.IsNull(text); - return builder.Bind(text, static (x, target) => - { -#if LITMOTION_SUPPORT_ZSTRING - target.SetTextFormat(format, x); -#else - target.SetText(format, x); -#endif - }); - } - - /// - /// Create a motion data and bind it to TMP_Text.text. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Format string - /// Handle of the created motion data. - public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text, string format) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - return builder.Bind(text, format, static (x, text, format) => - { -#if LITMOTION_SUPPORT_ZSTRING - text.SetTextFormat(format, x); -#else - text.text = string.Format(format, x); -#endif - }); - } - - /// - /// Create motion data and bind it to the character color. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharColor(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - animator.charInfoArray[charIndex.Value].color = x; - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character color.r. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharColorR(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - animator.charInfoArray[charIndex.Value].color.r = x; - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character color.g. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharColorG(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - animator.charInfoArray[charIndex.Value].color.g = x; - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character color.b. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharColorB(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - animator.charInfoArray[charIndex.Value].color.b = x; - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character color.a. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharColorA(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - animator.charInfoArray[charIndex.Value].color.a = x; - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character position. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharPosition(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - animator.charInfoArray[charIndex.Value].position = x; - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character position.x. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharPositionX(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - animator.charInfoArray[charIndex.Value].position.x = x; - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character position.y. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharPositionY(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - animator.charInfoArray[charIndex.Value].position.y = x; - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character position.z. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharPositionZ(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - animator.charInfoArray[charIndex.Value].position.z = x; - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character rotation. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharRotation(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - animator.charInfoArray[charIndex.Value].rotation = x; - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character rotation (using euler angles). - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharEulerAngles(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - animator.charInfoArray[charIndex.Value].rotation = Quaternion.Euler(x); - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character rotation (using euler angles). - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharEulerAnglesX(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - var eulerAngles = animator.charInfoArray[charIndex.Value].rotation.eulerAngles; - eulerAngles.x = x; - animator.charInfoArray[charIndex.Value].rotation = Quaternion.Euler(eulerAngles); - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character rotation (using euler angles). - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharEulerAnglesY(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - var eulerAngles = animator.charInfoArray[charIndex.Value].rotation.eulerAngles; - eulerAngles.y = x; - animator.charInfoArray[charIndex.Value].rotation = Quaternion.Euler(eulerAngles); - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character rotation (using euler angles). - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharEulerAnglesZ(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - var eulerAngles = animator.charInfoArray[charIndex.Value].rotation.eulerAngles; - eulerAngles.z = x; - animator.charInfoArray[charIndex.Value].rotation = Quaternion.Euler(eulerAngles); - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character scale. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharScale(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - animator.charInfoArray[charIndex.Value].scale = x; - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character scale.x. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharScaleX(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - animator.charInfoArray[charIndex.Value].scale.x = x; - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character scale.y. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharScaleY(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - animator.charInfoArray[charIndex.Value].scale.y = x; - animator.SetDirty(); - }); - - return handle; - } - - /// - /// Create motion data and bind it to the character scale.z. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// Target TMP_Text - /// Target character index - /// Handle of the created motion data. - public static MotionHandle BindToTMPCharScaleZ(this MotionBuilder builder, TMP_Text text, int charIndex) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(text); - - var animator = TextMeshProMotionAnimator.Get(text); - animator.EnsureCapacity(charIndex + 1); - var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => - { - animator.charInfoArray[charIndex.Value].scale.z = x; - animator.SetDirty(); - }); - - return handle; - } - } -} -#endif +// #if LITMOTION_SUPPORT_TMP +// using System.Buffers; +// using UnityEngine; +// using Unity.Collections; +// using TMPro; + +// #if LITMOTION_SUPPORT_ZSTRING +// using Cysharp.Text; +// #endif + +// namespace LitMotion.Extensions +// { +// /// +// /// Provides binding extension methods for TMP_Text +// /// +// public static class LitMotionTextMeshProExtensions +// { +// /// +// /// Create a motion data and bind it to TMP_Text.fontSize +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public static MotionHandle BindToFontSize(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// target.fontSize = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.maxVisibleCharacters +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public static MotionHandle BindToMaxVisibleCharacters(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// target.maxVisibleCharacters = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.maxVisibleLines +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public static MotionHandle BindToMaxVisibleLines(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// target.maxVisibleLines = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.characterSpacing +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public static MotionHandle BindToCharacterSpacing(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// target.characterSpacing = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.wordSpacing +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public static MotionHandle BindToWordSpacing(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// target.wordSpacing = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.paragraphSpacing +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public static MotionHandle BindToParagraphSpacing(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// target.paragraphSpacing = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.lineSpacing +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public static MotionHandle BindToLineSpacing(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// target.lineSpacing = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.maxVisibleWords +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public static MotionHandle BindToMaxVisibleWords(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// target.maxVisibleWords = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.color +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public static MotionHandle BindToColor(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// target.color = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.color.r +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public static MotionHandle BindToColorR(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// var c = target.color; +// c.r = x; +// target.color = c; +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.color.g +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public static MotionHandle BindToColorG(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// var c = target.color; +// c.g = x; +// target.color = c; +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.color.b +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public static MotionHandle BindToColorB(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// var c = target.color; +// c.b = x; +// target.color = c; +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.color.a +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public static MotionHandle BindToColorA(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// var c = target.color; +// c.a = x; +// target.color = c; +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.text. +// /// +// /// +// /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// var enumerator = x.GetEnumerator(); +// var length = 0; +// var buffer = ArrayPool.Shared.Rent(64); +// fixed (char* c = buffer) +// { +// Unicode.Utf8ToUtf16(x.GetUnsafePtr(), x.Length, c, out length, x.Length * 2); +// } +// target.SetText(buffer, 0, length); +// ArrayPool.Shared.Return(buffer); +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.text. +// /// +// /// +// /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// var enumerator = x.GetEnumerator(); +// var length = 0; +// var buffer = ArrayPool.Shared.Rent(128); +// fixed (char* c = buffer) +// { +// Unicode.Utf8ToUtf16(x.GetUnsafePtr(), x.Length, c, out length, x.Length * 2); +// } +// target.SetText(buffer, 0, length); +// ArrayPool.Shared.Return(buffer); +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.text. +// /// +// /// +// /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// var enumerator = x.GetEnumerator(); +// var length = 0; +// var buffer = ArrayPool.Shared.Rent(256); +// fixed (char* c = buffer) +// { +// Unicode.Utf8ToUtf16(x.GetUnsafePtr(), x.Length, c, out length, x.Length * 2); +// } +// target.SetText(buffer, 0, length); +// ArrayPool.Shared.Return(buffer); +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.text. +// /// +// /// +// /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// var enumerator = x.GetEnumerator(); +// var length = 0; +// var buffer = ArrayPool.Shared.Rent(1024); +// fixed (char* c = buffer) +// { +// Unicode.Utf8ToUtf16(x.GetUnsafePtr(), x.Length, c, out length, x.Length * 2); +// } +// target.SetText(buffer, 0, length); +// ArrayPool.Shared.Return(buffer); +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.text. +// /// +// /// +// /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Handle of the created motion data. +// public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// var enumerator = x.GetEnumerator(); +// var length = 0; +// var buffer = ArrayPool.Shared.Rent(8192); +// fixed (char* c = buffer) +// { +// Unicode.Utf8ToUtf16(x.GetUnsafePtr(), x.Length, c, out length, x.Length * 2); +// } +// target.SetText(buffer, 0, length); +// ArrayPool.Shared.Return(buffer); +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.text. +// /// +// /// +// /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Handle of the created motion data. +// public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { + +// var buffer = ArrayPool.Shared.Rent(128); +// var bufferOffset = 0; +// Utf16StringHelper.WriteInt32(ref buffer, ref bufferOffset, x); +// target.SetText(buffer, 0, bufferOffset); +// ArrayPool.Shared.Return(buffer); +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.text. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Format string +// /// Handle of the created motion data. +// public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text, string format) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, format, static (x, text, format) => +// { +// #if LITMOTION_SUPPORT_ZSTRING +// text.SetTextFormat(format, x); +// #else +// text.text = string.Format(format, x); +// #endif +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.text. +// /// +// /// +// /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Handle of the created motion data. +// public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { + +// var buffer = ArrayPool.Shared.Rent(128); +// var bufferOffset = 0; +// Utf16StringHelper.WriteInt64(ref buffer, ref bufferOffset, x); +// target.SetText(buffer, 0, bufferOffset); +// ArrayPool.Shared.Return(buffer); +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.text. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Format string +// /// Handle of the created motion data. +// public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text, string format) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, format, static (x, text, format) => +// { +// #if LITMOTION_SUPPORT_ZSTRING +// text.SetTextFormat(format, x); +// #else +// text.text = string.Format(format, x); +// #endif +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.text. +// /// +// /// +// /// Note: This extension method uses TMP_Text.SetText() to achieve zero allocation, so it is recommended to use this method when binding to text. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Handle of the created motion data. +// public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// const string format = "{0}"; +// Error.IsNull(text); +// return builder.Bind(text, static (x, target) => +// { +// #if LITMOTION_SUPPORT_ZSTRING +// target.SetTextFormat(format, x); +// #else +// target.SetText(format, x); +// #endif +// }); +// } + +// /// +// /// Create a motion data and bind it to TMP_Text.text. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Format string +// /// Handle of the created motion data. +// public unsafe static MotionHandle BindToText(this MotionBuilder builder, TMP_Text text, string format) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); +// return builder.Bind(text, format, static (x, text, format) => +// { +// #if LITMOTION_SUPPORT_ZSTRING +// text.SetTextFormat(format, x); +// #else +// text.text = string.Format(format, x); +// #endif +// }); +// } + +// /// +// /// Create motion data and bind it to the character color. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharColor(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// animator.charInfoArray[charIndex.Value].color = x; +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character color.r. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharColorR(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// animator.charInfoArray[charIndex.Value].color.r = x; +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character color.g. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharColorG(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// animator.charInfoArray[charIndex.Value].color.g = x; +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character color.b. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharColorB(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// animator.charInfoArray[charIndex.Value].color.b = x; +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character color.a. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharColorA(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// animator.charInfoArray[charIndex.Value].color.a = x; +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character position. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharPosition(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// animator.charInfoArray[charIndex.Value].position = x; +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character position.x. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharPositionX(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// animator.charInfoArray[charIndex.Value].position.x = x; +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character position.y. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharPositionY(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// animator.charInfoArray[charIndex.Value].position.y = x; +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character position.z. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharPositionZ(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// animator.charInfoArray[charIndex.Value].position.z = x; +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character rotation. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharRotation(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// animator.charInfoArray[charIndex.Value].rotation = x; +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character rotation (using euler angles). +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharEulerAngles(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// animator.charInfoArray[charIndex.Value].rotation = Quaternion.Euler(x); +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character rotation (using euler angles). +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharEulerAnglesX(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// var eulerAngles = animator.charInfoArray[charIndex.Value].rotation.eulerAngles; +// eulerAngles.x = x; +// animator.charInfoArray[charIndex.Value].rotation = Quaternion.Euler(eulerAngles); +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character rotation (using euler angles). +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharEulerAnglesY(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// var eulerAngles = animator.charInfoArray[charIndex.Value].rotation.eulerAngles; +// eulerAngles.y = x; +// animator.charInfoArray[charIndex.Value].rotation = Quaternion.Euler(eulerAngles); +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character rotation (using euler angles). +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharEulerAnglesZ(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// var eulerAngles = animator.charInfoArray[charIndex.Value].rotation.eulerAngles; +// eulerAngles.z = x; +// animator.charInfoArray[charIndex.Value].rotation = Quaternion.Euler(eulerAngles); +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character scale. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharScale(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// animator.charInfoArray[charIndex.Value].scale = x; +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character scale.x. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharScaleX(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// animator.charInfoArray[charIndex.Value].scale.x = x; +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character scale.y. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharScaleY(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// animator.charInfoArray[charIndex.Value].scale.y = x; +// animator.SetDirty(); +// }); + +// return handle; +// } + +// /// +// /// Create motion data and bind it to the character scale.z. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// Target TMP_Text +// /// Target character index +// /// Handle of the created motion data. +// public static MotionHandle BindToTMPCharScaleZ(this MotionBuilder builder, TMP_Text text, int charIndex) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(text); + +// var animator = TextMeshProMotionAnimator.Get(text); +// animator.EnsureCapacity(charIndex + 1); +// var handle = builder.WithOnComplete(animator.updateAction).Bind(animator, Box.Create(charIndex), static (x, animator, charIndex) => +// { +// animator.charInfoArray[charIndex.Value].scale.z = x; +// animator.SetDirty(); +// }); + +// return handle; +// } +// } +// } +// #endif diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/TextMeshPro/TextMeshProMotionAnimator.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/TextMeshPro/TextMeshProMotionAnimator.cs index 61e7cb0a..d294f6d5 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/TextMeshPro/TextMeshProMotionAnimator.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/TextMeshPro/TextMeshProMotionAnimator.cs @@ -1,294 +1,294 @@ -#if LITMOTION_SUPPORT_TMP -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using UnityEngine; -using TMPro; -using LitMotion.Collections; - -#if UNITY_EDITOR -using UnityEditor; -#endif - -namespace LitMotion.Extensions -{ - // TODO: optimization - - /// - /// Wrapper class for animating individual characters in TextMeshPro. - /// - internal sealed class TextMeshProMotionAnimator - { - [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] - static void Init() - { -#if UNITY_EDITOR - var domainReloadDisabled = EditorSettings.enterPlayModeOptionsEnabled && EditorSettings.enterPlayModeOptions.HasFlag(EnterPlayModeOptions.DisableDomainReload); - if (!domainReloadDisabled && initialized) return; -#else - if (initialized) return; -#endif - PlayerLoopHelper.OnUpdate += UpdateAnimators; - initialized = true; - } - -#if UNITY_EDITOR - [InitializeOnLoadMethod] - static void InitEditor() - { - EditorApplication.update += UpdateAnimatorsEditor; - } -#endif - - static bool initialized; - static TextMeshProMotionAnimator rootNode; - - internal static TextMeshProMotionAnimator Get(TMP_Text text) - { - if (textToAnimator.TryGetValue(text, out var animator)) - { - animator.Reset(); - return animator; - } - - // get or create animator - animator = rootNode ?? new(); - rootNode = animator.nextNode; - animator.nextNode = null; - - // set target - animator.target = text; - animator.Reset(); - - // add to array - if (tail == animators.Length) - { - Array.Resize(ref animators, tail * 2); - } - animators[tail] = animator; - tail++; - - // add to dictionary - textToAnimator.Add(text, animator); - - return animator; - } - - internal static void Return(TextMeshProMotionAnimator animator) - { - animator.nextNode = rootNode; - rootNode = animator; - - textToAnimator.Remove(animator.target); - animator.target = null; - } - - static readonly Dictionary textToAnimator = new(); - static TextMeshProMotionAnimator[] animators = new TextMeshProMotionAnimator[8]; - static int tail; - - static void UpdateAnimators() - { - var j = tail - 1; - - for (int i = 0; i < animators.Length; i++) - { - var animator = animators[i]; - if (animator != null) - { - if (!animator.TryUpdate()) - { - Return(animator); - animators[i] = null; - } - else - { - continue; - } - } - - while (i < j) - { - var fromTail = animators[j]; - if (fromTail != null) - { - if (!fromTail.TryUpdate()) - { - Return(fromTail); - animators[j] = null; - j--; - continue; - } - else - { - animators[i] = fromTail; - animators[j] = null; - j--; - goto NEXT_LOOP; - } - } - else - { - j--; - } - } - - tail = i; - break; - - NEXT_LOOP: - continue; - } - } - -#if UNITY_EDITOR - static void UpdateAnimatorsEditor() - { - if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling || EditorApplication.isUpdating) - { - return; - } - UpdateAnimators(); - } -#endif - - internal struct CharInfo - { - public Vector3 position; - public Vector3 scale; - public Quaternion rotation; - public Color color; - } - - public TextMeshProMotionAnimator() - { - charInfoArray = new CharInfo[32]; - for (int i = 0; i < charInfoArray.Length; i++) - { - charInfoArray[i].color = Color.white; - charInfoArray[i].rotation = Quaternion.identity; - charInfoArray[i].scale = Vector3.one; - charInfoArray[i].position = Vector3.zero; - } - - updateAction = UpdateCore; - } - - TMP_Text target; - internal readonly Action updateAction; - internal CharInfo[] charInfoArray; - bool isDirty; - - TextMeshProMotionAnimator nextNode; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void EnsureCapacity(int length) - { - var prevLength = charInfoArray.Length; - if (length > prevLength) - { - Array.Resize(ref charInfoArray, length); - - if (length > prevLength) - { - for (int i = prevLength; i < length; i++) - { - charInfoArray[i].color = new(target.color.r, target.color.g, target.color.b, target.color.a); - charInfoArray[i].rotation = Quaternion.identity; - charInfoArray[i].scale = Vector3.one; - charInfoArray[i].position = Vector3.zero; - } - } - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Update() - { - TryUpdate(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SetDirty() - { - isDirty = true; - } - - public void Reset() - { - for (int i = 0; i < charInfoArray.Length; i++) - { - charInfoArray[i].color = new(target.color.r, target.color.g, target.color.b, target.color.a); - charInfoArray[i].rotation = Quaternion.identity; - charInfoArray[i].scale = Vector3.one; - charInfoArray[i].position = Vector3.zero; - } - - isDirty = false; - } - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - bool TryUpdate() - { - if (target == null) return false; - - if (isDirty) - { - UpdateCore(); - } - - return true; - } - - void UpdateCore() - { - target.ForceMeshUpdate(); - - var textInfo = target.textInfo; - EnsureCapacity(textInfo.characterCount); - - for (int i = 0; i < textInfo.characterCount; i++) - { - ref var charInfo = ref textInfo.characterInfo[i]; - if (!charInfo.isVisible) continue; - - var materialIndex = charInfo.materialReferenceIndex; - var vertexIndex = charInfo.vertexIndex; - - ref var colors = ref textInfo.meshInfo[materialIndex].colors32; - ref var motionCharInfo = ref charInfoArray[i]; - - var charColor = motionCharInfo.color; - for (int n = 0; n < 4; n++) - { - colors[vertexIndex + n] = charColor; - } - - var verts = textInfo.meshInfo[materialIndex].vertices; - var center = (verts[vertexIndex] + verts[vertexIndex + 2]) * 0.5f; - - var charRotation = motionCharInfo.rotation; - var charScale = motionCharInfo.scale; - var charOffset = motionCharInfo.position; - for (int n = 0; n < 4; n++) - { - var vert = verts[vertexIndex + n]; - var dir = vert - center; - verts[vertexIndex + n] = center + - charRotation * new Vector3(dir.x * charScale.x, dir.y * charScale.y, dir.z * charScale.z) + - charOffset; - } - } - - for (int i = 0; i < textInfo.materialCount; i++) - { - if (textInfo.meshInfo[i].mesh == null) continue; - textInfo.meshInfo[i].mesh.colors32 = textInfo.meshInfo[i].colors32; - textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices; - target.UpdateGeometry(textInfo.meshInfo[i].mesh, i); - } - } - } -} -#endif \ No newline at end of file +// #if LITMOTION_SUPPORT_TMP +// using System; +// using System.Collections.Generic; +// using System.Runtime.CompilerServices; +// using UnityEngine; +// using TMPro; +// using LitMotion.Collections; + +// #if UNITY_EDITOR +// using UnityEditor; +// #endif + +// namespace LitMotion.Extensions +// { +// // TODO: optimization + +// /// +// /// Wrapper class for animating individual characters in TextMeshPro. +// /// +// internal sealed class TextMeshProMotionAnimator +// { +// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] +// static void Init() +// { +// #if UNITY_EDITOR +// var domainReloadDisabled = EditorSettings.enterPlayModeOptionsEnabled && EditorSettings.enterPlayModeOptions.HasFlag(EnterPlayModeOptions.DisableDomainReload); +// if (!domainReloadDisabled && initialized) return; +// #else +// if (initialized) return; +// #endif +// PlayerLoopHelper.OnUpdate += UpdateAnimators; +// initialized = true; +// } + +// #if UNITY_EDITOR +// [InitializeOnLoadMethod] +// static void InitEditor() +// { +// EditorApplication.update += UpdateAnimatorsEditor; +// } +// #endif + +// static bool initialized; +// static TextMeshProMotionAnimator rootNode; + +// internal static TextMeshProMotionAnimator Get(TMP_Text text) +// { +// if (textToAnimator.TryGetValue(text, out var animator)) +// { +// animator.Reset(); +// return animator; +// } + +// // get or create animator +// animator = rootNode ?? new(); +// rootNode = animator.nextNode; +// animator.nextNode = null; + +// // set target +// animator.target = text; +// animator.Reset(); + +// // add to array +// if (tail == animators.Length) +// { +// Array.Resize(ref animators, tail * 2); +// } +// animators[tail] = animator; +// tail++; + +// // add to dictionary +// textToAnimator.Add(text, animator); + +// return animator; +// } + +// internal static void Return(TextMeshProMotionAnimator animator) +// { +// animator.nextNode = rootNode; +// rootNode = animator; + +// textToAnimator.Remove(animator.target); +// animator.target = null; +// } + +// static readonly Dictionary textToAnimator = new(); +// static TextMeshProMotionAnimator[] animators = new TextMeshProMotionAnimator[8]; +// static int tail; + +// static void UpdateAnimators() +// { +// var j = tail - 1; + +// for (int i = 0; i < animators.Length; i++) +// { +// var animator = animators[i]; +// if (animator != null) +// { +// if (!animator.TryUpdate()) +// { +// Return(animator); +// animators[i] = null; +// } +// else +// { +// continue; +// } +// } + +// while (i < j) +// { +// var fromTail = animators[j]; +// if (fromTail != null) +// { +// if (!fromTail.TryUpdate()) +// { +// Return(fromTail); +// animators[j] = null; +// j--; +// continue; +// } +// else +// { +// animators[i] = fromTail; +// animators[j] = null; +// j--; +// goto NEXT_LOOP; +// } +// } +// else +// { +// j--; +// } +// } + +// tail = i; +// break; + +// NEXT_LOOP: +// continue; +// } +// } + +// #if UNITY_EDITOR +// static void UpdateAnimatorsEditor() +// { +// if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling || EditorApplication.isUpdating) +// { +// return; +// } +// UpdateAnimators(); +// } +// #endif + +// internal struct CharInfo +// { +// public Vector3 position; +// public Vector3 scale; +// public Quaternion rotation; +// public Color color; +// } + +// public TextMeshProMotionAnimator() +// { +// charInfoArray = new CharInfo[32]; +// for (int i = 0; i < charInfoArray.Length; i++) +// { +// charInfoArray[i].color = Color.white; +// charInfoArray[i].rotation = Quaternion.identity; +// charInfoArray[i].scale = Vector3.one; +// charInfoArray[i].position = Vector3.zero; +// } + +// updateAction = UpdateCore; +// } + +// TMP_Text target; +// internal readonly Action updateAction; +// internal CharInfo[] charInfoArray; +// bool isDirty; + +// TextMeshProMotionAnimator nextNode; + +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// public void EnsureCapacity(int length) +// { +// var prevLength = charInfoArray.Length; +// if (length > prevLength) +// { +// Array.Resize(ref charInfoArray, length); + +// if (length > prevLength) +// { +// for (int i = prevLength; i < length; i++) +// { +// charInfoArray[i].color = new(target.color.r, target.color.g, target.color.b, target.color.a); +// charInfoArray[i].rotation = Quaternion.identity; +// charInfoArray[i].scale = Vector3.one; +// charInfoArray[i].position = Vector3.zero; +// } +// } +// } +// } + +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// public void Update() +// { +// TryUpdate(); +// } + +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// public void SetDirty() +// { +// isDirty = true; +// } + +// public void Reset() +// { +// for (int i = 0; i < charInfoArray.Length; i++) +// { +// charInfoArray[i].color = new(target.color.r, target.color.g, target.color.b, target.color.a); +// charInfoArray[i].rotation = Quaternion.identity; +// charInfoArray[i].scale = Vector3.one; +// charInfoArray[i].position = Vector3.zero; +// } + +// isDirty = false; +// } + + +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// bool TryUpdate() +// { +// if (target == null) return false; + +// if (isDirty) +// { +// UpdateCore(); +// } + +// return true; +// } + +// void UpdateCore() +// { +// target.ForceMeshUpdate(); + +// var textInfo = target.textInfo; +// EnsureCapacity(textInfo.characterCount); + +// for (int i = 0; i < textInfo.characterCount; i++) +// { +// ref var charInfo = ref textInfo.characterInfo[i]; +// if (!charInfo.isVisible) continue; + +// var materialIndex = charInfo.materialReferenceIndex; +// var vertexIndex = charInfo.vertexIndex; + +// ref var colors = ref textInfo.meshInfo[materialIndex].colors32; +// ref var motionCharInfo = ref charInfoArray[i]; + +// var charColor = motionCharInfo.color; +// for (int n = 0; n < 4; n++) +// { +// colors[vertexIndex + n] = charColor; +// } + +// var verts = textInfo.meshInfo[materialIndex].vertices; +// var center = (verts[vertexIndex] + verts[vertexIndex + 2]) * 0.5f; + +// var charRotation = motionCharInfo.rotation; +// var charScale = motionCharInfo.scale; +// var charOffset = motionCharInfo.position; +// for (int n = 0; n < 4; n++) +// { +// var vert = verts[vertexIndex + n]; +// var dir = vert - center; +// verts[vertexIndex + n] = center + +// charRotation * new Vector3(dir.x * charScale.x, dir.y * charScale.y, dir.z * charScale.z) + +// charOffset; +// } +// } + +// for (int i = 0; i < textInfo.materialCount; i++) +// { +// if (textInfo.meshInfo[i].mesh == null) continue; +// textInfo.meshInfo[i].mesh.colors32 = textInfo.meshInfo[i].colors32; +// textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices; +// target.UpdateGeometry(textInfo.meshInfo[i].mesh, i); +// } +// } +// } +// } +// #endif \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/UIToolkit/LitMotionUIToolkitExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/UIToolkit/LitMotionUIToolkitExtensions.cs index 10f4cfd6..9ab5e3d9 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/UIToolkit/LitMotionUIToolkitExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/UIToolkit/LitMotionUIToolkitExtensions.cs @@ -1,762 +1,762 @@ -#if LITMOTION_SUPPORT_UIELEMENTS -using Unity.Collections; -using UnityEngine; -using UnityEngine.UIElements; -#if LITMOTION_SUPPORT_ZSTRING -using Cysharp.Text; -#endif - -namespace LitMotion.Extensions -{ - /// - /// Provides binding extension methods for UIElements. - /// - public static class LitMotionUIToolkitExtensions - { - #region VisualElement - - /// - /// Create a motion data and bind it to VisualElement.style.left - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleLeft(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.left = x; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.right - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleRight(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.right = x; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.top - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleTop(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.top = x; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.bottom - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleBottom(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.bottom = x; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.width - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleWidth(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.width = x; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.height - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleHeight(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.height = x; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.color - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleColor(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.color = x; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.color.r - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleColorR(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - var c = target.style.color.value; - c.r = x; - target.style.color = c; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.color.g - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleColorG(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - var c = target.style.color.value; - c.g = x; - target.style.color = c; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.color.b - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleColorB(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - var c = target.style.color.value; - c.b = x; - target.style.color = c; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.color.a - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleColorA(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - var c = target.style.color.value; - c.a = x; - target.style.color = c; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.backgroundColor - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleBackgroundColor(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.backgroundColor = x; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.backgroundColor.r - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleBackgroundColorR(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - var c = target.style.backgroundColor.value; - c.r = x; - target.style.backgroundColor = c; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.backgroundColor.g - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleBackgroundColorG(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - var c = target.style.backgroundColor.value; - c.g = x; - target.style.backgroundColor = c; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.backgroundColor.b - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleBackgroundColorB(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - var c = target.style.backgroundColor.value; - c.b = x; - target.style.backgroundColor = c; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.backgroundColor.a - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleBackgroundColorA(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - var c = target.style.backgroundColor.value; - c.a = x; - target.style.backgroundColor = c; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.opacity - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleOpacity(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.opacity = x; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.fontSize - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleFontSize(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.fontSize = x; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.wordSpacing - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleWordSpacing(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.wordSpacing = x; - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.translate - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleTranslate(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.translate = new Translate(x.x, x.y, x.z); - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.translate - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleTranslate(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.translate = new Translate(x.x, x.y); - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.rotate - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleRotate(this MotionBuilder builder, VisualElement visualElement, AngleUnit angleUnit = AngleUnit.Degree) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, (x, target) => - { - target.style.rotate = new Rotate(new Angle(x, angleUnit)); - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.scale - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleScale(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.scale = new Scale(x); - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.transformOrigin - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleTransformOrigin(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.transformOrigin = new TransformOrigin(x.x, x.y, x.z); - }); - } - - /// - /// Create a motion data and bind it to VisualElement.style.transformOrigin - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToStyleTransformOrigin(this MotionBuilder builder, VisualElement visualElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualElement); - return builder.Bind(visualElement, static (x, target) => - { - target.style.transformOrigin = new TransformOrigin(x.x, x.y); - }); - } - - #endregion - - #region AbstractProgressBar - - /// - /// Create a motion data and bind it to AbstractProgressBar.value - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToProgressBar(this MotionBuilder builder, AbstractProgressBar progressBar) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(progressBar); - return builder.Bind(progressBar, static (x, target) => - { - target.value = x; - }); - } - - #endregion - - #region TextElement - - /// - /// Create a motion data and bind it to TextElement.text - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(textElement); - return builder.Bind(textElement, static (x, target) => - { - target.text = x.ConvertToString(); - }); - } - - /// - /// Create a motion data and bind it to TextElement.text - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(textElement); - return builder.Bind(textElement, static (x, target) => - { - target.text = x.ConvertToString(); - }); - } - - /// - /// Create a motion data and bind it to TextElement.text - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(textElement); - return builder.Bind(textElement, static (x, target) => - { - target.text = x.ConvertToString(); - }); - } - - /// - /// Create a motion data and bind it to TextElement.text - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(textElement); - return builder.Bind(textElement, static (x, target) => - { - target.text = x.ConvertToString(); - }); - } - - /// - /// Create a motion data and bind it to TextElement.text - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(textElement); - return builder.Bind(textElement, static (x, target) => - { - target.text = x.ConvertToString(); - }); - } - - /// - /// Create a motion data and bind it to Text.text - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(textElement); - return builder.Bind(textElement, static (x, target) => - { - target.text = x.ToString(); - }); - } - - /// - /// Create a motion data and bind it to Text.text - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Format string - /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement, string format) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(textElement); - return builder.Bind(textElement, format, static (x, textElement, format) => - { -#if LITMOTION_SUPPORT_ZSTRING - textElement.text = ZString.Format(format, x); -#else - textElement.text = string.Format(format, x); -#endif - }); - } - - /// - /// Create a motion data and bind it to Text.text - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(textElement); - return builder.Bind(textElement, static (x, target) => - { - target.text = x.ToString(); - }); - } - - /// - /// Create a motion data and bind it to Text.text - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Format string - /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement, string format) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(textElement); - return builder.Bind(textElement, format, static (x, textElement, format) => - { -#if LITMOTION_SUPPORT_ZSTRING - textElement.text = ZString.Format(format, x); -#else - textElement.text = string.Format(format, x); -#endif - }); - } - - /// - /// Create a motion data and bind it to Text.text - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(textElement); - return builder.Bind(textElement, static (x, target) => - { - target.text = x.ToString(); - }); - } - - /// - /// Create a motion data and bind it to Text.text - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Format string - /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement, string format) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(textElement); - return builder.Bind(textElement, format, static (x, textElement, format) => - { -#if LITMOTION_SUPPORT_ZSTRING - textElement.text = ZString.Format(format, x); -#else - textElement.text = string.Format(format, x); -#endif - }); - } - #endregion - } -} -#endif +// #if LITMOTION_SUPPORT_UIELEMENTS +// using Unity.Collections; +// using UnityEngine; +// using UnityEngine.UIElements; +// #if LITMOTION_SUPPORT_ZSTRING +// using Cysharp.Text; +// #endif + +// namespace LitMotion.Extensions +// { +// /// +// /// Provides binding extension methods for UIElements. +// /// +// public static class LitMotionUIToolkitExtensions +// { +// #region VisualElement + +// /// +// /// Create a motion data and bind it to VisualElement.style.left +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleLeft(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.left = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.right +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleRight(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.right = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.top +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleTop(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.top = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.bottom +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleBottom(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.bottom = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.width +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleWidth(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.width = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.height +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleHeight(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.height = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.color +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleColor(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.color = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.color.r +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleColorR(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// var c = target.style.color.value; +// c.r = x; +// target.style.color = c; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.color.g +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleColorG(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// var c = target.style.color.value; +// c.g = x; +// target.style.color = c; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.color.b +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleColorB(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// var c = target.style.color.value; +// c.b = x; +// target.style.color = c; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.color.a +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleColorA(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// var c = target.style.color.value; +// c.a = x; +// target.style.color = c; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.backgroundColor +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleBackgroundColor(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.backgroundColor = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.backgroundColor.r +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleBackgroundColorR(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// var c = target.style.backgroundColor.value; +// c.r = x; +// target.style.backgroundColor = c; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.backgroundColor.g +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleBackgroundColorG(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// var c = target.style.backgroundColor.value; +// c.g = x; +// target.style.backgroundColor = c; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.backgroundColor.b +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleBackgroundColorB(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// var c = target.style.backgroundColor.value; +// c.b = x; +// target.style.backgroundColor = c; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.backgroundColor.a +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleBackgroundColorA(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// var c = target.style.backgroundColor.value; +// c.a = x; +// target.style.backgroundColor = c; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.opacity +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleOpacity(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.opacity = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.fontSize +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleFontSize(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.fontSize = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.wordSpacing +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleWordSpacing(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.wordSpacing = x; +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.translate +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleTranslate(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.translate = new Translate(x.x, x.y, x.z); +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.translate +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleTranslate(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.translate = new Translate(x.x, x.y); +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.rotate +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleRotate(this MotionBuilder builder, VisualElement visualElement, AngleUnit angleUnit = AngleUnit.Degree) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, (x, target) => +// { +// target.style.rotate = new Rotate(new Angle(x, angleUnit)); +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.scale +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleScale(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.scale = new Scale(x); +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.transformOrigin +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleTransformOrigin(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.transformOrigin = new TransformOrigin(x.x, x.y, x.z); +// }); +// } + +// /// +// /// Create a motion data and bind it to VisualElement.style.transformOrigin +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToStyleTransformOrigin(this MotionBuilder builder, VisualElement visualElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualElement); +// return builder.Bind(visualElement, static (x, target) => +// { +// target.style.transformOrigin = new TransformOrigin(x.x, x.y); +// }); +// } + +// #endregion + +// #region AbstractProgressBar + +// /// +// /// Create a motion data and bind it to AbstractProgressBar.value +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToProgressBar(this MotionBuilder builder, AbstractProgressBar progressBar) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(progressBar); +// return builder.Bind(progressBar, static (x, target) => +// { +// target.value = x; +// }); +// } + +// #endregion + +// #region TextElement + +// /// +// /// Create a motion data and bind it to TextElement.text +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(textElement); +// return builder.Bind(textElement, static (x, target) => +// { +// target.text = x.ConvertToString(); +// }); +// } + +// /// +// /// Create a motion data and bind it to TextElement.text +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(textElement); +// return builder.Bind(textElement, static (x, target) => +// { +// target.text = x.ConvertToString(); +// }); +// } + +// /// +// /// Create a motion data and bind it to TextElement.text +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(textElement); +// return builder.Bind(textElement, static (x, target) => +// { +// target.text = x.ConvertToString(); +// }); +// } + +// /// +// /// Create a motion data and bind it to TextElement.text +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(textElement); +// return builder.Bind(textElement, static (x, target) => +// { +// target.text = x.ConvertToString(); +// }); +// } + +// /// +// /// Create a motion data and bind it to TextElement.text +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(textElement); +// return builder.Bind(textElement, static (x, target) => +// { +// target.text = x.ConvertToString(); +// }); +// } + +// /// +// /// Create a motion data and bind it to Text.text +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(textElement); +// return builder.Bind(textElement, static (x, target) => +// { +// target.text = x.ToString(); +// }); +// } + +// /// +// /// Create a motion data and bind it to Text.text +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Format string +// /// Handle of the created motion data. +// public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement, string format) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(textElement); +// return builder.Bind(textElement, format, static (x, textElement, format) => +// { +// #if LITMOTION_SUPPORT_ZSTRING +// textElement.text = ZString.Format(format, x); +// #else +// textElement.text = string.Format(format, x); +// #endif +// }); +// } + +// /// +// /// Create a motion data and bind it to Text.text +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(textElement); +// return builder.Bind(textElement, static (x, target) => +// { +// target.text = x.ToString(); +// }); +// } + +// /// +// /// Create a motion data and bind it to Text.text +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Format string +// /// Handle of the created motion data. +// public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement, string format) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(textElement); +// return builder.Bind(textElement, format, static (x, textElement, format) => +// { +// #if LITMOTION_SUPPORT_ZSTRING +// textElement.text = ZString.Format(format, x); +// #else +// textElement.text = string.Format(format, x); +// #endif +// }); +// } + +// /// +// /// Create a motion data and bind it to Text.text +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(textElement); +// return builder.Bind(textElement, static (x, target) => +// { +// target.text = x.ToString(); +// }); +// } + +// /// +// /// Create a motion data and bind it to Text.text +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Format string +// /// Handle of the created motion data. +// public static MotionHandle BindToText(this MotionBuilder builder, TextElement textElement, string format) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(textElement); +// return builder.Bind(textElement, format, static (x, textElement, format) => +// { +// #if LITMOTION_SUPPORT_ZSTRING +// textElement.text = ZString.Format(format, x); +// #else +// textElement.text = string.Format(format, x); +// #endif +// }); +// } +// #endregion +// } +// } +// #endif diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/VisualEffectGragh/LitMotionVisualEffectExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/VisualEffectGragh/LitMotionVisualEffectExtensions.cs index 47794b84..88842ca9 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/VisualEffectGragh/LitMotionVisualEffectExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/VisualEffectGragh/LitMotionVisualEffectExtensions.cs @@ -1,203 +1,203 @@ -#if LITMOTION_SUPPORT_VFX_GRAPH -using UnityEngine; -using UnityEngine.VFX; +// #if LITMOTION_SUPPORT_VFX_GRAPH +// using UnityEngine; +// using UnityEngine.VFX; -namespace LitMotion.Extensions -{ - /// - /// Provides binding extension methods for VisualEffect. - /// - public static class LitMotionVisualEffectExtensions - { - /// - /// Create a motion data and bind it to VisualEffect parameter. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToVisualEffectFloat(this MotionBuilder builder, VisualEffect visualEffect, string name) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualEffect); - return builder.Bind(visualEffect, name, static (x, visualEffect, name) => - { - visualEffect.SetFloat(name, x); - }); - } +// namespace LitMotion.Extensions +// { +// /// +// /// Provides binding extension methods for VisualEffect. +// /// +// public static class LitMotionVisualEffectExtensions +// { +// /// +// /// Create a motion data and bind it to VisualEffect parameter. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToVisualEffectFloat(this MotionBuilder builder, VisualEffect visualEffect, string name) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualEffect); +// return builder.Bind(visualEffect, name, static (x, visualEffect, name) => +// { +// visualEffect.SetFloat(name, x); +// }); +// } - /// - /// Create a motion data and bind it to VisualEffect parameter. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToVisualEffectFloat(this MotionBuilder builder, VisualEffect visualEffect, int nameID) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualEffect); - return builder.Bind(visualEffect, Box.Create(nameID), static (x, visualEffect, nameID) => - { - visualEffect.SetFloat(nameID.Value, x); - }); - } +// /// +// /// Create a motion data and bind it to VisualEffect parameter. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToVisualEffectFloat(this MotionBuilder builder, VisualEffect visualEffect, int nameID) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualEffect); +// return builder.Bind(visualEffect, Box.Create(nameID), static (x, visualEffect, nameID) => +// { +// visualEffect.SetFloat(nameID.Value, x); +// }); +// } - /// - /// Create a motion data and bind it to VisualEffect parameter. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToVisualEffectInt(this MotionBuilder builder, VisualEffect visualEffect, string name) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualEffect); - return builder.Bind(visualEffect, name, static (x, visualEffect, name) => - { - visualEffect.SetInt(name, x); - }); - } +// /// +// /// Create a motion data and bind it to VisualEffect parameter. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToVisualEffectInt(this MotionBuilder builder, VisualEffect visualEffect, string name) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualEffect); +// return builder.Bind(visualEffect, name, static (x, visualEffect, name) => +// { +// visualEffect.SetInt(name, x); +// }); +// } - /// - /// Create a motion data and bind it to VisualEffect parameter. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToVisualEffectInt(this MotionBuilder builder, VisualEffect visualEffect, int nameID) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualEffect); - return builder.Bind(visualEffect, Box.Create(nameID), static (x, visualEffect, nameID) => - { - visualEffect.SetFloat(nameID.Value, x); - }); - } +// /// +// /// Create a motion data and bind it to VisualEffect parameter. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToVisualEffectInt(this MotionBuilder builder, VisualEffect visualEffect, int nameID) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualEffect); +// return builder.Bind(visualEffect, Box.Create(nameID), static (x, visualEffect, nameID) => +// { +// visualEffect.SetFloat(nameID.Value, x); +// }); +// } - /// - /// Create a motion data and bind it to VisualEffect parameter. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToVisualEffectVector2(this MotionBuilder builder, VisualEffect visualEffect, string name) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualEffect); - return builder.Bind(visualEffect, name, static (x, visualEffect, name) => - { - visualEffect.SetVector2(name, x); - }); - } +// /// +// /// Create a motion data and bind it to VisualEffect parameter. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToVisualEffectVector2(this MotionBuilder builder, VisualEffect visualEffect, string name) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualEffect); +// return builder.Bind(visualEffect, name, static (x, visualEffect, name) => +// { +// visualEffect.SetVector2(name, x); +// }); +// } - /// - /// Create a motion data and bind it to VisualEffect parameter. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToVisualEffectVector2(this MotionBuilder builder, VisualEffect visualEffect, int nameID) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualEffect); - return builder.Bind(visualEffect, Box.Create(nameID), static (x, visualEffect, nameID) => - { - visualEffect.SetVector2(nameID.Value, x); - }); - } +// /// +// /// Create a motion data and bind it to VisualEffect parameter. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToVisualEffectVector2(this MotionBuilder builder, VisualEffect visualEffect, int nameID) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualEffect); +// return builder.Bind(visualEffect, Box.Create(nameID), static (x, visualEffect, nameID) => +// { +// visualEffect.SetVector2(nameID.Value, x); +// }); +// } - /// - /// Create a motion data and bind it to VisualEffect parameter. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToVisualEffectVector3(this MotionBuilder builder, VisualEffect visualEffect, string name) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualEffect); - return builder.Bind(visualEffect, name, static (x, visualEffect, name) => - { - visualEffect.SetVector3(name, x); - }); - } +// /// +// /// Create a motion data and bind it to VisualEffect parameter. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToVisualEffectVector3(this MotionBuilder builder, VisualEffect visualEffect, string name) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualEffect); +// return builder.Bind(visualEffect, name, static (x, visualEffect, name) => +// { +// visualEffect.SetVector3(name, x); +// }); +// } - /// - /// Create a motion data and bind it to VisualEffect parameter. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToVisualEffectVector3(this MotionBuilder builder, VisualEffect visualEffect, int nameID) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualEffect); - return builder.Bind(visualEffect, Box.Create(nameID), static (x, visualEffect, nameID) => - { - visualEffect.SetVector3(nameID.Value, x); - }); - } +// /// +// /// Create a motion data and bind it to VisualEffect parameter. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToVisualEffectVector3(this MotionBuilder builder, VisualEffect visualEffect, int nameID) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualEffect); +// return builder.Bind(visualEffect, Box.Create(nameID), static (x, visualEffect, nameID) => +// { +// visualEffect.SetVector3(nameID.Value, x); +// }); +// } - /// - /// Create a motion data and bind it to VisualEffect parameter. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToVisualEffectVector4(this MotionBuilder builder, VisualEffect visualEffect, string name) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualEffect); - return builder.Bind(visualEffect, name, static (x, visualEffect, name) => - { - visualEffect.SetVector4(name, x); - }); - } +// /// +// /// Create a motion data and bind it to VisualEffect parameter. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToVisualEffectVector4(this MotionBuilder builder, VisualEffect visualEffect, string name) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualEffect); +// return builder.Bind(visualEffect, name, static (x, visualEffect, name) => +// { +// visualEffect.SetVector4(name, x); +// }); +// } - /// - /// Create a motion data and bind it to VisualEffect parameter. - /// - /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - /// This builder - /// - /// Handle of the created motion data. - public static MotionHandle BindToVisualEffectVector4(this MotionBuilder builder, VisualEffect visualEffect, int nameID) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter - { - Error.IsNull(visualEffect); - return builder.Bind(visualEffect, Box.Create(nameID), static (x, visualEffect, nameID) => - { - visualEffect.SetVector4(nameID.Value, x); - }); - } - } -} -#endif +// /// +// /// Create a motion data and bind it to VisualEffect parameter. +// /// +// /// The type of special parameters given to the motion data +// /// The type of adapter that support value animation +// /// This builder +// /// +// /// Handle of the created motion data. +// public static MotionHandle BindToVisualEffectVector4(this MotionBuilder builder, VisualEffect visualEffect, int nameID) +// where TOptions : unmanaged, IMotionOptions +// where TAdapter : unmanaged, IMotionAdapter +// { +// Error.IsNull(visualEffect); +// return builder.Bind(visualEffect, Box.Create(nameID), static (x, visualEffect, nameID) => +// { +// visualEffect.SetVector4(nameID.Value, x); +// }); +// } +// } +// } +// #endif diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/uGUI/LitMotionRectTransformExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/uGUI/LitMotionRectTransformExtensions.cs index 609f6d56..1d6d902f 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/uGUI/LitMotionRectTransformExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/uGUI/LitMotionRectTransformExtensions.cs @@ -15,9 +15,9 @@ public static class LitMotionRectTransformExtensions /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToAnchoredPosition(this MotionBuilder builder, RectTransform rectTransform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToAnchoredPosition(this MotionBuilder builder, RectTransform rectTransform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rectTransform); return builder.Bind(rectTransform, static (x, target) => @@ -34,9 +34,9 @@ public static MotionHandle BindToAnchoredPosition(this Motio /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToAnchoredPositionX(this MotionBuilder builder, RectTransform rectTransform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToAnchoredPositionX(this MotionBuilder builder, RectTransform rectTransform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rectTransform); return builder.Bind(rectTransform, static (x, target) => @@ -55,9 +55,9 @@ public static MotionHandle BindToAnchoredPositionX(this Moti /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToAnchoredPositionY(this MotionBuilder builder, RectTransform rectTransform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToAnchoredPositionY(this MotionBuilder builder, RectTransform rectTransform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rectTransform); return builder.Bind(rectTransform, static (x, target) => @@ -76,9 +76,9 @@ public static MotionHandle BindToAnchoredPositionY(this Moti /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToAnchoredPosition3D(this MotionBuilder builder, RectTransform rectTransform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToAnchoredPosition3D(this MotionBuilder builder, RectTransform rectTransform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rectTransform); return builder.Bind(rectTransform, static (x, target) => @@ -95,9 +95,9 @@ public static MotionHandle BindToAnchoredPosition3D(this Mot /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToAnchoredPosition3DX(this MotionBuilder builder, RectTransform rectTransform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToAnchoredPosition3DX(this MotionBuilder builder, RectTransform rectTransform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rectTransform); return builder.Bind(rectTransform, static (x, target) => @@ -116,9 +116,9 @@ public static MotionHandle BindToAnchoredPosition3DX(this Mo /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToAnchoredPosition3DY(this MotionBuilder builder, RectTransform rectTransform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToAnchoredPosition3DY(this MotionBuilder builder, RectTransform rectTransform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rectTransform); return builder.Bind(rectTransform, static (x, target) => @@ -137,9 +137,9 @@ public static MotionHandle BindToAnchoredPosition3DY(this Mo /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToAnchoredPosition3DZ(this MotionBuilder builder, RectTransform rectTransform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToAnchoredPosition3DZ(this MotionBuilder builder, RectTransform rectTransform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rectTransform); return builder.Bind(rectTransform, static (x, target) => @@ -158,9 +158,9 @@ public static MotionHandle BindToAnchoredPosition3DZ(this Mo /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToAnchorMin(this MotionBuilder builder, RectTransform rectTransform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToAnchorMin(this MotionBuilder builder, RectTransform rectTransform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rectTransform); return builder.Bind(rectTransform, static (x, target) => @@ -177,9 +177,9 @@ public static MotionHandle BindToAnchorMin(this MotionBuilde /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToAnchorMax(this MotionBuilder builder, RectTransform rectTransform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToAnchorMax(this MotionBuilder builder, RectTransform rectTransform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rectTransform); return builder.Bind(rectTransform, static (x, target) => @@ -197,9 +197,9 @@ public static MotionHandle BindToAnchorMax(this MotionBuilde /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToSizeDelta(this MotionBuilder builder, RectTransform rectTransform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToSizeDelta(this MotionBuilder builder, RectTransform rectTransform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rectTransform); return builder.Bind(rectTransform, static (x, target) => @@ -216,9 +216,9 @@ public static MotionHandle BindToSizeDelta(this MotionBuilde /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToSizeDeltaX(this MotionBuilder builder, RectTransform rectTransform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToSizeDeltaX(this MotionBuilder builder, RectTransform rectTransform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rectTransform); return builder.Bind(rectTransform, static (x, target) => @@ -237,9 +237,9 @@ public static MotionHandle BindToSizeDeltaX(this MotionBuild /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToSizeDeltaY(this MotionBuilder builder, RectTransform rectTransform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToSizeDeltaY(this MotionBuilder builder, RectTransform rectTransform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rectTransform); return builder.Bind(rectTransform, static (x, target) => @@ -258,9 +258,9 @@ public static MotionHandle BindToSizeDeltaY(this MotionBuild /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToPivot(this MotionBuilder builder, RectTransform rectTransform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPivot(this MotionBuilder builder, RectTransform rectTransform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rectTransform); return builder.Bind(rectTransform, static (x, target) => @@ -277,9 +277,9 @@ public static MotionHandle BindToPivot(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToPivotX(this MotionBuilder builder, RectTransform rectTransform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPivotX(this MotionBuilder builder, RectTransform rectTransform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rectTransform); return builder.Bind(rectTransform, static (x, target) => @@ -298,9 +298,9 @@ public static MotionHandle BindToPivotX(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToPivotY(this MotionBuilder builder, RectTransform rectTransform) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToPivotY(this MotionBuilder builder, RectTransform rectTransform) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(rectTransform); return builder.Bind(rectTransform, static (x, target) => diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/uGUI/LitMotionUGUIExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/uGUI/LitMotionUGUIExtensions.cs index db5a6337..142b89d9 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Extensions/uGUI/LitMotionUGUIExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Extensions/uGUI/LitMotionUGUIExtensions.cs @@ -21,9 +21,9 @@ public static class LitMotionUGUIExtensions /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToColor(this MotionBuilder builder, Graphic graphic) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToColor(this MotionBuilder builder, Graphic graphic) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(graphic); return builder.Bind(graphic, static (x, target) => @@ -40,9 +40,9 @@ public static MotionHandle BindToColor(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToColorR(this MotionBuilder builder, Graphic graphic) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToColorR(this MotionBuilder builder, Graphic graphic) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(graphic); return builder.Bind(graphic, static (x, target) => @@ -61,9 +61,9 @@ public static MotionHandle BindToColorR(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToColorG(this MotionBuilder builder, Graphic graphic) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToColorG(this MotionBuilder builder, Graphic graphic) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(graphic); return builder.Bind(graphic, static (x, target) => @@ -82,9 +82,9 @@ public static MotionHandle BindToColorG(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToColorB(this MotionBuilder builder, Graphic graphic) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToColorB(this MotionBuilder builder, Graphic graphic) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(graphic); return builder.Bind(graphic, static (x, target) => @@ -103,9 +103,9 @@ public static MotionHandle BindToColorB(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToColorA(this MotionBuilder builder, Graphic graphic) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToColorA(this MotionBuilder builder, Graphic graphic) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(graphic); return builder.Bind(graphic, static (x, target) => @@ -124,9 +124,9 @@ public static MotionHandle BindToColorA(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToFillAmount(this MotionBuilder builder, Image image) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToFillAmount(this MotionBuilder builder, Image image) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(image); return builder.Bind(image, static (x, target) => @@ -143,9 +143,9 @@ public static MotionHandle BindToFillAmount(this MotionBuild /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToAlpha(this MotionBuilder builder, CanvasGroup canvasGroup) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToAlpha(this MotionBuilder builder, CanvasGroup canvasGroup) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(canvasGroup); return builder.Bind(canvasGroup, static (x, target) => @@ -162,9 +162,9 @@ public static MotionHandle BindToAlpha(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToFontSize(this MotionBuilder builder, Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToFontSize(this MotionBuilder builder, Text text) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(text); return builder.Bind(text, static (x, target) => @@ -181,9 +181,9 @@ public static MotionHandle BindToFontSize(this MotionBuilder /// This builder /// /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToText(this MotionBuilder builder, Text text) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(text); return builder.Bind(text, static (x, target) => @@ -200,9 +200,9 @@ public static MotionHandle BindToText(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToText(this MotionBuilder builder, Text text) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(text); return builder.Bind(text, static (x, target) => @@ -219,9 +219,9 @@ public static MotionHandle BindToText(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToText(this MotionBuilder builder, Text text) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(text); return builder.Bind(text, static (x, target) => @@ -238,9 +238,9 @@ public static MotionHandle BindToText(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToText(this MotionBuilder builder, Text text) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(text); return builder.Bind(text, static (x, target) => @@ -257,9 +257,9 @@ public static MotionHandle BindToText(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToText(this MotionBuilder builder, Text text) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(text); return builder.Bind(text, static (x, target) => @@ -276,9 +276,9 @@ public static MotionHandle BindToText(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToText(this MotionBuilder builder, Text text) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(text); return builder.Bind(text, static (x, target) => @@ -296,9 +296,9 @@ public static MotionHandle BindToText(this MotionBuilder /// Format string /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, Text text, string format) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToText(this MotionBuilder builder, Text text, string format) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(text); return builder.Bind(text, format, static (x, text, format) => @@ -319,9 +319,9 @@ public static MotionHandle BindToText(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToText(this MotionBuilder builder, Text text) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(text); return builder.Bind(text, static (x, target) => @@ -339,9 +339,9 @@ public static MotionHandle BindToText(this MotionBuilder /// Format string /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, Text text, string format) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToText(this MotionBuilder builder, Text text, string format) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(text); return builder.Bind(text, format, static (x, text, format) => @@ -362,9 +362,9 @@ public static MotionHandle BindToText(this MotionBuilderThis builder /// /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, Text text) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToText(this MotionBuilder builder, Text text) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(text); return builder.Bind(text, static (x, target) => @@ -382,9 +382,9 @@ public static MotionHandle BindToText(this MotionBuilder /// Format string /// Handle of the created motion data. - public static MotionHandle BindToText(this MotionBuilder builder, Text text, string format) - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + public static MotionHandle BindToText(this MotionBuilder builder, Text text, string format) + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(text); return builder.Bind(text, format, static (x, text, format) => diff --git a/src/LitMotion/Assets/LitMotion/Runtime/External/R3/LitMotionR3Extensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/External/R3/LitMotionR3Extensions.cs index 30a86fd0..b5264063 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/External/R3/LitMotionR3Extensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/External/R3/LitMotionR3Extensions.cs @@ -9,14 +9,16 @@ public static class LitMotionR3Extensions /// Create the motion as Observable. /// /// The type of value to animate + /// The type of vectorized value for internal processing /// The type of special parameters given to the motion data - /// The type of adapter that support value animation + /// The type of animation specification /// This builder /// Observable of the created motion. - public static Observable ToObservable(this MotionBuilder builder) + public static Observable ToObservable(this MotionBuilder builder) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { var subject = new Subject(); builder.SetCallbackData(subject, static (x, subject) => subject.OnNext(x)); @@ -30,15 +32,17 @@ public static Observable ToObservable(this M /// Create a motion data and bind it to ReactiveProperty. /// /// The type of value to animate + /// The type of vectorized value for internal processing /// The type of special parameters given to the motion data - /// The type of adapter that support value animation + /// The type of animation specification /// This builder - /// Target object that implements IProgress + /// Target ReactiveProperty to bind to /// Handle of the created motion data. - public static MotionHandle BindToReactiveProperty(this MotionBuilder builder, ReactiveProperty reactiveProperty) + public static MotionHandle BindToReactiveProperty(this MotionBuilder builder, ReactiveProperty reactiveProperty) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { Error.IsNull(reactiveProperty); return builder.Bind(reactiveProperty, static (x, target) => diff --git a/src/LitMotion/Assets/LitMotion/Runtime/IMotionAdapter.cs b/src/LitMotion/Assets/LitMotion/Runtime/IMotionAdapter.cs index f3313e3d..cf375a3e 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/IMotionAdapter.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/IMotionAdapter.cs @@ -4,9 +4,11 @@ namespace LitMotion /// Implement this interface to define animating values of a particular type. /// /// The type of value to animate + /// The vectorized type for internal calculations /// The type of special parameters given to the motion entity - public interface IMotionAdapter + public interface IMotionAdapter : ITwoWayConverter where TValue : unmanaged + where VValue : unmanaged where TOptions : unmanaged, IMotionOptions { /// diff --git a/src/LitMotion/Assets/LitMotion/Runtime/IMotionScheduler.cs b/src/LitMotion/Assets/LitMotion/Runtime/IMotionScheduler.cs index fcb22b96..c42b27b1 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/IMotionScheduler.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/IMotionScheduler.cs @@ -9,14 +9,16 @@ public interface IMotionScheduler /// Schedule the motion. /// /// The type of value to animate + /// The type of vectorized value for internal processing /// The type of special parameters given to the motion data - /// The type of adapter that support value animation + /// The type of animation specification /// Motion builder /// Motion handle - MotionHandle Schedule(ref MotionBuilder builder) + MotionHandle Schedule(ref MotionBuilder builder) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter; + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec; } /// diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/ManagedMotionData.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/ManagedMotionData.cs index 16d85870..62a37e1c 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/ManagedMotionData.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/ManagedMotionData.cs @@ -88,5 +88,36 @@ public readonly void InvokeOnLoopComplete(int completedLoops) MotionDispatcher.GetUnhandledExceptionHandler()?.Invoke(ex); } } + + /// + /// Initialize the managed motion data with builder buffer values + /// + /// The type of value to animate + /// The options type + /// The motion builder buffer containing initialization data + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Initialize(in MotionBuilderBuffer buffer, TValue startValue) + where TValue : unmanaged + where TOptions : unmanaged, IMotionOptions + { + CancelOnError = buffer.CancelOnError; + SkipValuesDuringDelay = buffer.SkipValuesDuringDelay; + UpdateAction = buffer.UpdateAction; + OnLoopCompleteAction = buffer.OnLoopCompleteAction; + OnCancelAction = buffer.OnCancelAction; + OnCompleteAction = buffer.OnCompleteAction; + StateCount = buffer.StateCount; + State0 = buffer.State0; + State1 = buffer.State1; + State2 = buffer.State2; + +#if LITMOTION_DEBUG + DebugName = buffer.DebugName; +#endif + if (buffer.ImmediateBind && buffer.UpdateAction != null) + { + UpdateUnsafe(startValue); + } + } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs index 54405a7a..d99ea29f 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs @@ -224,8 +224,34 @@ internal struct MotionData public TValue EndValue; public TOptions Options; + // 新增泛型Initialize方法 + public void Initialize(TweenOption option) + { + Core.Parameters.Duration = option.DurationNanos / AnimationConstants.SecondsToNanos; + Core.Parameters.Delay = option.DelayNanos / AnimationConstants.SecondsToNanos; + Core.Parameters.DelayType = option.DelayType; + Core.Parameters.Ease = option.Ease; + Core.Parameters.Loops = option.Loops; + Core.Parameters.LoopType = option.LoopType; + } + + public TValue GetFirstValue() + where TAdapter : unmanaged, IMotionAdapter + { + return default(TAdapter).Evaluate(ref StartValue,ref EndValue,ref Options, + new() + { + Progress = Core.Parameters.Ease switch + { + Ease.CustomAnimationCurve => Core.Parameters.AnimationCurve.Evaluate(0f), + _ => EaseUtility.Evaluate(0f, Core.Parameters.Ease) + }, + Time = Core.State.Time, + }); + } + public void Update(double time, out TValue result) - where TAdapter : unmanaged, IMotionAdapter + where TAdapter : unmanaged, IMotionAdapter { Core.Update(time, out var progress); @@ -238,7 +264,7 @@ public void Update(double time, out TValue result) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Complete(out TValue result) - where TAdapter : unmanaged, IMotionAdapter + where TAdapter : unmanaged, IMotionAdapter { Core.Complete(out var progress); diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionManager.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionManager.cs index 940b5441..533c8f55 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionManager.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionManager.cs @@ -10,20 +10,22 @@ internal static class MotionManager public static int MotionTypeCount { get; private set; } - public static void Register(MotionStorage storage) + public static void Register( + MotionStorage storage) where TValue : unmanaged + where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { list.Add(storage); MotionTypeCount++; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref MotionData GetDataRef(MotionHandle handle, bool checkIsInSequence = true) + public static ref AnimationState GetStateRef(MotionHandle handle, bool checkIsInSequence = true) { CheckTypeId(handle); - return ref list[handle.StorageId].GetDataRef(handle, checkIsInSequence); + return ref list[handle.StorageId].GetStateRef(handle, checkIsInSequence); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStatus.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStatus.cs index b6a47986..77e5d8ae 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStatus.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStatus.cs @@ -3,7 +3,7 @@ namespace LitMotion /// /// Motion status. /// - internal enum MotionStatus : byte + public enum MotionStatus : byte { None = 0, Scheduled = 1, diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStorage.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStorage.cs index 55d55177..53e07341 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStorage.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStorage.cs @@ -26,17 +26,18 @@ internal interface IMotionStorage void Cancel(MotionHandle handle, bool checkIsInSequence = true); void Complete(MotionHandle handle, bool checkIsInSequence = true); void SetTime(MotionHandle handle, double time, bool checkIsInSequence = true); - ref MotionData GetDataRef(MotionHandle handle, bool checkIsInSequence = true); + ref AnimationState GetStateRef(MotionHandle handle, bool checkIsInSequence = true); ref ManagedMotionData GetManagedDataRef(MotionHandle handle, bool checkIsInSequence = true); void AddToSequence(MotionHandle handle, out double motionDuration); MotionDebugInfo GetDebugInfo(MotionHandle handle); void Reset(); } - internal sealed class MotionStorage : IMotionStorage + internal sealed class MotionStorage : IMotionStorage where TValue : unmanaged + where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { const int InitialCapacity = 32; @@ -45,7 +46,7 @@ internal sealed class MotionStorage : IMotionStorage SparseSetCore sparseSetCore = new(InitialCapacity); SparseIndex[] sparseIndexLookup = new SparseIndex[InitialCapacity]; - MotionData[] unmanagedDataArray = new MotionData[InitialCapacity]; + TargetBasedAnimation[] unmanagedDataArray = new TargetBasedAnimation[InitialCapacity]; ManagedMotionData[] managedDataArray = new ManagedMotionData[InitialCapacity]; AllocatorHelper allocator; int tail; @@ -57,7 +58,7 @@ public MotionStorage(int id) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span> GetDataSpan() + public Span> GetDataSpan() { return unmanagedDataArray.AsSpan(); } @@ -77,88 +78,27 @@ public void EnsureCapacity(int minimumCapacity) ArrayHelper.EnsureCapacity(ref managedDataArray, minimumCapacity); } - public unsafe MotionHandle Create(ref MotionBuilder builder) + public unsafe MotionHandle Create(ref MotionBuilder builder) + where TweenOptions : unmanaged, ITweenOptions + where TTweenAnimationSpec : unmanaged, IVectorizedAnimationSpec { EnsureCapacity(tail + 1); var buffer = builder.buffer; ref var dataRef = ref unmanagedDataArray[tail]; ref var managedDataRef = ref managedDataArray[tail]; - - ref var state = ref dataRef.Core.State; - ref var parameters = ref dataRef.Core.Parameters; - - state.Status = MotionStatus.Scheduled; - state.Time = 0; - state.PlaybackSpeed = 1f; - state.IsPreserved = false; - - parameters.TimeKind = buffer.TimeKind; - parameters.Duration = buffer.Duration; - parameters.Delay = buffer.Delay; - parameters.DelayType = buffer.DelayType; - parameters.Ease = buffer.Ease; - parameters.Loops = buffer.Loops; - parameters.LoopType = buffer.LoopType; - dataRef.StartValue = buffer.StartValue; - dataRef.EndValue = buffer.EndValue; - dataRef.Options = buffer.Options; - - if (buffer.Ease == Ease.CustomAnimationCurve) - { - if (parameters.AnimationCurve.IsCreated) - { - parameters.AnimationCurve.CopyFrom(buffer.AnimationCurve); - } - else - { -#if LITMOTION_COLLECTIONS_2_0_OR_NEWER - parameters.AnimationCurve = new NativeAnimationCurve(buffer.AnimationCurve, allocator.Allocator.Handle); -#else - parameters.AnimationCurve = new UnsafeAnimationCurve(buffer.AnimationCurve, allocator.Allocator.Handle); -#endif - } - } - - managedDataRef.CancelOnError = buffer.CancelOnError; - managedDataRef.SkipValuesDuringDelay = buffer.SkipValuesDuringDelay; - managedDataRef.UpdateAction = buffer.UpdateAction; - managedDataRef.OnLoopCompleteAction = buffer.OnLoopCompleteAction; - managedDataRef.OnCancelAction = buffer.OnCancelAction; - managedDataRef.OnCompleteAction = buffer.OnCompleteAction; - managedDataRef.StateCount = buffer.StateCount; - managedDataRef.State0 = buffer.State0; - managedDataRef.State1 = buffer.State1; - managedDataRef.State2 = buffer.State2; - -#if LITMOTION_DEBUG - managedDataRef.DebugName = buffer.DebugName; -#endif - - if (buffer.ImmediateBind && buffer.UpdateAction != null) - { - managedDataRef.UpdateUnsafe( - default(TAdapter).Evaluate( - ref dataRef.StartValue, - ref dataRef.EndValue, - ref dataRef.Options, - new() - { - Progress = parameters.Ease switch - { - Ease.CustomAnimationCurve => buffer.AnimationCurve.Evaluate(0f), - _ => EaseUtility.Evaluate(0f, parameters.Ease) - }, - Time = state.Time, - } - )); - } - + + // 初始化非托管数据 + var options = Unsafe.As(ref buffer.Options); + dataRef.Initialize(options, buffer.StartValue, buffer.EndValue); + + // 初始化托管数据 + dataRef.GetValueFromNanos(0L,out var startValue); + managedDataRef.Initialize(buffer,startValue); var sparseIndex = sparseSetCore.Alloc(tail); sparseIndexLookup[tail] = sparseIndex; tail++; - return new MotionHandle() { Index = sparseIndex.Index, @@ -213,26 +153,26 @@ public void RemoveAll(NativeList denseIndexList) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsActive(MotionHandle handle) + public unsafe bool IsActive(MotionHandle handle) { ref var slot = ref sparseSetCore.GetSlotRefUnchecked(handle.Index); if (IsDenseIndexOutOfRange(slot.DenseIndex)) return false; if (IsInvalidVersion(slot.Version, handle)) return false; - ref var state = ref unmanagedDataArray[slot.DenseIndex].Core.State; - return state.Status is MotionStatus.Scheduled or MotionStatus.Delayed or MotionStatus.Playing || - (state.Status is MotionStatus.Completed && state.IsPreserved); + var state = unmanagedDataArray[slot.DenseIndex].Core.State; + return state->Status is MotionStatus.Scheduled or MotionStatus.Delayed or MotionStatus.Playing || + (state->Status is MotionStatus.Completed && state->IsPreserved); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsPlaying(MotionHandle handle) + public unsafe bool IsPlaying(MotionHandle handle) { ref var slot = ref sparseSetCore.GetSlotRefUnchecked(handle.Index); if (IsDenseIndexOutOfRange(slot.DenseIndex)) return false; if (IsInvalidVersion(slot.Version, handle)) return false; - ref var state = ref unmanagedDataArray[slot.DenseIndex].Core.State; - return state.Status is MotionStatus.Scheduled or MotionStatus.Delayed or MotionStatus.Playing; + var state = unmanagedDataArray[slot.DenseIndex].Core.State; + return state->Status is MotionStatus.Scheduled or MotionStatus.Delayed or MotionStatus.Playing; } public bool TryCancel(MotionHandle handle, bool checkIsInSequence = true) @@ -256,7 +196,7 @@ public void Cancel(MotionHandle handle, bool checkIsInSequence = true) } } - int TryCancelCore(MotionHandle handle, bool checkIsInSequence) + unsafe int TryCancelCore(MotionHandle handle, bool checkIsInSequence) { ref var slot = ref sparseSetCore.GetSlotRefUnchecked(handle.Index); var denseIndex = slot.DenseIndex; @@ -266,20 +206,20 @@ int TryCancelCore(MotionHandle handle, bool checkIsInSequence) } ref var dataRef = ref unmanagedDataArray[denseIndex]; - ref var state = ref dataRef.Core.State; + var state = dataRef.Core.State; - if (state.Status is MotionStatus.None or MotionStatus.Canceled || - (state.Status is MotionStatus.Completed && !state.IsPreserved)) + if (state->Status is MotionStatus.None or MotionStatus.Canceled || + (state->Status is MotionStatus.Completed && !state->IsPreserved)) { return 2; } - if (checkIsInSequence && state.IsInSequence) + if (checkIsInSequence && state->IsInSequence) { return 3; } - state.Status = MotionStatus.Canceled; + state->Status = MotionStatus.Canceled; ref var managedData = ref managedDataArray[denseIndex]; managedData.InvokeOnCancel(); @@ -310,7 +250,7 @@ public void Complete(MotionHandle handle, bool checkIsInSequence = true) } } - int TryCompleteCore(MotionHandle handle, bool checkIsInSequence) + unsafe int TryCompleteCore(MotionHandle handle, bool checkIsInSequence) { ref var slot = ref sparseSetCore.GetSlotRefUnchecked(handle.Index); @@ -320,25 +260,24 @@ int TryCompleteCore(MotionHandle handle, bool checkIsInSequence) } ref var dataRef = ref unmanagedDataArray[slot.DenseIndex]; - ref var state = ref dataRef.Core.State; - ref var parameters = ref dataRef.Core.Parameters; + var state = dataRef.Core.State; - if (state.Status is MotionStatus.None or MotionStatus.Canceled or MotionStatus.Completed) + if (state->Status is MotionStatus.None or MotionStatus.Canceled or MotionStatus.Completed) { return 2; } - if (checkIsInSequence && state.IsInSequence) + if (checkIsInSequence && state->IsInSequence) { return 3; } - if (parameters.Loops < 0) + if (dataRef.IsInfinite) { return 4; } - dataRef.Complete(out var result); + dataRef.Complete(out var result); ref var managedData = ref managedDataArray[slot.DenseIndex]; try @@ -350,9 +289,9 @@ int TryCompleteCore(MotionHandle handle, bool checkIsInSequence) MotionDispatcher.GetUnhandledExceptionHandler()?.Invoke(ex); } - if (state.WasLoopCompleted) + if (state->WasLoopCompleted) { - managedData.InvokeOnLoopComplete(state.CompletedLoops); + managedData.InvokeOnLoopComplete(state->CompletedLoops); } managedData.InvokeOnComplete(); @@ -370,16 +309,18 @@ public unsafe void SetTime(MotionHandle handle, double time, bool checkIsInSeque var version = slot.Version; if (version <= 0 || version != handle.Version) Error.MotionNotExists(); - fixed (MotionData* arrayPtr = unmanagedDataArray) + fixed (TargetBasedAnimation* arrayPtr = unmanagedDataArray) { var dataPtr = arrayPtr + denseIndex; - ref var state = ref dataPtr->Core.State; + var state = dataPtr->Core.State; - if (checkIsInSequence && state.IsInSequence) Error.MotionIsInSequence(); + if (checkIsInSequence && state->IsInSequence) Error.MotionIsInSequence(); - dataPtr->Update(time, out var result); + // TODO: TargetBasedAnimation 需要实现 Update 方法 + // dataPtr->Update(time, out var result); + dataPtr->GetValueFromNanos((long)(time * 1_000_000_000),out var result); // 转换为纳秒 - var status = state.Status; + var status = state->Status; ref var managedData = ref managedDataArray[denseIndex]; if (status is MotionStatus.Playing or MotionStatus.Completed || (status == MotionStatus.Delayed && !managedData.SkipValuesDuringDelay)) @@ -393,18 +334,18 @@ public unsafe void SetTime(MotionHandle handle, double time, bool checkIsInSeque MotionDispatcher.GetUnhandledExceptionHandler()?.Invoke(ex); if (managedData.CancelOnError) { - state.Status = MotionStatus.Canceled; + state->Status = MotionStatus.Canceled; managedData.OnCancelAction?.Invoke(); return; } } - if (state.WasLoopCompleted) + if (state->WasLoopCompleted) { - managedData.InvokeOnLoopComplete(state.CompletedLoops); + managedData.InvokeOnLoopComplete(state->CompletedLoops); } - if (status is MotionStatus.Completed && state.WasStatusChanged) + if (status is MotionStatus.Completed && state->WasStatusChanged) { managedData.InvokeOnComplete(); } @@ -412,24 +353,25 @@ public unsafe void SetTime(MotionHandle handle, double time, bool checkIsInSeque } } - public void AddToSequence(MotionHandle handle, out double motionDuration) + public unsafe void AddToSequence(MotionHandle handle, out double motionDuration) { ref var slot = ref GetSlotWithVarify(handle, true); ref var dataRef = ref unmanagedDataArray[slot.DenseIndex]; - if (dataRef.Core.State.Status is not MotionStatus.Scheduled) + if (dataRef.Core.State->Status is not MotionStatus.Scheduled) { throw new ArgumentException("Cannot add a running motion to a sequence."); } motionDuration = handle.TotalDuration; - if (double.IsInfinity(motionDuration)) + //if (double.IsInfinity(motionDuration)) + if (handle.IsInfinite) { throw new ArgumentException("Cannot add an infinitely looping motion to a sequence."); } - dataRef.Core.State.IsPreserved = true; - dataRef.Core.State.IsInSequence = true; + dataRef.Core.State->IsPreserved = true; + dataRef.Core.State->IsInSequence = true; } public ref ManagedMotionData GetManagedDataRef(MotionHandle handle, bool checkIsInSequence = true) @@ -438,13 +380,20 @@ public ref ManagedMotionData GetManagedDataRef(MotionHandle handle, bool checkIs return ref managedDataArray[slot.DenseIndex]; } - public ref MotionData GetDataRef(MotionHandle handle, bool checkIsInSequence = true) + public ref AnimationState GetStateRef(MotionHandle handle, bool checkIsInSequence = true) + { + ref var slot = ref GetSlotWithVarify(handle, checkIsInSequence); + return ref UnsafeUtility.As, AnimationState>(ref unmanagedDataArray[slot.DenseIndex]); + } + + public unsafe ref TOptions GetOptionRef(MotionHandle handle, bool checkIsInSequence = true) { ref var slot = ref GetSlotWithVarify(handle, checkIsInSequence); - return ref UnsafeUtility.As, MotionData>(ref unmanagedDataArray[slot.DenseIndex]); + ref TAnimationSpec dataRef = ref UnsafeUtility.As, TAnimationSpec>(ref unmanagedDataArray[slot.DenseIndex]); + return ref *dataRef.Options; } - public MotionDebugInfo GetDebugInfo(MotionHandle handle) + public unsafe MotionDebugInfo GetDebugInfo(MotionHandle handle) { ref var slot = ref GetSlotWithVarify(handle, false); ref var dataRef = ref unmanagedDataArray[slot.DenseIndex]; @@ -452,25 +401,25 @@ public MotionDebugInfo GetDebugInfo(MotionHandle handle) return new() { StartValue = dataRef.StartValue, - EndValue = dataRef.EndValue, - Options = dataRef.Options, + EndValue = dataRef.TargetValue, + Options = UnsafeUtility.AsRef(dataRef.Core.Options) }; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - ref SparseSetCore.Slot GetSlotWithVarify(MotionHandle handle, bool checkIsInSequence = true) + unsafe ref SparseSetCore.Slot GetSlotWithVarify(MotionHandle handle, bool checkIsInSequence = true) { ref var slot = ref sparseSetCore.GetSlotRefUnchecked(handle.Index); if (IsDenseIndexOutOfRange(slot.DenseIndex)) Error.MotionNotExists(); ref var dataRef = ref unmanagedDataArray[slot.DenseIndex]; - if (IsInvalidVersion(slot.Version, handle) || dataRef.Core.State.Status == MotionStatus.None) + if (IsInvalidVersion(slot.Version, handle) || dataRef.Core.State->Status == MotionStatus.None) { Error.MotionNotExists(); } - if (checkIsInSequence && dataRef.Core.State.IsInSequence) + if (checkIsInSequence && dataRef.Core.State->IsInSequence) { Error.MotionIsInSequence(); } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/PlayerLoopMotionScheduler.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/PlayerLoopMotionScheduler.cs index 16af3dc5..96a9b83a 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/PlayerLoopMotionScheduler.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/PlayerLoopMotionScheduler.cs @@ -17,10 +17,11 @@ internal PlayerLoopMotionScheduler(PlayerLoopTiming playerLoopTiming, MotionTime this.timeKind = timeKind; } - public MotionHandle Schedule(ref MotionBuilder builder) + public MotionHandle Schedule(ref MotionBuilder builder) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { builder.buffer.TimeKind = timeKind; diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/UpdateRunner.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/UpdateRunner.cs index 43542343..82d55d70 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/UpdateRunner.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/UpdateRunner.cs @@ -12,12 +12,13 @@ internal interface IUpdateRunner public void Reset(); } - internal sealed class UpdateRunner : IUpdateRunner + internal sealed class UpdateRunner : IUpdateRunner where TValue : unmanaged + where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { - public UpdateRunner(MotionStorage storage, double time, double unscaledTime, double realtime) + public UpdateRunner(MotionStorage storage, double time, double unscaledTime, double realtime) { this.storage = storage; prevTime = time; @@ -25,13 +26,13 @@ public UpdateRunner(MotionStorage storage, double ti prevRealtime = realtime; } - readonly MotionStorage storage; + readonly MotionStorage storage; double prevTime; double prevUnscaledTime; double prevRealtime; - public MotionStorage Storage => storage; + public MotionStorage Storage => storage; IMotionStorage IUpdateRunner.Storage => storage; public unsafe void Update(double time, double unscaledTime, double realtime) @@ -47,10 +48,10 @@ public unsafe void Update(double time, double unscaledTime, double realtime) prevUnscaledTime = unscaledTime; prevRealtime = realtime; - fixed (MotionData* dataPtr = storage.GetDataSpan()) + fixed (TargetBasedAnimation* dataPtr = storage.GetDataSpan()) { // update data - var job = new MotionUpdateJob() + var job = new MotionUpdateJob() { DataPtr = dataPtr, DeltaTime = deltaTime, @@ -67,11 +68,11 @@ public unsafe void Update(double time, double unscaledTime, double realtime) for (int i = 0; i < managedDataSpan.Length; i++) { var currentDataPtr = dataPtr + i; - ref var state = ref currentDataPtr->Core.State; + var state = currentDataPtr->Core.State; - if (state.IsInSequence) continue; + if (state->IsInSequence) continue; - var status = state.Status; + var status = state->Status; ref var managedData = ref managedDataSpan[i]; if (status is MotionStatus.Playing or MotionStatus.Completed || (status == MotionStatus.Delayed && !managedData.SkipValuesDuringDelay)) { @@ -84,17 +85,17 @@ public unsafe void Update(double time, double unscaledTime, double realtime) MotionDispatcher.GetUnhandledExceptionHandler()?.Invoke(ex); if (managedData.CancelOnError) { - state.Status = MotionStatus.Canceled; + state->Status = MotionStatus.Canceled; managedData.OnCancelAction?.Invoke(); } } - if (state.WasLoopCompleted) + if (state->WasLoopCompleted) { - managedData.InvokeOnLoopComplete(state.CompletedLoops); + managedData.InvokeOnLoopComplete(state->CompletedLoops); } - if (status is MotionStatus.Completed && state.WasStatusChanged) + if (status is MotionStatus.Completed && state->WasStatusChanged) { managedData.InvokeOnComplete(); } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.FromSettings.cs b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.FromSettings.cs index cc604b91..52e71f7c 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.FromSettings.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.FromSettings.cs @@ -10,100 +10,95 @@ public static partial class LMotion /// /// Motion settings /// Created motion builder - public static MotionBuilder Create(MotionSettings settings) => Create(settings); + public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder Create(MotionSettings settings) => Create(settings); + public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder Create(MotionSettings settings) => Create(settings); + public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder Create(MotionSettings settings) => Create(settings); + public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder Create(MotionSettings settings) => Create(settings); + public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder Create(MotionSettings settings) => Create(settings); + public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder Create(MotionSettings settings) => Create(settings); + public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder Create(MotionSettings settings) => Create(settings); + public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder Create(MotionSettings settings) => Create(settings); + public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder Create(MotionSettings settings) => Create(settings); + public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); /// /// Create a builder for building motion. /// /// The type of value to animate + /// The type of vectorized value for internal processing /// The type of special parameters given to the motion entity - /// The type of adapter that support value animation + /// The type of animation specification /// Motion settings /// Created motion builder - public static MotionBuilder Create(MotionSettings settings) + public static MotionBuilder Create(MotionSettings settings) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { var buffer = MotionBuilderBuffer.Rent(); buffer.StartValue = settings.StartValue; buffer.EndValue = settings.EndValue; - buffer.Duration = settings.Duration; buffer.Options = settings.Options; - buffer.Ease = settings.Ease; - buffer.AnimationCurve = settings.CustomEaseCurve; - buffer.Delay = settings.Delay; - buffer.DelayType = settings.DelayType; - buffer.Loops = settings.Loops; - buffer.LoopType = settings.LoopType; buffer.CancelOnError = settings.CancelOnError; buffer.SkipValuesDuringDelay = settings.SkipValuesDuringDelay; buffer.ImmediateBind = settings.ImmediateBind; buffer.Scheduler = settings.Scheduler; - return new MotionBuilder(buffer); + return new MotionBuilder(buffer); } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.cs b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.cs index 385eec8f..6b52d0c9 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.cs @@ -15,7 +15,19 @@ public static partial class LMotion /// End value /// Duration /// Created motion builder - public static MotionBuilder Create(float from, float to, float duration) => Create(from, to, duration); + public static MotionBuilder> Create(float from, float to, float duration) + { + var options = new TweenOption + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear + }; + return Create>(from, to, options); + } /// /// Create a builder for building motion. @@ -24,7 +36,19 @@ public static partial class LMotion /// End value /// Duration /// Created motion builder - public static MotionBuilder Create(double from, double to, float duration) => Create(from, to, duration); + public static MotionBuilder> Create(double from, double to, float duration) + { + var options = new TweenOption + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear + }; + return Create>(from, to, options); + } /// /// Create a builder for building motion. @@ -33,7 +57,19 @@ public static partial class LMotion /// End value /// Duration /// Created motion builder - public static MotionBuilder Create(int from, int to, float duration) => Create(from, to, duration); + public static MotionBuilder> Create(int from, int to, float duration) + { + var options = new IntegerOptions + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear + }; + return Create>(from, to, options); + } /// /// Create a builder for building motion. @@ -42,7 +78,19 @@ public static partial class LMotion /// End value /// Duration /// Created motion builder - public static MotionBuilder Create(long from, long to, float duration) => Create(from, to, duration); + public static MotionBuilder> Create(long from, long to, float duration) + { + var options = new IntegerOptions + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear + }; + return Create>(from, to, options); + } /// /// Create a builder for building motion. @@ -51,7 +99,19 @@ public static partial class LMotion /// End value /// Duration /// Created motion builder - public static MotionBuilder Create(Vector2 from, Vector2 to, float duration) => Create(from, to, duration); + public static MotionBuilder> Create(Vector2 from, Vector2 to, float duration) + { + var options = new TweenOption + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear + }; + return Create>(from, to, options); + } /// /// Create a builder for building motion. @@ -60,7 +120,19 @@ public static partial class LMotion /// End value /// Duration /// Created motion builder - public static MotionBuilder Create(Vector3 from, Vector3 to, float duration) => Create(from, to, duration); + public static MotionBuilder> Create(Vector3 from, Vector3 to, float duration) + { + var options = new TweenOption + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear + }; + return Create>(from, to, options); + } /// /// Create a builder for building motion. @@ -69,7 +141,19 @@ public static partial class LMotion /// End value /// Duration /// Created motion builder - public static MotionBuilder Create(Vector4 from, Vector4 to, float duration) => Create(from, to, duration); + public static MotionBuilder> Create(Vector4 from, Vector4 to, float duration) + { + var options = new TweenOption + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear + }; + return Create>(from, to, options); + } /// /// Create a builder for building motion. @@ -78,7 +162,19 @@ public static partial class LMotion /// End value /// Duration /// Created motion builder - public static MotionBuilder Create(Quaternion from, Quaternion to, float duration) => Create(from, to, duration); + public static MotionBuilder> Create(Quaternion from, Quaternion to, float duration) + { + var options = new TweenOption + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear + }; + return Create>(from, to, options); + } /// /// Create a builder for building motion. @@ -87,7 +183,19 @@ public static partial class LMotion /// End value /// Duration /// Created motion builder - public static MotionBuilder Create(Color from, Color to, float duration) => Create(from, to, duration); + public static MotionBuilder> Create(Color from, Color to, float duration) + { + var options = new TweenOption + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear + }; + return Create>(from, to, options); + } /// /// Create a builder for building motion. @@ -96,28 +204,56 @@ public static partial class LMotion /// End value /// Duration /// Created motion builder - public static MotionBuilder Create(Rect from, Rect to, float duration) => Create(from, to, duration); + public static MotionBuilder> Create(Rect from, Rect to, float duration) + { + var options = new TweenOption + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear + }; + return Create>(from, to, options); + } + /// - /// Create a builder for building motion. + /// Create a builder for building motion with explicit animation specification. /// /// The type of value to animate + /// The type of vectorized value for internal processing /// The type of special parameters given to the motion entity - /// The type of adapter that support value animation + /// The type of animation specification /// Start value /// End value - /// Duration + /// Animation options /// Created motion builder - public static MotionBuilder Create(in TValue from, in TValue to, float duration) + // public static MotionBuilder Create(in TValue from, in TValue to, TOptions options) + // where TValue : unmanaged + // where VValue : unmanaged + // where TOptions : unmanaged, IMotionOptions + // where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + // { + // var buffer = MotionBuilderBuffer.Rent(); + // buffer.StartValue = from; + // buffer.EndValue = to; + // buffer.Options = options; + // return new MotionBuilder(buffer); + // } + + public static MotionBuilder Create(in TValue from, in TValue to, TOptions options) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { var buffer = MotionBuilderBuffer.Rent(); buffer.StartValue = from; buffer.EndValue = to; - buffer.Duration = duration; - return new MotionBuilder(buffer); + buffer.Options = options; + return new MotionBuilder(buffer); } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.CreateString.cs b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.CreateString.cs index 5d7a0b14..e68ce61b 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.CreateString.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.CreateString.cs @@ -17,9 +17,18 @@ public static class String /// End value /// Duration /// Created motion builder - public static MotionBuilder Create32Bytes(in FixedString32Bytes from, in FixedString32Bytes to, float duration) + public static MotionBuilder> Create32Bytes(in FixedString32Bytes from, in FixedString32Bytes to, float duration) { - return Create(from, to, duration); + var options = new StringOptions + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear + }; + return Create>(from, to, options); } /// @@ -29,9 +38,18 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder Create64Bytes(in FixedString64Bytes from, in FixedString64Bytes to, float duration) + public static MotionBuilder> Create64Bytes(in FixedString64Bytes from, in FixedString64Bytes to, float duration) { - return Create(from, to, duration); + var options = new StringOptions + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear + }; + return Create>(from, to, options); } /// @@ -41,9 +59,18 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder Create128Bytes(in FixedString128Bytes from, in FixedString128Bytes to, float duration) + public static MotionBuilder> Create128Bytes(in FixedString128Bytes from, in FixedString128Bytes to, float duration) { - return Create(from, to, duration); + var options = new StringOptions + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear + }; + return Create>(from, to, options); } /// @@ -53,9 +80,18 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder Create512Bytes(in FixedString512Bytes from, in FixedString512Bytes to, float duration) + public static MotionBuilder> Create512Bytes(in FixedString512Bytes from, in FixedString512Bytes to, float duration) { - return Create(from, to, duration); + var options = new StringOptions + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear + }; + return Create>(from, to, options); } /// @@ -65,9 +101,18 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder Create4096Bytes(in FixedString4096Bytes from, in FixedString4096Bytes to, float duration) + public static MotionBuilder> Create4096Bytes(in FixedString4096Bytes from, in FixedString4096Bytes to, float duration) { - return Create(from, to, duration); + var options = new StringOptions + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear + }; + return Create>(from, to, options); } } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Punch.cs b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Punch.cs index 105e1126..ba0ad73b 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Punch.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Punch.cs @@ -17,10 +17,20 @@ public static class Punch /// Vibration strength /// Duration /// Created motion builder - public static MotionBuilder Create(float startValue, float strength, float duration) + public static MotionBuilder> Create(float startValue, float strength, float duration) { - return Create(startValue, strength, duration) - .WithOptions(PunchOptions.Default); + var options = new PunchOptions + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear, + Frequency = 10, + DampingRatio = 1f + }; + return Create>(startValue, startValue, options); } /// @@ -30,10 +40,20 @@ public static MotionBuilder Create /// Vibration strength /// Duration /// Created motion builder - public static MotionBuilder Create(Vector2 startValue, Vector2 strength, float duration) + public static MotionBuilder> Create(Vector2 startValue, Vector2 strength, float duration) { - return Create(startValue, strength, duration) - .WithOptions(PunchOptions.Default); + var options = new PunchOptions + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear, + Frequency = 10, + DampingRatio = 1f + }; + return Create>(startValue, startValue, options); } /// @@ -43,10 +63,20 @@ public static MotionBuilder Cr /// Vibration strength /// Duration /// Created motion builder - public static MotionBuilder Create(Vector3 startValue, Vector3 strength, float duration) + public static MotionBuilder> Create(Vector3 startValue, Vector3 strength, float duration) { - return Create(startValue, strength, duration) - .WithOptions(PunchOptions.Default); + var options = new PunchOptions + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear, + Frequency = 10, + DampingRatio = 1f + }; + return Create>(startValue, startValue, options); } } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Shake.cs b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Shake.cs index 0ce44df3..b3aac815 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Shake.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Shake.cs @@ -17,10 +17,20 @@ public static class Shake /// Vibration strength /// Duration /// Created motion builder - public static MotionBuilder Create(float startValue, float strength, float duration) + public static MotionBuilder> Create(float startValue, float strength, float duration) { - return Create(startValue, strength, duration) - .WithOptions(ShakeOptions.Default); + var options = new ShakeOptions + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear, + Frequency = 10, + DampingRatio = 1f + }; + return Create>(startValue, startValue, options); } /// @@ -30,10 +40,20 @@ public static MotionBuilder Create /// Vibration strength /// Duration /// Created motion builder - public static MotionBuilder Create(Vector2 startValue, Vector2 strength, float duration) + public static MotionBuilder> Create(Vector2 startValue, Vector2 strength, float duration) { - return Create(startValue, strength, duration) - .WithOptions(ShakeOptions.Default); + var options = new ShakeOptions + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear, + Frequency = 10, + DampingRatio = 1f + }; + return Create>(startValue, startValue, options); } /// @@ -43,10 +63,20 @@ public static MotionBuilder Cr /// Vibration strength /// Duration /// Created motion builder - public static MotionBuilder Create(Vector3 startValue, Vector3 strength, float duration) + public static MotionBuilder> Create(Vector3 startValue, Vector3 strength, float duration) { - return Create(startValue, strength, duration) - .WithOptions(ShakeOptions.Default); + var options = new ShakeOptions + { + DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), + Loops = 1, + DelayNanos = 0, + DelayType = DelayType.FirstLoop, + LoopType = LoopType.Restart, + Ease = Ease.Linear, + Frequency = 10, + DampingRatio = 1f + }; + return Create>(startValue, startValue, options); } } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/ManualMotionDispatcher.cs b/src/LitMotion/Assets/LitMotion/Runtime/ManualMotionDispatcher.cs index e7708667..c207ab07 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/ManualMotionDispatcher.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/ManualMotionDispatcher.cs @@ -12,12 +12,13 @@ public ManualMotionDispatcherScheduler(ManualMotionDispatcher dispatcher) this.dispatcher = dispatcher; } - public MotionHandle Schedule(ref MotionBuilder builder) + public MotionHandle Schedule(ref MotionBuilder builder) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { - return dispatcher.GetOrCreateRunner().Storage.Create(ref builder); + return dispatcher.GetOrCreateRunner().Storage.Create(ref builder); } } @@ -62,13 +63,14 @@ public double Time /// Ensures the storage capacity until it reaches at least capacity. /// /// The minimum capacity to ensure - public void EnsureStorageCapacity(int capacity) + public void EnsureStorageCapacity(int capacity) where TValue : unmanaged + where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { - GetOrCreateRunner().Storage.EnsureCapacity(capacity); + GetOrCreateRunner().Storage.EnsureCapacity(capacity); } /// @@ -98,22 +100,23 @@ public void Reset() time = 0; } - internal UpdateRunner GetOrCreateRunner() + internal UpdateRunner GetOrCreateRunner() where TValue : unmanaged + where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { - var key = typeof((TValue, TOptions, TAdapter)); + var key = typeof((TValue, TOptions, TAnimationSpec)); if (!runners.TryGetValue(key, out var runner)) { - var storage = new MotionStorage(MotionManager.MotionTypeCount); + var storage = new MotionStorage(MotionManager.MotionTypeCount); MotionManager.Register(storage); - runner = new UpdateRunner(storage, 0, 0, 0); + runner = new UpdateRunner(storage, 0, 0, 0); runners.Add(key, runner); } - return (UpdateRunner)runner; + return (UpdateRunner)runner; } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilder.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilder.cs index 2cc31b7c..c58f7152 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilder.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilder.cs @@ -5,6 +5,8 @@ using System; using System.Runtime.CompilerServices; using UnityEngine; +using Unity.Collections; +using LitMotion.Collections; namespace LitMotion { @@ -39,13 +41,7 @@ public static void Return(MotionBuilderBuffer buffer) buffer.EndValue = default; buffer.Options = default; - buffer.Duration = default; - buffer.Ease = default; - buffer.AnimationCurve = default; buffer.TimeKind = default; - buffer.Delay = default; - buffer.Loops = 1; - buffer.LoopType = default; buffer.State0 = default; buffer.State1 = default; @@ -78,13 +74,7 @@ public static void Return(MotionBuilderBuffer buffer) public TValue StartValue; public TValue EndValue; public TOptions Options; - public float Duration; - public Ease Ease; public MotionTimeKind TimeKind; - public float Delay; - public int Loops = 1; - public DelayType DelayType; - public LoopType LoopType; public bool CancelOnError; public bool SkipValuesDuringDelay; public bool ImmediateBind = true; @@ -97,24 +87,24 @@ public static void Return(MotionBuilderBuffer buffer) public Action OnLoopCompleteAction; public Action OnCompleteAction; public Action OnCancelAction; - public AnimationCurve AnimationCurve; public IMotionScheduler Scheduler; #if LITMOTION_DEBUG public string DebugName; #endif } - /// /// Supports construction, scheduling, and binding of motion entities. /// /// The type of value to animate + /// The type of vectorized value for internal processing /// The type of special parameters given to the motion data - /// The type of adapter that support value animation - public struct MotionBuilder : IDisposable + /// The type of animation specification + public struct MotionBuilder : IDisposable where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged,ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { internal MotionBuilder(MotionBuilderBuffer buffer) { @@ -131,11 +121,11 @@ internal MotionBuilder(MotionBuilderBuffer buffer) /// The type of easing /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithEase(Ease ease) + public readonly MotionBuilder WithEase(Ease ease) { CheckEaseType(ease); CheckBuffer(); - buffer.Ease = ease; + buffer.Options.Ease = ease; return this; } @@ -145,11 +135,15 @@ public readonly MotionBuilder WithEase(Ease ease) /// Animation curve /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithEase(AnimationCurve animationCurve) + public readonly MotionBuilder WithEase(AnimationCurve animationCurve) { CheckBuffer(); - buffer.AnimationCurve = animationCurve; - buffer.Ease = Ease.CustomAnimationCurve; +#if LITMOTION_COLLECTIONS_2_0_OR_NEWER + buffer.Options.AnimationCurve = new NativeAnimationCurve(animationCurve, MotionDispatcher.Allocator.Allocator.Handle); +#else + buffer.Options.AnimationCurve = new UnsafeAnimationCurve(buffer.AnimationCurve, MotionDispatcher.Allocator.Allocator.Handle); +#endif + buffer.Options.Ease = Ease.CustomAnimationCurve; return this; } @@ -161,11 +155,11 @@ public readonly MotionBuilder WithEase(AnimationCurv /// Whether to skip updating values during the delay time /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithDelay(float delay, DelayType delayType = DelayType.FirstLoop, bool skipValuesDuringDelay = true) + public readonly MotionBuilder WithDelay(float delay, DelayType delayType = DelayType.FirstLoop, bool skipValuesDuringDelay = true) { CheckBuffer(); - buffer.Delay = delay; - buffer.DelayType = delayType; + buffer.Options.DelayNanos = (long)(delay * 1_000_000_000); // 转换为纳秒 + buffer.Options.DelayType = delayType; buffer.SkipValuesDuringDelay = skipValuesDuringDelay; return this; } @@ -177,11 +171,11 @@ public readonly MotionBuilder WithDelay(float delay, /// Behavior at the end of each loop /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithLoops(int loops, LoopType loopType = LoopType.Restart) + public readonly MotionBuilder WithLoops(int loops, LoopType loopType = LoopType.Restart) { CheckBuffer(); - buffer.Loops = loops; - buffer.LoopType = loopType; + buffer.Options.Loops = loops; + buffer.Options.LoopType = loopType; return this; } @@ -191,7 +185,7 @@ public readonly MotionBuilder WithLoops(int loops, L /// Option value to specify /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithOptions(TOptions options) + public readonly MotionBuilder WithOptions(TOptions options) { CheckBuffer(); buffer.Options = options; @@ -204,7 +198,7 @@ public readonly MotionBuilder WithOptions(TOptions o /// Callback when canceled /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithOnCancel(Action callback) + public readonly MotionBuilder WithOnCancel(Action callback) { CheckBuffer(); buffer.OnCancelAction += callback; @@ -217,7 +211,7 @@ public readonly MotionBuilder WithOnCancel(Action ca /// Callback when playback ends /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithOnComplete(Action callback) + public readonly MotionBuilder WithOnComplete(Action callback) { CheckBuffer(); buffer.OnCompleteAction += callback; @@ -230,7 +224,7 @@ public readonly MotionBuilder WithOnComplete(Action /// Callback to be performed when each loop finishes. /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithOnLoopComplete(Action callback) + public readonly MotionBuilder WithOnLoopComplete(Action callback) { CheckBuffer(); buffer.OnLoopCompleteAction += callback; @@ -243,7 +237,7 @@ public readonly MotionBuilder WithOnLoopComplete(Act /// Whether to cancel on error /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithCancelOnError(bool cancelOnError = true) + public readonly MotionBuilder WithCancelOnError(bool cancelOnError = true) { CheckBuffer(); buffer.CancelOnError = cancelOnError; @@ -256,7 +250,7 @@ public readonly MotionBuilder WithCancelOnError(bool /// Whether to bind on sheduling /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithImmediateBind(bool immediateBind = true) + public readonly MotionBuilder WithImmediateBind(bool immediateBind = true) { CheckBuffer(); buffer.ImmediateBind = immediateBind; @@ -269,7 +263,7 @@ public readonly MotionBuilder WithImmediateBind(bool /// Scheduler /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithScheduler(IMotionScheduler scheduler) + public readonly MotionBuilder WithScheduler(IMotionScheduler scheduler) { CheckBuffer(); buffer.Scheduler = scheduler; @@ -282,7 +276,7 @@ public readonly MotionBuilder WithScheduler(IMotionS /// Debug name /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithDebugName(string debugName) + public readonly MotionBuilder WithDebugName(string debugName) { #if LITMOTION_DEBUG CheckBuffer(); @@ -384,14 +378,7 @@ public readonly MotionSettings ToMotionSettings() { StartValue = buffer.StartValue, EndValue = buffer.EndValue, - Duration = buffer.Duration, Options = buffer.Options, - Ease = buffer.Ease, - CustomEaseCurve = buffer.AnimationCurve, - Delay = buffer.Delay, - DelayType = buffer.DelayType, - Loops = buffer.Loops, - LoopType = buffer.LoopType, CancelOnError = buffer.CancelOnError, SkipValuesDuringDelay = buffer.SkipValuesDuringDelay, ImmediateBind = buffer.ImmediateBind, @@ -409,11 +396,12 @@ internal MotionHandle ScheduleMotion() #if UNITY_EDITOR if (!UnityEditor.EditorApplication.isPlaying) { - handle = EditorMotionDispatcher.Schedule(ref this); + // Use default scheduler interface to avoid generic parameter inference issues + handle = MotionScheduler.DefaultScheduler.Schedule(ref this); } else if (MotionScheduler.DefaultScheduler == MotionScheduler.Update) // avoid virtual method call { - handle = MotionDispatcher.Schedule(ref this, PlayerLoopTiming.Update); + handle = MotionScheduler.Update.Schedule(ref this); } else { @@ -422,7 +410,7 @@ internal MotionHandle ScheduleMotion() #else if (MotionScheduler.DefaultScheduler == MotionScheduler.Update) // avoid virtual method call { - handle = MotionDispatcher.Schedule(ref this, PlayerLoopTiming.Update); + handle = MotionScheduler.Update.Schedule(ref this); } else { diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilderExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilderExtensions.cs index e93a0d60..8b91d00e 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilderExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilderExtensions.cs @@ -15,10 +15,11 @@ public static class MotionBuilderExtensions /// Motion state /// Action that handles binding /// Handle of the created motion data. - public unsafe static MotionHandle Bind(this MotionBuilder builder, TState state, Action action) + public unsafe static MotionHandle Bind(this MotionBuilder builder, TState state, Action action) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec where TState : struct { return builder.Bind(Box.Create(state), action, (value, state, action) => action(value, state.Value)); @@ -28,13 +29,15 @@ public unsafe static MotionHandle Bind(this /// Specifies the rounding format for decimal values when animating integer types. /// /// The type of value to animate - /// The type of adapter that support value animation + /// The type of vectorized value for internal processing + /// The type of animation specification /// This builder /// Rounding mode /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithRoundingMode(this MotionBuilder builder, RoundingMode roundingMode) + public static MotionBuilder WithRoundingMode(this MotionBuilder builder, RoundingMode roundingMode) where TValue : unmanaged - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { var options = builder.buffer.Options; options.RoundingMode = roundingMode; @@ -46,13 +49,15 @@ public static MotionBuilder WithRoundingMode /// The type of value to animate - /// The type of adapter that support value animation + /// The type of vectorized value for internal processing + /// The type of animation specification /// This builder /// Frequency /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithFrequency(this MotionBuilder builder, int frequency) + public static MotionBuilder WithFrequency(this MotionBuilder builder, int frequency) where TValue : unmanaged - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { var options = builder.buffer.Options; options.Frequency = frequency; @@ -64,13 +69,15 @@ public static MotionBuilder WithFrequency /// The type of value to animate - /// The type of adapter that support value animation + /// The type of vectorized value for internal processing + /// The type of animation specification /// This builder /// Damping ratio /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithDampingRatio(this MotionBuilder builder, float dampingRatio) + public static MotionBuilder WithDampingRatio(this MotionBuilder builder, float dampingRatio) where TValue : unmanaged - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { var options = builder.buffer.Options; options.DampingRatio = dampingRatio; @@ -82,13 +89,15 @@ public static MotionBuilder WithDampingRatio /// The type of value to animate - /// The type of adapter that support value animation + /// The type of vectorized value for internal processing + /// The type of animation specification /// This builder /// Frequency /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithFrequency(this MotionBuilder builder, int frequency) + public static MotionBuilder WithFrequency(this MotionBuilder builder, int frequency) where TValue : unmanaged - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { var options = builder.buffer.Options; options.Frequency = frequency; @@ -100,13 +109,15 @@ public static MotionBuilder WithFrequency /// The type of value to animate - /// The type of adapter that support value animation + /// The type of vectorized value for internal processing + /// The type of animation specification /// This builder /// Damping ratio /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithDampingRatio(this MotionBuilder builder, float dampingRatio) + public static MotionBuilder WithDampingRatio(this MotionBuilder builder, float dampingRatio) where TValue : unmanaged - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { var options = builder.buffer.Options; options.DampingRatio = dampingRatio; @@ -118,13 +129,15 @@ public static MotionBuilder WithDampingRatio /// The type of value to animate - /// The type of adapter that support value animation + /// The type of vectorized value for internal processing + /// The type of animation specification /// This builder /// Random number seed /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithRandomSeed(this MotionBuilder builder, uint seed) + public static MotionBuilder WithRandomSeed(this MotionBuilder builder, uint seed) where TValue : unmanaged - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { var options = builder.buffer.Options; options.RandomSeed = seed; @@ -136,13 +149,15 @@ public static MotionBuilder WithRandomSeed /// The type of value to animate - /// The type of adapter that support value animation + /// The type of vectorized value for internal processing + /// The type of animation specification /// This builder /// Whether to support Rich Text tags /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithRichText(this MotionBuilder builder, bool richTextEnabled = true) + public static MotionBuilder WithRichText(this MotionBuilder builder, bool richTextEnabled = true) where TValue : unmanaged - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { var options = builder.buffer.Options; options.RichTextEnabled = richTextEnabled; @@ -154,13 +169,15 @@ public static MotionBuilder WithRichText /// The type of value to animate - /// The type of adapter that support value animation + /// The type of vectorized value for internal processing + /// The type of animation specification /// This builder /// Rrandom number seed /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithRandomSeed(this MotionBuilder builder, uint seed) + public static MotionBuilder WithRandomSeed(this MotionBuilder builder, uint seed) where TValue : unmanaged - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { var options = builder.buffer.Options; options.RandomSeed = seed; @@ -172,13 +189,15 @@ public static MotionBuilder WithRandomSeed /// The type of value to animate - /// The type of adapter that support value animation + /// The type of vectorized value for internal processing + /// The type of animation specification /// This builder /// Type of characters used for blank padding /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithScrambleChars(this MotionBuilder builder, ScrambleMode scrambleMode) + public static MotionBuilder WithScrambleChars(this MotionBuilder builder, ScrambleMode scrambleMode) where TValue : unmanaged - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { if (scrambleMode == ScrambleMode.Custom) throw new ArgumentException("ScrambleMode.Custom cannot be specified explicitly. Use WithScrambleMode(FixedString64Bytes) instead."); @@ -193,13 +212,15 @@ public static MotionBuilder WithScrambleChars /// The type of value to animate - /// The type of adapter that support value animation + /// The type of vectorized value for internal processing + /// The type of animation specification /// This builder /// Characters used for blank padding /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithScrambleChars(this MotionBuilder builder, FixedString64Bytes customScrambleChars) + public static MotionBuilder WithScrambleChars(this MotionBuilder builder, FixedString64Bytes customScrambleChars) where TValue : unmanaged - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { var options = builder.buffer.Options; options.ScrambleMode = ScrambleMode.Custom; diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionDebugger.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionDebugger.cs index 75717d4d..19ecdf7c 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionDebugger.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionDebugger.cs @@ -84,7 +84,7 @@ void OnComplete() MotionDispatcher.GetUnhandledExceptionHandler()?.Invoke(ex); } - if (Handle.IsActive() && !MotionManager.GetDataRef(Handle, false).State.IsPreserved) + if (Handle.IsActive() && !MotionManager.GetStateRef(Handle, false).IsPreserved) { Release(); } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionDispatcher.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionDispatcher.cs index 0fb2723d..88cfd17b 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionDispatcher.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionDispatcher.cs @@ -14,21 +14,22 @@ namespace LitMotion /// public static class MotionDispatcher { - static class StorageCache + static class StorageCache where TValue : unmanaged + where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { - public static MotionStorage initialization; - public static MotionStorage earlyUpdate; - public static MotionStorage fixedUpdate; - public static MotionStorage preUpdate; - public static MotionStorage update; - public static MotionStorage preLateUpdate; - public static MotionStorage postLateUpdate; - public static MotionStorage timeUpdate; + public static MotionStorage initialization; + public static MotionStorage earlyUpdate; + public static MotionStorage fixedUpdate; + public static MotionStorage preUpdate; + public static MotionStorage update; + public static MotionStorage preLateUpdate; + public static MotionStorage postLateUpdate; + public static MotionStorage timeUpdate; - public static MotionStorage GetOrCreate(PlayerLoopTiming playerLoopTiming) + public static MotionStorage GetOrCreate(PlayerLoopTiming playerLoopTiming) { return playerLoopTiming switch { @@ -45,32 +46,33 @@ public static MotionStorage GetOrCreate(PlayerLoopTi } [MethodImpl(MethodImplOptions.AggressiveInlining)] - static MotionStorage CreateIfNull(ref MotionStorage storage) + static MotionStorage CreateIfNull(ref MotionStorage storage) { if (storage == null) { - storage = new MotionStorage(MotionManager.MotionTypeCount); + storage = new MotionStorage(MotionManager.MotionTypeCount); MotionManager.Register(storage); } return storage; } } - static class RunnerCache + static class RunnerCache where TValue : unmanaged + where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { - public static UpdateRunner initialization; - public static UpdateRunner earlyUpdate; - public static UpdateRunner fixedUpdate; - public static UpdateRunner preUpdate; - public static UpdateRunner update; - public static UpdateRunner preLateUpdate; - public static UpdateRunner postLateUpdate; - public static UpdateRunner timeUpdate; + public static UpdateRunner initialization; + public static UpdateRunner earlyUpdate; + public static UpdateRunner fixedUpdate; + public static UpdateRunner preUpdate; + public static UpdateRunner update; + public static UpdateRunner preLateUpdate; + public static UpdateRunner postLateUpdate; + public static UpdateRunner timeUpdate; - public static (UpdateRunner runner, bool isCreated) GetOrCreate(PlayerLoopTiming playerLoopTiming, MotionStorage storage) + public static (UpdateRunner runner, bool isCreated) GetOrCreate(PlayerLoopTiming playerLoopTiming, MotionStorage storage) { return playerLoopTiming switch { @@ -87,17 +89,17 @@ public static (UpdateRunner runner, bool isCreated) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - static (UpdateRunner, bool) CreateIfNull(PlayerLoopTiming playerLoopTiming, ref UpdateRunner runner, MotionStorage storage) + static (UpdateRunner, bool) CreateIfNull(PlayerLoopTiming playerLoopTiming, ref UpdateRunner runner, MotionStorage storage) { if (runner == null) { if (playerLoopTiming == PlayerLoopTiming.FixedUpdate) { - runner = new UpdateRunner(storage, Time.fixedTimeAsDouble, Time.fixedUnscaledTimeAsDouble, Time.realtimeSinceStartupAsDouble); + runner = new UpdateRunner(storage, Time.fixedTimeAsDouble, Time.fixedUnscaledTimeAsDouble, Time.realtimeSinceStartupAsDouble); } else { - runner = new UpdateRunner(storage, Time.timeAsDouble, Time.unscaledTimeAsDouble, Time.realtimeSinceStartupAsDouble); + runner = new UpdateRunner(storage, Time.timeAsDouble, Time.unscaledTimeAsDouble, Time.realtimeSinceStartupAsDouble); } GetRunnerList(playerLoopTiming).Add(runner); return (runner, true); @@ -147,6 +149,23 @@ static ref FastListCore GetRunnerList(PlayerLoopTiming playerLoop static Action unhandledException = DefaultUnhandledExceptionHandler; static readonly PlayerLoopTiming[] playerLoopTimings = (PlayerLoopTiming[])Enum.GetValues(typeof(PlayerLoopTiming)); + static Unity.Collections.AllocatorHelper allocator; + + static bool isCreatedAllocator = false; + + public static Unity.Collections.AllocatorHelper Allocator + { + get + { + if (!isCreatedAllocator) + { + allocator = RewindableAllocatorFactory.CreateAllocator(); + isCreatedAllocator = true; + } + return allocator; + } + } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void Init() { @@ -187,33 +206,40 @@ public static void Clear() span[i].Reset(); } } + if (isCreatedAllocator) + { + allocator.Allocator.Rewind(); + isCreatedAllocator = false; + } } /// /// Ensures the storage capacity until it reaches at least `capacity`. /// /// The minimum capacity to ensure. - public static void EnsureStorageCapacity(int capacity) + public static void EnsureStorageCapacity(int capacity) where TValue : unmanaged + where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { foreach (var playerLoopTiming in playerLoopTimings) { - StorageCache.GetOrCreate(playerLoopTiming).EnsureCapacity(capacity); + StorageCache.GetOrCreate(playerLoopTiming).EnsureCapacity(capacity); } #if UNITY_EDITOR - EditorMotionDispatcher.EnsureStorageCapacity(capacity); + EditorMotionDispatcher.EnsureStorageCapacity(capacity); #endif } - internal static MotionHandle Schedule(ref MotionBuilder builder, PlayerLoopTiming playerLoopTiming) + internal static MotionHandle Schedule(ref MotionBuilder builder, PlayerLoopTiming playerLoopTiming) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { - var storage = StorageCache.GetOrCreate(playerLoopTiming); - RunnerCache.GetOrCreate(playerLoopTiming, storage); + var storage = StorageCache.GetOrCreate(playerLoopTiming); + RunnerCache.GetOrCreate(playerLoopTiming, storage); return storage.Create(ref builder); } @@ -237,19 +263,20 @@ internal static void Update(PlayerLoopTiming playerLoopTiming) #if UNITY_EDITOR internal static class EditorMotionDispatcher { - static class Cache + static class Cache where TValue : unmanaged + where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { - static MotionStorage storage; - static UpdateRunner updateRunner; + static MotionStorage storage; + static UpdateRunner updateRunner; - public static MotionStorage GetOrCreateStorage() + public static MotionStorage GetOrCreateStorage() { if (storage == null) { - storage = new MotionStorage(MotionManager.MotionTypeCount); + storage = new MotionStorage(MotionManager.MotionTypeCount); MotionManager.Register(storage); } return storage; @@ -260,7 +287,7 @@ public static void InitUpdateRunner() if (updateRunner == null) { var time = EditorApplication.timeSinceStartup; - updateRunner = new UpdateRunner(storage, time, time, time); + updateRunner = new UpdateRunner(storage, time, time, time); updateRunners.Add(updateRunner); } } @@ -268,22 +295,24 @@ public static void InitUpdateRunner() static FastListCore updateRunners; - public static MotionHandle Schedule(ref MotionBuilder builder) + public static MotionHandle Schedule(ref MotionBuilder builder) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { - var storage = Cache.GetOrCreateStorage(); - Cache.InitUpdateRunner(); + var storage = Cache.GetOrCreateStorage(); + Cache.InitUpdateRunner(); return storage.Create(ref builder); } - public static void EnsureStorageCapacity(int capacity) + public static void EnsureStorageCapacity(int capacity) where TValue : unmanaged + where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { - Cache.GetOrCreateStorage().EnsureCapacity(capacity); + Cache.GetOrCreateStorage().EnsureCapacity(capacity); } [InitializeOnLoadMethod] diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs index 46dbd84b..17b09473 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs @@ -34,36 +34,45 @@ public readonly double Time { get { - return MotionManager.GetDataRef(this, false).State.Time; + return MotionManager.GetStateRef(this, false).Time; } set { MotionManager.SetTime(this, value); } } - - /// - /// The delay of the motion - /// - public readonly float Delay - { - get - { - return MotionManager.GetDataRef(this, false).Parameters.Delay; - } - } - - /// - /// The duration of the motion - /// - public readonly float Duration + //todo + public readonly bool IsInfinite { get { - return MotionManager.GetDataRef(this, false).Parameters.Duration; + //return MotionManager.GetDataRef(this, false).IsInfinite; + return false; } } - + //todo + // /// + // /// The delay of the motion + // /// + // public readonly float Delay + // { + // get + // { + // return MotionManager.GetDataRef(this, false).Parameters.Delay; + // } + // } + //todo + // /// + // /// The duration of the motion + // /// + // public readonly float Duration + // { + // get + // { + // return MotionManager.GetDataRef(this, false).Parameters.Duration; + // } + // } + //todo /// /// The total duration of the motion /// @@ -71,20 +80,21 @@ public readonly double TotalDuration { get { - return MotionManager.GetDataRef(this, false).Parameters.TotalDuration; - } - } - - /// - /// The number of loops - /// - public readonly int Loops - { - get - { - return MotionManager.GetDataRef(this, false).Parameters.Loops; + //return MotionManager.GetDataRef(this, false).GetDuration(); + return 1; } } + //todo + // /// + // /// The number of loops + // /// + // public readonly int Loops + // { + // get + // { + // return MotionManager.GetDataRef(this, false).Parameters.Loops; + // } + // } /// /// The number of loops completed @@ -93,7 +103,7 @@ public readonly int CompletedLoops { get { - return MotionManager.GetDataRef(this).State.CompletedLoops; + return MotionManager.GetStateRef(this).CompletedLoops; } } @@ -104,11 +114,11 @@ public readonly float PlaybackSpeed { get { - return MotionManager.GetDataRef(this).State.PlaybackSpeed; + return MotionManager.GetStateRef(this).PlaybackSpeed; } set { - MotionManager.GetDataRef(this).State.PlaybackSpeed = value; + MotionManager.GetStateRef(this).PlaybackSpeed = value; } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionHandleExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionHandleExtensions.cs index 6fd8d632..57c45102 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionHandleExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionHandleExtensions.cs @@ -62,7 +62,7 @@ public static string GetDebugName(this MotionHandle handle) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static MotionHandle Preserve(this MotionHandle handle) { - MotionManager.GetDataRef(handle).State.IsPreserved = true; + MotionManager.GetStateRef(handle).IsPreserved = true; return handle; } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceBuilder.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceBuilder.cs index e4afd2ee..69cfc32b 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceBuilder.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceBuilder.cs @@ -76,7 +76,7 @@ public void WithEase(Ease ease) this.ease = ease; } - public MotionHandle Schedule(Action> configuration) + public MotionHandle Schedule(Action>> configuration) { var source = MotionSequenceSource.Rent(); var builder = LMotion.Create(0.0, duration, (float)duration) @@ -170,7 +170,7 @@ public MotionHandle Run() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public MotionHandle Run(Action> configuration) + public MotionHandle Run(Action>> configuration) { CheckIsDisposed(); var handle = source.Schedule(configuration); diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceSource.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceSource.cs index 022d0bfd..0cad4e6f 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceSource.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceSource.cs @@ -109,7 +109,7 @@ public double Time void OnComplete() { if (!handle.IsActive()) return; - if (MotionManager.GetDataRef(handle, false).State.IsPreserved) return; + if (MotionManager.GetStateRef(handle, false).IsPreserved) return; Return(this); } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs index f61a4b2b..e1c3bf30 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs @@ -9,16 +9,18 @@ namespace LitMotion /// /// A job that updates the status of the motion data and outputs the current value. /// - /// The type of value to animate + /// The type of value to animate (user-facing) + /// The type of vectorized value for internal processing /// The type of special parameters given to the motion data - /// The type of adapter that support value animation + /// The type of vectorized animation specification [BurstCompile] - public unsafe struct MotionUpdateJob : IJobParallelFor + public unsafe struct MotionUpdateJob : IJobParallelFor where TValue : unmanaged + where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { - [NativeDisableUnsafePtrRestriction] internal MotionData* DataPtr; + [NativeDisableUnsafePtrRestriction] internal TargetBasedAnimation* DataPtr; [ReadOnly] public double DeltaTime; [ReadOnly] public double UnscaledDeltaTime; [ReadOnly] public double RealDeltaTime; @@ -26,18 +28,19 @@ public unsafe struct MotionUpdateJob : IJobParallelF [WriteOnly] public NativeList.ParallelWriter CompletedIndexList; [WriteOnly] public NativeArray Output; + [WriteOnly] public NativeArray OutputVelocity; + public void Execute([AssumeRange(0, int.MaxValue)] int index) { var ptr = DataPtr + index; - ref var state = ref ptr->Core.State; - ref var parameters = ref ptr->Core.Parameters; + var state = ptr->Core.State; - if (Hint.Likely(state.Status is MotionStatus.Scheduled or MotionStatus.Delayed or MotionStatus.Playing) || - Hint.Unlikely(state.IsPreserved && state.Status is MotionStatus.Completed)) + if (Hint.Likely(state->Status is MotionStatus.Scheduled or MotionStatus.Delayed or MotionStatus.Playing) || + Hint.Unlikely(state->IsPreserved && state->Status is MotionStatus.Completed)) { - if (Hint.Unlikely(state.IsInSequence)) return; + if (Hint.Unlikely(state->IsInSequence)) return; - var deltaTime = parameters.TimeKind switch + var deltaTime = ptr->Core.TimeKind switch { MotionTimeKind.Time => DeltaTime, MotionTimeKind.UnscaledTime => UnscaledDeltaTime, @@ -45,14 +48,16 @@ public void Execute([AssumeRange(0, int.MaxValue)] int index) _ => default }; - var time = state.Time + deltaTime * state.PlaybackSpeed; - ptr->Update(time, out var result); + var time = state->playTimeNanos + (long)(deltaTime * state->PlaybackSpeed * 1_000_000_000); // Convert to nanoseconds + ptr->GetValueFromNanos(time,out var result); Output[index] = result; + ptr->GetVelocityVectorFromNanos(time,out var velocity); + OutputVelocity[index] = velocity; } - else if ((!state.IsPreserved && state.Status is MotionStatus.Completed) || state.Status is MotionStatus.Canceled) + else if ((!state->IsPreserved && state->Status is MotionStatus.Completed) || state->Status is MotionStatus.Canceled) { CompletedIndexList.AddNoResize(index); - state.Status = MotionStatus.Disposed; + state->Status = MotionStatus.Disposed; } } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/ITweenOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/ITweenOptions.cs new file mode 100644 index 00000000..dd642e2f --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/ITweenOptions.cs @@ -0,0 +1,50 @@ +using System; +using LitMotion.Collections; + +namespace LitMotion +{ + /// + /// Interface for tween animation options that provides common properties for all tween-based animations. + /// + public interface ITweenOptions : IMotionOptions + { + /// + /// Duration of the animation in nanoseconds. + /// + long DurationNanos { get; set; } + + /// + /// Number of loops. Use -1 for infinite loops. + /// + int Loops { get; set; } + + /// + /// Delay before the animation starts in nanoseconds. + /// + long DelayNanos { get; set; } + + /// + /// Type of delay behavior. + /// + DelayType DelayType { get; set; } + + /// + /// Type of loop behavior. + /// + LoopType LoopType { get; set; } + + /// + /// Easing function for the animation. + /// + Ease Ease { get; set; } + + /// + /// Custom animation curve for the easing. + /// + #if LITMOTION_COLLECTIONS_2_0_OR_NEWER + NativeAnimationCurve AnimationCurve { get; set; } + #else + UnsafeAnimationCurve AnimationCurve { get; set; } + #endif + } +} \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/IntegerOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/IntegerOptions.cs index 12b79b87..c575aecb 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/IntegerOptions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/IntegerOptions.cs @@ -1,4 +1,5 @@ using System; +using LitMotion.Collections; namespace LitMotion { @@ -6,13 +7,67 @@ namespace LitMotion /// Options for integer type motion. /// [Serializable] - public struct IntegerOptions : IMotionOptions, IEquatable + public struct IntegerOptions : ITweenOptions, IEquatable { - public RoundingMode RoundingMode; + private TweenOption tweenOptions; + + // IntegerOptions特有的属性 + public RoundingMode RoundingMode { get; set; } + + // ITweenOptions接口实现 - 委托给tweenOptions + public long DurationNanos + { + get => tweenOptions.DurationNanos; + set => tweenOptions.DurationNanos = value; + } + + public int Loops + { + get => tweenOptions.Loops; + set => tweenOptions.Loops = value; + } + + public long DelayNanos + { + get => tweenOptions.DelayNanos; + set => tweenOptions.DelayNanos = value; + } + + public DelayType DelayType + { + get => tweenOptions.DelayType; + set => tweenOptions.DelayType = value; + } + + public LoopType LoopType + { + get => tweenOptions.LoopType; + set => tweenOptions.LoopType = value; + } + + public Ease Ease + { + get => tweenOptions.Ease; + set => tweenOptions.Ease = value; + } + + #if LITMOTION_COLLECTIONS_2_0_OR_NEWER + public NativeAnimationCurve AnimationCurve + { + get => tweenOptions.AnimationCurve; + set => tweenOptions.AnimationCurve = value; + } + #else + public UnsafeAnimationCurve AnimationCurve + { + get => tweenOptions.AnimationCurve; + set => tweenOptions.AnimationCurve = value; + } + #endif public readonly bool Equals(IntegerOptions other) { - return other.RoundingMode == RoundingMode; + return tweenOptions.Equals(other.tweenOptions) && RoundingMode == other.RoundingMode; } public override readonly bool Equals(object obj) @@ -23,7 +78,7 @@ public override readonly bool Equals(object obj) public override readonly int GetHashCode() { - return (int)RoundingMode; + return HashCode.Combine(tweenOptions, RoundingMode); } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/NoOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/NoOptions.cs deleted file mode 100644 index 4c39e400..00000000 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/NoOptions.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; - -namespace LitMotion -{ - /// - /// A type indicating that motion has no special options. Specify in the type argument of MotionAdapter when the option is not required. - /// - [Serializable] - public readonly struct NoOptions : IMotionOptions, IEquatable - { - public bool Equals(NoOptions other) - { - return true; - } - - public override bool Equals(object obj) - { - return obj is NoOptions; - } - - public override int GetHashCode() - { - return 0; - } - } -} \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/NoOptions.cs.meta b/src/LitMotion/Assets/LitMotion/Runtime/Options/NoOptions.cs.meta deleted file mode 100644 index 303f2a82..00000000 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/NoOptions.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3368898326e974eef8d562e993b21645 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/PunchOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/PunchOptions.cs index ba73d67c..4d1af2e8 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/PunchOptions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/PunchOptions.cs @@ -1,4 +1,5 @@ using System; +using LitMotion.Collections; namespace LitMotion { @@ -6,10 +7,64 @@ namespace LitMotion /// Options for punch motion. /// [Serializable] - public struct PunchOptions : IEquatable, IMotionOptions + public struct PunchOptions : ITweenOptions, IEquatable { - public int Frequency; - public float DampingRatio; + private TweenOption tweenOptions; + + // PunchOptions特有的属性 + public int Frequency { get; set; } + public float DampingRatio { get; set; } + + // ITweenOptions接口实现 - 委托给tweenOptions + public long DurationNanos + { + get => tweenOptions.DurationNanos; + set => tweenOptions.DurationNanos = value; + } + + public int Loops + { + get => tweenOptions.Loops; + set => tweenOptions.Loops = value; + } + + public long DelayNanos + { + get => tweenOptions.DelayNanos; + set => tweenOptions.DelayNanos = value; + } + + public DelayType DelayType + { + get => tweenOptions.DelayType; + set => tweenOptions.DelayType = value; + } + + public LoopType LoopType + { + get => tweenOptions.LoopType; + set => tweenOptions.LoopType = value; + } + + public Ease Ease + { + get => tweenOptions.Ease; + set => tweenOptions.Ease = value; + } + + #if LITMOTION_COLLECTIONS_2_0_OR_NEWER + public NativeAnimationCurve AnimationCurve + { + get => tweenOptions.AnimationCurve; + set => tweenOptions.AnimationCurve = value; + } + #else + public UnsafeAnimationCurve AnimationCurve + { + get => tweenOptions.AnimationCurve; + set => tweenOptions.AnimationCurve = value; + } + #endif public static PunchOptions Default { @@ -25,7 +80,9 @@ public static PunchOptions Default public readonly bool Equals(PunchOptions other) { - return other.Frequency == Frequency && other.DampingRatio == DampingRatio; + return tweenOptions.Equals(other.tweenOptions) + && Frequency == other.Frequency + && DampingRatio == other.DampingRatio; } public override readonly bool Equals(object obj) @@ -36,7 +93,7 @@ public override readonly bool Equals(object obj) public override readonly int GetHashCode() { - return HashCode.Combine(Frequency, DampingRatio); + return HashCode.Combine(tweenOptions, Frequency, DampingRatio); } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/ShakeOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/ShakeOptions.cs index 7aa98fa3..5d7a45f5 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/ShakeOptions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/ShakeOptions.cs @@ -1,4 +1,5 @@ using System; +using LitMotion.Collections; namespace LitMotion { @@ -6,11 +7,65 @@ namespace LitMotion /// Options for shake motion. /// [Serializable] - public struct ShakeOptions : IEquatable, IMotionOptions + public struct ShakeOptions : ITweenOptions, IEquatable { - public int Frequency; - public float DampingRatio; - public uint RandomSeed; + private TweenOption tweenOptions; + + // ShakeOptions特有的属性 + public int Frequency { get; set; } + public float DampingRatio { get; set; } + public uint RandomSeed { get; set; } + + // ITweenOptions接口实现 - 委托给tweenOptions + public long DurationNanos + { + get => tweenOptions.DurationNanos; + set => tweenOptions.DurationNanos = value; + } + + public int Loops + { + get => tweenOptions.Loops; + set => tweenOptions.Loops = value; + } + + public long DelayNanos + { + get => tweenOptions.DelayNanos; + set => tweenOptions.DelayNanos = value; + } + + public DelayType DelayType + { + get => tweenOptions.DelayType; + set => tweenOptions.DelayType = value; + } + + public LoopType LoopType + { + get => tweenOptions.LoopType; + set => tweenOptions.LoopType = value; + } + + public Ease Ease + { + get => tweenOptions.Ease; + set => tweenOptions.Ease = value; + } + + #if LITMOTION_COLLECTIONS_2_0_OR_NEWER + public NativeAnimationCurve AnimationCurve + { + get => tweenOptions.AnimationCurve; + set => tweenOptions.AnimationCurve = value; + } + #else + public UnsafeAnimationCurve AnimationCurve + { + get => tweenOptions.AnimationCurve; + set => tweenOptions.AnimationCurve = value; + } + #endif public static ShakeOptions Default { @@ -26,9 +81,10 @@ public static ShakeOptions Default public readonly bool Equals(ShakeOptions other) { - return other.Frequency == Frequency && - other.DampingRatio == DampingRatio && - other.RandomSeed == RandomSeed; + return tweenOptions.Equals(other.tweenOptions) + && Frequency == other.Frequency + && DampingRatio == other.DampingRatio + && RandomSeed == other.RandomSeed; } public override readonly bool Equals(object obj) @@ -39,7 +95,7 @@ public override readonly bool Equals(object obj) public override readonly int GetHashCode() { - return HashCode.Combine(Frequency, DampingRatio, RandomSeed); + return HashCode.Combine(tweenOptions, Frequency, DampingRatio, RandomSeed); } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/StringOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/StringOptions.cs index d197c1d4..a722e178 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/StringOptions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/StringOptions.cs @@ -1,5 +1,6 @@ using System; using Unity.Collections; +using LitMotion.Collections; namespace LitMotion { @@ -38,19 +39,74 @@ public enum ScrambleMode : byte /// Options for string type motion. /// [Serializable] - public struct StringOptions : IMotionOptions, IEquatable + public struct StringOptions : ITweenOptions, IEquatable { - public ScrambleMode ScrambleMode; - public bool RichTextEnabled; - public FixedString64Bytes CustomScrambleChars; - public uint RandomSeed; + private TweenOption tweenOptions; + + // StringOptions特有的属性 + public ScrambleMode ScrambleMode { get; set; } + public bool RichTextEnabled { get; set; } + public FixedString64Bytes CustomScrambleChars { get; set; } + public uint RandomSeed { get; set; } + + // ITweenOptions接口实现 - 委托给tweenOptions + public long DurationNanos + { + get => tweenOptions.DurationNanos; + set => tweenOptions.DurationNanos = value; + } + + public int Loops + { + get => tweenOptions.Loops; + set => tweenOptions.Loops = value; + } + + public long DelayNanos + { + get => tweenOptions.DelayNanos; + set => tweenOptions.DelayNanos = value; + } + + public DelayType DelayType + { + get => tweenOptions.DelayType; + set => tweenOptions.DelayType = value; + } + + public LoopType LoopType + { + get => tweenOptions.LoopType; + set => tweenOptions.LoopType = value; + } + + public Ease Ease + { + get => tweenOptions.Ease; + set => tweenOptions.Ease = value; + } + + #if LITMOTION_COLLECTIONS_2_0_OR_NEWER + public NativeAnimationCurve AnimationCurve + { + get => tweenOptions.AnimationCurve; + set => tweenOptions.AnimationCurve = value; + } + #else + public UnsafeAnimationCurve AnimationCurve + { + get => tweenOptions.AnimationCurve; + set => tweenOptions.AnimationCurve = value; + } + #endif public readonly bool Equals(StringOptions other) { - return other.ScrambleMode == ScrambleMode && - other.RichTextEnabled == RichTextEnabled && - other.CustomScrambleChars == CustomScrambleChars && - other.RandomSeed == RandomSeed; + return tweenOptions.Equals(other.tweenOptions) + && ScrambleMode == other.ScrambleMode + && RichTextEnabled == other.RichTextEnabled + && CustomScrambleChars == other.CustomScrambleChars + && RandomSeed == other.RandomSeed; } public override readonly bool Equals(object obj) @@ -61,7 +117,7 @@ public override readonly bool Equals(object obj) public override readonly int GetHashCode() { - return HashCode.Combine(ScrambleMode, RichTextEnabled, CustomScrambleChars, RandomSeed); + return HashCode.Combine(tweenOptions, ScrambleMode, RichTextEnabled, CustomScrambleChars, RandomSeed); } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/TweenOption.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/TweenOption.cs new file mode 100644 index 00000000..b2b54b0f --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/TweenOption.cs @@ -0,0 +1,46 @@ +using System; +using LitMotion.Collections; + +namespace LitMotion +{ + /// + /// A type indicating that motion has no special options. Specify in the type argument of MotionAdapter when the option is not required. + /// + [Serializable] + public struct TweenOption : ITweenOptions, IEquatable + { + public long DurationNanos { get; set; } + public int Loops { get; set; } + public long DelayNanos { get; set; } + public DelayType DelayType { get; set; } + public LoopType LoopType { get; set; } + public Ease Ease { get; set; } + + #if LITMOTION_COLLECTIONS_2_0_OR_NEWER + public NativeAnimationCurve AnimationCurve { get; set; } + #else + public UnsafeAnimationCurve AnimationCurve { get; set; } + #endif + + public bool Equals(TweenOption other) + { + return DurationNanos.Equals(other.DurationNanos) + && DelayNanos.Equals(other.DelayNanos) + && DelayType == other.DelayType + && Ease == other.Ease + && Loops == other.Loops + && LoopType == other.LoopType + && AnimationCurve.Equals(other.AnimationCurve); + } + + public override bool Equals(object obj) + { + return obj is TweenOption other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine(DurationNanos, DelayNanos, DelayType, Ease, Loops, LoopType); + } + } +} \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Tests/Benchmark/BindBenchmark.cs b/src/LitMotion/Assets/LitMotion/Tests/Benchmark/BindBenchmark.cs index 2c5c9090..11b98f89 100644 --- a/src/LitMotion/Assets/LitMotion/Tests/Benchmark/BindBenchmark.cs +++ b/src/LitMotion/Assets/LitMotion/Tests/Benchmark/BindBenchmark.cs @@ -15,7 +15,7 @@ public class BindBenchmark [OneTimeSetUp] public void OneTimeSetUp() { - MotionDispatcher.EnsureStorageCapacity(64000); + MotionDispatcher.EnsureStorageCapacity>(64000); } [TearDown] diff --git a/src/LitMotion/Assets/LitMotion/Tests/Runtime/ExternalExtensions.cs b/src/LitMotion/Assets/LitMotion/Tests/Runtime/ExternalExtensions.cs index 70b1131f..1591f23f 100644 --- a/src/LitMotion/Assets/LitMotion/Tests/Runtime/ExternalExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Tests/Runtime/ExternalExtensions.cs @@ -3,10 +3,11 @@ static class ExternalExtensions { #if LITMOTION_TEST_R3 - public static R3.Observable ToR3Observable(this MotionBuilder builder) + public static R3.Observable ToR3Observable(this MotionBuilder builder) where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - where TAdapter : unmanaged, IMotionAdapter + where VValue : unmanaged + where TOptions : unmanaged, ITweenOptions + where TAnimationSpec : unmanaged, IVectorizedAnimationSpec { return LitMotionR3Extensions.ToObservable(builder); } diff --git a/src/LitMotion/Assets/LitMotion/Tests/Runtime/MotionSettingsTest.cs b/src/LitMotion/Assets/LitMotion/Tests/Runtime/MotionSettingsTest.cs index 94c3789e..fe5151b8 100644 --- a/src/LitMotion/Assets/LitMotion/Tests/Runtime/MotionSettingsTest.cs +++ b/src/LitMotion/Assets/LitMotion/Tests/Runtime/MotionSettingsTest.cs @@ -11,7 +11,7 @@ public class MotionSettingsTest public IEnumerator Test_Create() { - var settings = new MotionSettings + var settings = new MotionSettings { StartValue = 0f, EndValue = 1f, From 0466a965f43c25977a381b462dff01fe80302ddf Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Thu, 18 Sep 2025 22:14:02 +0800 Subject: [PATCH 17/55] =?UTF-8?q?=E5=BC=B9=E7=B0=A7=E7=BC=93=E5=86=B2?= =?UTF-8?q?=E5=99=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets/LitMotion/Runtime/DamperUtility.cs | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/DamperUtility.cs diff --git a/src/LitMotion/Assets/LitMotion/Runtime/DamperUtility.cs b/src/LitMotion/Assets/LitMotion/Runtime/DamperUtility.cs new file mode 100644 index 00000000..cd85da35 --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/DamperUtility.cs @@ -0,0 +1,190 @@ +using System; +namespace LitMotion +{ + //https://github.com/orangeduck/Spring-It-On + /// + /// ṩֵʵóࡣ + /// + public static class DamperUtility + { + /// + /// ٽ + /// + /// + /// + /// + /// + /// + /// + public static double SimpleSpringDamperImplicit( + double startValue, + ref double velocity, + double targetValue, + double halfLife, + double deltaTime) + { + double y = HalfLifeToDamping(halfLife) / 2.0d; + double j0 = startValue - targetValue; + double j1 = velocity + j0 * y; + double eydt = FastNegExp(y * deltaTime); + + startValue = eydt * (j0 + j1 * deltaTime) + targetValue; + velocity = eydt * (velocity - j1 * y * deltaTime); + return startValue; + } + public static double VelocitySpringDamperImplicit( + double startValue, + ref double velocity, + ref double xi, + double targetValue, + double targetVelocity, + double halfLife, + double deltaTime, + double apprehension = 2.0d) + { + double x_diff = ((targetValue - xi) > 0.0d ? 1.0d : -1.0d) * targetVelocity; + + double t_goal_future = deltaTime + apprehension * halfLife; + double targetValue_future = Math.Abs(targetValue - xi) > t_goal_future * targetVelocity ? + xi + x_diff * t_goal_future : targetValue; + + double result = SimpleSpringDamperImplicit(startValue, ref velocity, targetValue_future, halfLife, deltaTime); + + xi = Math.Abs(targetValue - xi) > deltaTime * targetVelocity ? xi + x_diff * deltaTime : targetValue; + return result; + } + + public static double TimedSpringDamperImplicit( + double startValue, + ref double Velocity, + ref double xi, + double targetValue, + double targetTime, + double halfLife, + double deltaTime, + double apprehension = 2.0d) + { + double min_time = targetTime > deltaTime ? targetTime : deltaTime; + + double v_goal = (targetValue - xi) / min_time; + + double t_goal_future = deltaTime + apprehension * halfLife; + double targetValue_future = t_goal_future < targetTime ? + xi + v_goal * t_goal_future : targetValue; + + double result = SimpleSpringDamperImplicit(startValue, ref Velocity, targetValue_future, halfLife, deltaTime); + + xi += v_goal * deltaTime; + + return result; + } + + public static double DoubleSpringDamperImplicit( + double startValue, + ref double velocity, + ref double xi, + ref double vi, + double targetValue, + double halfLife, + double deltaTime) + { + xi = SimpleSpringDamperImplicit(xi, ref vi, targetValue, 0.5d * halfLife, deltaTime); + return SimpleSpringDamperImplicit(startValue, ref velocity, xi, 0.5d * halfLife, deltaTime); + } + + private static double HalfLifeToDamping(double halfLife, double eps = 1e-5f) + { + return (4.0d * 0.6931471805599453d) / (halfLife + eps); + } + + private static double DampingToHalfLife(double damping, double eps = 1e-5f) + { + return (4.0d * 0.6931471805599453d) / (damping + eps); + } + + private static double DampingRatioToStiffness(double ratio, double damping) + { + return Square(damping / (ratio * 2.0f)); + } + + private static double DampingRatioToDamping(double ratio, double stiffness) + { + return ratio * 2.0f * Math.Sqrt(stiffness); + } + + private static double FrequencyToStiffness(double frequency) + { + return Square(2.0d * Math.PI * frequency); + } + + private static double FastNegExp(double x) + { + return 1.0d / (1.0d + x + 0.48d * x * x + 0.235d * x * x * x); + } + + private static double Square(double x) + { + return x * x; + } + + + public static double SpringDamperExactRatio( + double x, + ref double v, + double targetValue, + double v_goal, + double damping_ratio, + double halfLife, + double deltaTime, + double eps = 1e-5f) + { + double g = targetValue; + double q = v_goal; + double d = HalfLifeToDamping(halfLife); + double s = DampingRatioToStiffness(damping_ratio, d); + double c = g + (d * q) / (s + eps); + double y = d / 2.0f; + + if (Math.Abs(s - (d * d) / 4.0f) < eps) // Ƿ + { + double j0 = x - c; + double j1 = v + j0 * y; + + double eydt = FastNegExp(y * deltaTime); + + x = j0 * eydt + deltaTime * j1 * eydt + c; + v = -y * j0 * eydt - y * deltaTime * j1 * eydt + j1 * eydt; + return x; + } + else if (s - (d * d) / 4.0f > 0.0) // ٽ + { + double w = Math.Sqrt(s - (d * d) / 4.0f); + double j = Math.Sqrt(Square(v + y * (x - c)) / (w * w + eps) + Square(x - c)); + double p = Math.Atan((v + (x - c) * y) / (-(x - c) * w + eps)); + + j = (x - c) > 0.0f ? j : -j; + + double eydt = FastNegExp(y * deltaTime); + + x = j * eydt * Math.Cos(w * deltaTime + p) + c; + v = -y * j * eydt * Math.Cos(w * deltaTime + p) - w * j * eydt * Math.Sin(w * deltaTime + p); + return x; + } + else if (s - (d * d) / 4.0f < 0.0) // + { + double y0 = (d + Math.Sqrt(d * d - 4 * s)) / 2.0f; + double y1 = (d - Math.Sqrt(d * d - 4 * s)) / 2.0f; + double j1 = (c * y0 - x * y0 - v) / (y1 - y0); + double j0 = x - j1 - c; + + double ey0deltaTime = FastNegExp(y0 * deltaTime); + double ey1deltaTime = FastNegExp(y1 * deltaTime); + + x = j0 * ey0deltaTime + j1 * ey1deltaTime + c; + v = -y0 * j0 * ey0deltaTime - y1 * j1 * ey1deltaTime; + return x; + } + return 0d; + } + } +} From 31c7192e5bcd269c269dbacba855a58e5aa85360 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Fri, 19 Sep 2025 01:23:33 +0800 Subject: [PATCH 18/55] Update DamperUtility.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 可能用到的弹簧算法 --- .../Assets/LitMotion/Runtime/DamperUtility.cs | 498 +++++++++++++----- 1 file changed, 377 insertions(+), 121 deletions(-) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/DamperUtility.cs b/src/LitMotion/Assets/LitMotion/Runtime/DamperUtility.cs index cd85da35..bcb0f392 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/DamperUtility.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/DamperUtility.cs @@ -3,93 +3,382 @@ namespace LitMotion { //https://github.com/orangeduck/Spring-It-On /// - /// ṩֵʵóࡣ + /// �ṩ�����ֵ�����ʵ�ó����ࡣ /// public static class DamperUtility { /// - /// ٽ + /// 简易弹簧阻尼器,只有临界阻尼,没有过阻尼和欠阻尼 /// - /// - /// - /// - /// - /// - /// - public static double SimpleSpringDamperImplicit( - double startValue, - ref double velocity, - double targetValue, - double halfLife, - double deltaTime) + /// 经过时间(毫秒) + /// 当前值 + /// 当前速度 + /// 目标值 + /// 输出新的速度 + /// 阻尼比 + /// 弹簧刚度(实际上直接作为自然频率使用) + /// 新的位移值 + public static float SpringSimple( + long timeElapsed, + float currentValue, + float currentVelocity, + float targetValue, + out float newVelocity, + float dampingRatio = 0.5f, + float stiffness = 1.0f) { - double y = HalfLifeToDamping(halfLife) / 2.0d; - double j0 = startValue - targetValue; - double j1 = velocity + j0 * y; - double eydt = FastNegExp(y * deltaTime); - - startValue = eydt * (j0 + j1 * deltaTime) + targetValue; - velocity = eydt * (velocity - j1 * y * deltaTime); - return startValue; + // 将stiffness参数重命名为naturalFreq进行内部计算 + float naturalFreq = stiffness; + + // 参数映射到更有意义的变量名,保持计算逻辑不变 + double currentPosition = currentValue; + double currentVel = currentVelocity; + double targetPosition = targetValue; + double deltaTime = timeElapsed / 1000.0; // 转换为秒 + + // 从stiffness和dampingRatio计算弹簧物理参数 + // 保持与原始SpringSimple相同的计算逻辑 + double halfLife = DampingToHalfLife(2.0 * dampingRatio * naturalFreq); // 从阻尼系数计算半衰期 + double dampingCoeff = HalfLifeToDamping(halfLife); // 阻尼系数 + double dampingHalf = dampingCoeff / 2.0d; // 阻尼系数的一半 + + // 临界阻尼计算(SpringSimple只支持临界阻尼) + double initialDisplacement = currentPosition - targetPosition; + double initialVelocityWithDamping = currentVel + initialDisplacement * dampingHalf; + double exponentialDecay = FastNegExp(dampingHalf * deltaTime); + + // 更新位置和速度 + currentPosition = exponentialDecay * (initialDisplacement + initialVelocityWithDamping * deltaTime) + targetPosition; + currentVel = exponentialDecay * (currentVel - initialVelocityWithDamping * dampingHalf * deltaTime); + + newVelocity = (float)currentVel; + return (float)currentPosition; + } + + /// + /// 近似弹性弹簧阻尼器,有过阻尼和欠阻尼和临界阻尼,采用高性能近似算法 + /// + /// 经过时间(毫秒) + /// 当前值 + /// 当前速度 + /// 目标值 + /// 输出新的速度 + /// 目标速度(到达目标位置时的期望速度) + /// 阻尼比 + /// 弹簧刚度(实际上直接作为自然频率使用) + /// 计算精度容差 + /// 新的位移值 + public static float SpringElastic( + long timeElapsed, + float currentValue, + float currentVelocity, + float targetValue, + out float newVelocity, + float targetVelocity = 0.0f, + float dampingRatio = 0.5f, + float stiffness = 1.0f, + float precision = 1e-5f) + { + // 将stiffness参数重命名为naturalFreq进行内部计算 + float naturalFreq = stiffness; + + double currentPosition = currentValue; + double currentVel = currentVelocity; + double targetPosition = targetValue; + double targetVel = targetVelocity; + double deltaTime = timeElapsed / 1000.0; // 转换为秒 + + // 从stiffness和dampingRatio计算弹簧物理参数 + // 保持与原始SpringElastic相同的计算逻辑 + double halfLife = DampingToHalfLife(2.0 * dampingRatio * naturalFreq); // 从阻尼系数计算半衰期 + double dampingCoeff = HalfLifeToDamping(halfLife); // 阻尼系数 + double stiffnessValue = DampingRatioToStiffness(dampingRatio, dampingCoeff); // 刚度值 + + // 计算调整后的目标位置,支持连续运动 + double adjustedTargetPosition = targetPosition + (dampingCoeff * targetVel) / (stiffnessValue + precision); + double dampingHalf = dampingCoeff / 2.0f; // 阻尼系数的一半 + + if (Math.Abs(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f) < precision) + { + // 临界阻尼:计算初始条件系数 + double initialDisplacement = currentPosition - adjustedTargetPosition; + double initialVelocityWithDamping = currentVel + initialDisplacement * dampingHalf; + + double exponentialDecay = FastNegExp(dampingHalf * deltaTime); + + // 更新位置和速度 + currentPosition = initialDisplacement * exponentialDecay + deltaTime * initialVelocityWithDamping * exponentialDecay + adjustedTargetPosition; + currentVel = -dampingHalf * initialDisplacement * exponentialDecay - dampingHalf * deltaTime * initialVelocityWithDamping * exponentialDecay + initialVelocityWithDamping * exponentialDecay; + } + else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f > 0.0) + { + // 欠阻尼:计算振荡频率和振幅 + double dampedFrequency = Math.Sqrt(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f); + double displacementFromTarget = currentPosition - adjustedTargetPosition; + + // 计算振幅和相位 + double amplitude = Math.Sqrt(Square(currentVel + dampingHalf * displacementFromTarget) / (dampedFrequency * dampedFrequency + precision) + Square(displacementFromTarget)); + double phase = Math.Atan((currentVel + displacementFromTarget * dampingHalf) / (-displacementFromTarget * dampedFrequency + precision)); + + // 根据位移方向确定振幅符号 + amplitude = displacementFromTarget > 0.0f ? amplitude : -amplitude; + + double exponentialDecay = FastNegExp(dampingHalf * deltaTime); + + // 更新位置和速度(振荡运动) + currentPosition = amplitude * exponentialDecay * Math.Cos(dampedFrequency * deltaTime + phase) + adjustedTargetPosition; + currentVel = -dampingHalf * amplitude * exponentialDecay * Math.Cos(dampedFrequency * deltaTime + phase) - + dampedFrequency * amplitude * exponentialDecay * Math.Sin(dampedFrequency * deltaTime + phase); + } + else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f < 0.0) + { + // 过阻尼:计算两个衰减指数 + double fastDecayRate = (dampingCoeff + Math.Sqrt(dampingCoeff * dampingCoeff - 4 * stiffnessValue)) / 2.0f; + double slowDecayRate = (dampingCoeff - Math.Sqrt(dampingCoeff * dampingCoeff - 4 * stiffnessValue)) / 2.0f; + // 计算系数 + double fastCoeff = (adjustedTargetPosition * fastDecayRate - currentPosition * fastDecayRate - currentVel) / (slowDecayRate - fastDecayRate); + double slowCoeff = currentPosition - fastCoeff - adjustedTargetPosition; + + double fastExponentialDecay = FastNegExp(fastDecayRate * deltaTime); + double slowExponentialDecay = FastNegExp(slowDecayRate * deltaTime); + + // 更新位置和速度(过阻尼运动) + currentPosition = slowCoeff * slowExponentialDecay + fastCoeff * fastExponentialDecay + adjustedTargetPosition; + currentVel = -slowDecayRate * slowCoeff * slowExponentialDecay - fastDecayRate * fastCoeff * fastExponentialDecay; + } + + newVelocity = (float)currentVel; + return (float)currentPosition; + } + /// + /// 精确弹簧阻尼器,有过阻尼和欠阻尼和临界阻尼,采用精确算法 + /// + /// 上次位移 + /// 当前速度 + /// 经过时间(毫秒) + /// 目标位置 + /// 输出新的速度 + /// 阻尼比 + /// 弹簧刚度(实际上直接作为自然频率使用) + /// 目标速度(到达目标位置时的期望速度) + /// 计算精度容差 + /// 新的位移值 + public static float SpringPrecise( + long timeElapsed, + float currentValue, + float currentVelocity, + float targetValue, + out float newVelocity, + float targetVelocity = 0.0f, + float dampingRatio = 0.5f, + float stiffness = 1.0f, + float precision = 1e-5f) + { + // 将stiffness参数重命名为naturalFreq进行内部计算 + float naturalFreq = stiffness; + + // 根据targetVelocity调整目标位置(类似SpringElastic的逻辑) + float adjustedTargetPosition = targetValue; + if (Math.Abs(targetVelocity) > precision) + { + // 计算调整后的目标位置,使系统在到达目标时具有指定速度 + // 使用与SpringElastic相同的逻辑:c = g + (d * q) / (s + eps) + // 其中 d = 2 * dampingRatio * naturalFreq, s = naturalFreq^2 + float dampingCoeff = 2.0f * dampingRatio * naturalFreq; + float stiffnessValue = naturalFreq * naturalFreq; + adjustedTargetPosition = targetValue + (dampingCoeff * targetVelocity) / (stiffnessValue + precision); + } + + float adjustedDisplacement = currentValue - adjustedTargetPosition; + double deltaT = timeElapsed / 1000.0; // 转换为秒 + double dampingRatioSquared = dampingRatio * dampingRatio; + double r = -dampingRatio * naturalFreq; + + double displacement; + double calculatedVelocity; + + if (dampingRatio > 1) + { + // 过阻尼 + double s = naturalFreq * Math.Sqrt(dampingRatioSquared - 1); + double gammaPlus = r + s; + double gammaMinus = r - s; + + // 过阻尼计算 + double coeffB = (gammaMinus * adjustedDisplacement - currentVelocity) / (gammaMinus - gammaPlus); + double coeffA = adjustedDisplacement - coeffB; + displacement = coeffA * Math.Exp(gammaMinus * deltaT) + coeffB * Math.Exp(gammaPlus * deltaT); + calculatedVelocity = coeffA * gammaMinus * Math.Exp(gammaMinus * deltaT) + + coeffB * gammaPlus * Math.Exp(gammaPlus * deltaT); + } + else if (Math.Abs(dampingRatio - 1.0f) < precision) + { + // 临界阻尼 + double coeffA = adjustedDisplacement; + double coeffB = currentVelocity + naturalFreq * adjustedDisplacement; + double nFdT = -naturalFreq * deltaT; + displacement = (coeffA + coeffB * deltaT) * Math.Exp(nFdT); + calculatedVelocity = ((coeffA + coeffB * deltaT) * Math.Exp(nFdT) * (-naturalFreq)) + + coeffB * Math.Exp(nFdT); + } + else + { + // 欠阻尼 + double dampedFreq = naturalFreq * Math.Sqrt(1 - dampingRatioSquared); + double cosCoeff = adjustedDisplacement; + double sinCoeff = (1.0 / dampedFreq) * ((-r * adjustedDisplacement) + currentVelocity); + double dFdT = dampedFreq * deltaT; + displacement = Math.Exp(r * deltaT) * (cosCoeff * Math.Cos(dFdT) + sinCoeff * Math.Sin(dFdT)); + calculatedVelocity = displacement * r + + (Math.Exp(r * deltaT) * + ((-dampedFreq * cosCoeff * Math.Sin(dFdT) + + dampedFreq * sinCoeff * Math.Cos(dFdT)))); + } + + float newValue = (float)(displacement + adjustedTargetPosition); + newVelocity = (float)calculatedVelocity; + + return newValue; } - public static double VelocitySpringDamperImplicit( - double startValue, - ref double velocity, - ref double xi, - double targetValue, - double targetVelocity, - double halfLife, - double deltaTime, - double apprehension = 2.0d) + /// + /// 速度平滑弹簧阻尼器,支持目标速度的连续运动 + /// + /// 经过时间(毫秒) + /// 当前值 + /// 当前速度 + /// 目标值 + /// 输出新的速度 + /// 中间位置(用于维护状态) + /// 目标速度(到达目标位置时的期望速度) + /// 阻尼比 + /// 弹簧刚度(实际上直接作为自然频率使用) + /// 预期系数,用于预测未来目标位置 + /// 新的位移值 + public static float SpringSimpleVelocitySmoothing( + long timeElapsed, + float currentValue, + float currentVelocity, + float targetValue, + out float newVelocity, + ref float intermediatePosition, + float targetVelocity = 0.0f, + float dampingRatio = 0.5f, + float stiffness = 1.0f, + float anticipation = 2.0f) { - double x_diff = ((targetValue - xi) > 0.0d ? 1.0d : -1.0d) * targetVelocity; + // 将stiffness参数重命名为naturalFreq进行内部计算 + float naturalFreq = stiffness; + + // 从stiffness和dampingRatio计算弹簧物理参数 + double halfLife = DampingToHalfLife(2.0 * dampingRatio * naturalFreq); + double dampingCoeff = HalfLifeToDamping(halfLife); + double dampingHalf = dampingCoeff / 2.0d; + + // 计算速度方向 + float velocityDirection = (float)((targetValue - intermediatePosition) > 0.0d ? 1.0d : -1.0d) * targetVelocity; - double t_goal_future = deltaTime + apprehension * halfLife; - double targetValue_future = Math.Abs(targetValue - xi) > t_goal_future * targetVelocity ? - xi + x_diff * t_goal_future : targetValue; + // 计算预期时间 + float anticipatedTime = timeElapsed / 1000.0f + anticipation * (float)halfLife; + + // 计算未来目标位置 + float futureTargetPosition = Math.Abs(targetValue - intermediatePosition) > anticipatedTime * targetVelocity ? + intermediatePosition + velocityDirection * anticipatedTime : targetValue; - double result = SimpleSpringDamperImplicit(startValue, ref velocity, targetValue_future, halfLife, deltaTime); + // 直接调用SpringSimple函数 + float result = SpringSimple(timeElapsed, currentValue, currentVelocity, futureTargetPosition, out newVelocity, dampingRatio, stiffness); + + // 更新中间位置 + intermediatePosition = Math.Abs(targetValue - intermediatePosition) > timeElapsed / 1000.0f * targetVelocity ? + intermediatePosition + velocityDirection * timeElapsed / 1000.0f : targetValue; - xi = Math.Abs(targetValue - xi) > deltaTime * targetVelocity ? xi + x_diff * deltaTime : targetValue; return result; } - public static double TimedSpringDamperImplicit( - double startValue, - ref double Velocity, - ref double xi, - double targetValue, - double targetTime, - double halfLife, - double deltaTime, - double apprehension = 2.0d) + /// + /// 时间限制弹簧阻尼器,支持指定到达时间 + /// + /// 经过时间(毫秒) + /// 当前值 + /// 当前速度 + /// 目标值 + /// 输出新的速度 + /// 中间位置(用于维护状态) + /// 目标到达时间(毫秒) + /// 阻尼比 + /// 弹簧刚度(实际上直接作为自然频率使用) + /// 预期系数,用于预测未来目标位置 + /// 新的位移值 + public static float SpringSimpleDurationLimit( + long timeElapsed, + float currentValue, + float currentVelocity, + float targetValue, + out float newVelocity, + ref float intermediatePosition, + float durationMillisecond = 200.0f, + float dampingRatio = 0.5f, + float stiffness = 1.0f, + float anticipation = 2.0f) { - double min_time = targetTime > deltaTime ? targetTime : deltaTime; + // 将stiffness参数重命名为naturalFreq进行内部计算 + float naturalFreq = stiffness; + + // 从stiffness和dampingRatio计算弹簧物理参数 + double halfLife = DampingToHalfLife(2.0 * dampingRatio * naturalFreq); + double dampingCoeff = HalfLifeToDamping(halfLife); + double dampingHalf = dampingCoeff / 2.0d; + + // 计算最小时间(转换为秒) + float minTimeSeconds = (durationMillisecond > timeElapsed ? durationMillisecond : timeElapsed) / 1000.0f; - double v_goal = (targetValue - xi) / min_time; + // 基于中间位置计算目标速度 + float targetVel = (targetValue - intermediatePosition) / minTimeSeconds; - double t_goal_future = deltaTime + apprehension * halfLife; - double targetValue_future = t_goal_future < targetTime ? - xi + v_goal * t_goal_future : targetValue; + // 计算预期时间 + float anticipatedTime = timeElapsed / 1000.0f + anticipation * (float)halfLife; + + // 计算未来目标位置 + float futureTargetPosition = anticipatedTime < durationMillisecond ? + intermediatePosition + targetVel * anticipatedTime : targetValue; - double result = SimpleSpringDamperImplicit(startValue, ref Velocity, targetValue_future, halfLife, deltaTime); + // 直接调用SpringSimple函数 + float result = SpringSimple(timeElapsed, currentValue, currentVelocity, futureTargetPosition, out newVelocity, dampingRatio, stiffness); - xi += v_goal * deltaTime; + // 更新中间位置 + intermediatePosition += targetVel * timeElapsed / 1000.0f; return result; } - public static double DoubleSpringDamperImplicit( - double startValue, - ref double velocity, - ref double xi, - ref double vi, - double targetValue, - double halfLife, - double deltaTime) + /// + /// 双重平滑弹簧阻尼器,使用两个串联的弹簧系统实现更平滑的运动 + /// + /// 经过时间(毫秒) + /// 当前值 + /// 当前速度 + /// 目标值 + /// 输出新的速度 + /// 中间位置(用于维护状态) + /// 中间速度(用于维护状态) + /// 阻尼比 + /// 弹簧刚度(实际上直接作为自然频率使用) + /// 新的位移值 + public static float SpringSimpleDoubleSmoothing( + long timeElapsed, + float currentValue, + float currentVelocity, + float targetValue, + out float newVelocity, + ref float intermediatePosition, + ref float intermediateVelocity, + float dampingRatio = 0.5f, + float stiffness = 1.0f) { - xi = SimpleSpringDamperImplicit(xi, ref vi, targetValue, 0.5d * halfLife, deltaTime); - return SimpleSpringDamperImplicit(startValue, ref velocity, xi, 0.5d * halfLife, deltaTime); + // 第一层弹簧:从中间位置到目标位置 + float firstLayerResult = SpringSimple(timeElapsed, intermediatePosition, intermediateVelocity, targetValue, out intermediateVelocity, dampingRatio, stiffness); + + // 第二层弹簧:从当前位置到中间位置 + return SpringSimple(timeElapsed, currentValue, currentVelocity, firstLayerResult, out newVelocity, dampingRatio, stiffness); } private static double HalfLifeToDamping(double halfLife, double eps = 1e-5f) @@ -127,64 +416,31 @@ private static double Square(double x) return x * x; } - - public static double SpringDamperExactRatio( - double x, - ref double v, - double targetValue, - double v_goal, - double damping_ratio, - double halfLife, - double deltaTime, - double eps = 1e-5f) + /// + /// 根据纳秒时间计算弹簧动画值 + /// + /// 播放时间(纳秒) + /// 初始值 + /// 目标值 + /// 初始速度 + /// 阻尼比 + /// 弹簧刚度(实际上直接作为自然频率使用) + /// 目标速度(到达目标位置时的期望速度) + /// 计算精度容差 + /// 当前动画值 + public static float GetSpringValueAndVelocityFromNanos( + long playTimeNanos, + float initialValue, + float targetValue, + float initialVelocity, + float dampingRatio = 0.5f, + float stiffness = 1.0f, + float targetVelocity = 0.0f, + float precision = 1e-5f) { - double g = targetValue; - double q = v_goal; - double d = HalfLifeToDamping(halfLife); - double s = DampingRatioToStiffness(damping_ratio, d); - double c = g + (d * q) / (s + eps); - double y = d / 2.0f; - - if (Math.Abs(s - (d * d) / 4.0f) < eps) // Ƿ - { - double j0 = x - c; - double j1 = v + j0 * y; - - double eydt = FastNegExp(y * deltaTime); - - x = j0 * eydt + deltaTime * j1 * eydt + c; - v = -y * j0 * eydt - y * deltaTime * j1 * eydt + j1 * eydt; - return x; - } - else if (s - (d * d) / 4.0f > 0.0) // ٽ - { - double w = Math.Sqrt(s - (d * d) / 4.0f); - double j = Math.Sqrt(Square(v + y * (x - c)) / (w * w + eps) + Square(x - c)); - double p = Math.Atan((v + (x - c) * y) / (-(x - c) * w + eps)); - - j = (x - c) > 0.0f ? j : -j; - - double eydt = FastNegExp(y * deltaTime); - - x = j * eydt * Math.Cos(w * deltaTime + p) + c; - v = -y * j * eydt * Math.Cos(w * deltaTime + p) - w * j * eydt * Math.Sin(w * deltaTime + p); - return x; - } - else if (s - (d * d) / 4.0f < 0.0) // - { - double y0 = (d + Math.Sqrt(d * d - 4 * s)) / 2.0f; - double y1 = (d - Math.Sqrt(d * d - 4 * s)) / 2.0f; - double j1 = (c * y0 - x * y0 - v) / (y1 - y0); - double j0 = x - j1 - c; - - double ey0deltaTime = FastNegExp(y0 * deltaTime); - double ey1deltaTime = FastNegExp(y1 * deltaTime); - - x = j0 * ey0deltaTime + j1 * ey1deltaTime + c; - v = -y0 * j0 * ey0deltaTime - y1 * j1 * ey1deltaTime; - return x; - } - return 0d; - } + // TODO: 在弹簧实现中正确支持纳秒 + long playTimeMillis = playTimeNanos / 1_000_000L; + return SpringPrecise(playTimeMillis, initialValue, initialVelocity, targetValue, out _, targetVelocity, dampingRatio, stiffness, precision); } } +} From 570c747944034648a91dad52c992886a7ec2fa07 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Sat, 20 Sep 2025 00:33:21 +0800 Subject: [PATCH 19/55] =?UTF-8?q?=E7=BB=8F=E8=BF=87=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=92=8C=E6=B5=8B=E8=AF=95=E7=9A=84Damper=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets/LitMotion/Runtime/DamperUtility.cs | 253 +++++++++--------- 1 file changed, 124 insertions(+), 129 deletions(-) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/DamperUtility.cs b/src/LitMotion/Assets/LitMotion/Runtime/DamperUtility.cs index bcb0f392..b0e3b10e 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/DamperUtility.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/DamperUtility.cs @@ -1,10 +1,8 @@ using System; +using System.Diagnostics; +using Unity.Mathematics; namespace LitMotion { - //https://github.com/orangeduck/Spring-It-On - /// - /// �ṩ�����ֵ�����ʵ�ó����ࡣ - /// public static class DamperUtility { /// @@ -19,46 +17,34 @@ public static class DamperUtility /// 弹簧刚度(实际上直接作为自然频率使用) /// 新的位移值 public static float SpringSimple( - long timeElapsed, + float deltaTime, float currentValue, float currentVelocity, float targetValue, out float newVelocity, - float dampingRatio = 0.5f, float stiffness = 1.0f) { - // 将stiffness参数重命名为naturalFreq进行内部计算 - float naturalFreq = stiffness; - - // 参数映射到更有意义的变量名,保持计算逻辑不变 - double currentPosition = currentValue; - double currentVel = currentVelocity; - double targetPosition = targetValue; - double deltaTime = timeElapsed / 1000.0; // 转换为秒 + // SpringSimple是专门为临界阻尼设计的简化版本 + // 直接使用stiffness作为自然频率,阻尼系数的一半等于自然频率 + double naturalFreq = stiffness; - // 从stiffness和dampingRatio计算弹簧物理参数 - // 保持与原始SpringSimple相同的计算逻辑 - double halfLife = DampingToHalfLife(2.0 * dampingRatio * naturalFreq); // 从阻尼系数计算半衰期 - double dampingCoeff = HalfLifeToDamping(halfLife); // 阻尼系数 - double dampingHalf = dampingCoeff / 2.0d; // 阻尼系数的一半 - - // 临界阻尼计算(SpringSimple只支持临界阻尼) - double initialDisplacement = currentPosition - targetPosition; - double initialVelocityWithDamping = currentVel + initialDisplacement * dampingHalf; - double exponentialDecay = FastNegExp(dampingHalf * deltaTime); + // 临界阻尼的计算逻辑 + double displacementFromTarget = currentValue - targetValue; // 当前位置与目标的位移差 + double velocityWithDamping = currentVelocity + displacementFromTarget * naturalFreq; // 考虑阻尼的初始速度 + double exponentialDecay = FastNegExp(naturalFreq * deltaTime); // 指数衰减因子 - // 更新位置和速度 - currentPosition = exponentialDecay * (initialDisplacement + initialVelocityWithDamping * deltaTime) + targetPosition; - currentVel = exponentialDecay * (currentVel - initialVelocityWithDamping * dampingHalf * deltaTime); + // 临界阻尼的更新公式 + double newPosition = exponentialDecay * (displacementFromTarget + velocityWithDamping * deltaTime) + targetValue; // 新位置 + double newVel = exponentialDecay * (currentVelocity - velocityWithDamping * naturalFreq * deltaTime); // 新速度 - newVelocity = (float)currentVel; - return (float)currentPosition; + newVelocity = (float)newVel; + return (float)newPosition; } /// /// 近似弹性弹簧阻尼器,有过阻尼和欠阻尼和临界阻尼,采用高性能近似算法 /// - /// 经过时间(毫秒) + /// 时间步长(秒) /// 当前值 /// 当前速度 /// 目标值 @@ -69,7 +55,7 @@ public static float SpringSimple( /// 计算精度容差 /// 新的位移值 public static float SpringElastic( - long timeElapsed, + float deltaTime, float currentValue, float currentVelocity, float targetValue, @@ -79,72 +65,56 @@ public static float SpringElastic( float stiffness = 1.0f, float precision = 1e-5f) { - // 将stiffness参数重命名为naturalFreq进行内部计算 - float naturalFreq = stiffness; - + // 使用有意义的变量名,提高代码可读性 double currentPosition = currentValue; double currentVel = currentVelocity; double targetPosition = targetValue; double targetVel = targetVelocity; - double deltaTime = timeElapsed / 1000.0; // 转换为秒 - - // 从stiffness和dampingRatio计算弹簧物理参数 - // 保持与原始SpringElastic相同的计算逻辑 - double halfLife = DampingToHalfLife(2.0 * dampingRatio * naturalFreq); // 从阻尼系数计算半衰期 - double dampingCoeff = HalfLifeToDamping(halfLife); // 阻尼系数 - double stiffnessValue = DampingRatioToStiffness(dampingRatio, dampingCoeff); // 刚度值 - - // 计算调整后的目标位置,支持连续运动 + // 将stiffness参数重命名为naturalFreq进行内部计算 + double naturalFreq = stiffness; + double stiffnessValue = naturalFreq * naturalFreq; // 刚度值 = naturalFreq² + double dampingHalf = dampingRatio * naturalFreq; + double dampingCoeff = 2.0 * dampingHalf; // 阻尼系数 = 2 * 阻尼比 * naturalFreq double adjustedTargetPosition = targetPosition + (dampingCoeff * targetVel) / (stiffnessValue + precision); - double dampingHalf = dampingCoeff / 2.0f; // 阻尼系数的一半 - if (Math.Abs(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f) < precision) + if (Math.Abs(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f) < precision) // Critically Damped { - // 临界阻尼:计算初始条件系数 double initialDisplacement = currentPosition - adjustedTargetPosition; double initialVelocityWithDamping = currentVel + initialDisplacement * dampingHalf; double exponentialDecay = FastNegExp(dampingHalf * deltaTime); - // 更新位置和速度 currentPosition = initialDisplacement * exponentialDecay + deltaTime * initialVelocityWithDamping * exponentialDecay + adjustedTargetPosition; currentVel = -dampingHalf * initialDisplacement * exponentialDecay - dampingHalf * deltaTime * initialVelocityWithDamping * exponentialDecay + initialVelocityWithDamping * exponentialDecay; } - else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f > 0.0) + else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f > 0.0) // Under Damped { - // 欠阻尼:计算振荡频率和振幅 double dampedFrequency = Math.Sqrt(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f); double displacementFromTarget = currentPosition - adjustedTargetPosition; - - // 计算振幅和相位 - double amplitude = Math.Sqrt(Square(currentVel + dampingHalf * displacementFromTarget) / (dampedFrequency * dampedFrequency + precision) + Square(displacementFromTarget)); - double phase = Math.Atan((currentVel + displacementFromTarget * dampingHalf) / (-displacementFromTarget * dampedFrequency + precision)); + double amplitude = Math.Sqrt(FastSquare(currentVel + dampingHalf * displacementFromTarget) / (dampedFrequency * dampedFrequency + precision) + FastSquare(displacementFromTarget)); + double phase = FastAtan((currentVel + displacementFromTarget * dampingHalf) / (-displacementFromTarget * dampedFrequency + precision)); - // 根据位移方向确定振幅符号 amplitude = displacementFromTarget > 0.0f ? amplitude : -amplitude; double exponentialDecay = FastNegExp(dampingHalf * deltaTime); - // 更新位置和速度(振荡运动) currentPosition = amplitude * exponentialDecay * Math.Cos(dampedFrequency * deltaTime + phase) + adjustedTargetPosition; - currentVel = -dampingHalf * amplitude * exponentialDecay * Math.Cos(dampedFrequency * deltaTime + phase) - - dampedFrequency * amplitude * exponentialDecay * Math.Sin(dampedFrequency * deltaTime + phase); + currentVel = -dampingHalf * amplitude * exponentialDecay * Math.Cos(dampedFrequency * deltaTime + phase) - dampedFrequency * amplitude * exponentialDecay * Math.Sin(dampedFrequency * deltaTime + phase); } - else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f < 0.0) + else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f < 0.0) // Over Damped { - // 过阻尼:计算两个衰减指数 double fastDecayRate = (dampingCoeff + Math.Sqrt(dampingCoeff * dampingCoeff - 4 * stiffnessValue)) / 2.0f; double slowDecayRate = (dampingCoeff - Math.Sqrt(dampingCoeff * dampingCoeff - 4 * stiffnessValue)) / 2.0f; - // 计算系数 - double fastCoeff = (adjustedTargetPosition * fastDecayRate - currentPosition * fastDecayRate - currentVel) / (slowDecayRate - fastDecayRate); - double slowCoeff = currentPosition - fastCoeff - adjustedTargetPosition; + // 计算过阻尼系数:fastDecayCoeff对应fastDecayRate,slowDecayCoeff对应slowDecayRate + double fastDecayCoeff = (adjustedTargetPosition * fastDecayRate - currentPosition * fastDecayRate - currentVel) / (slowDecayRate - fastDecayRate); + double slowDecayCoeff = currentPosition - fastDecayCoeff - adjustedTargetPosition; double fastExponentialDecay = FastNegExp(fastDecayRate * deltaTime); double slowExponentialDecay = FastNegExp(slowDecayRate * deltaTime); - // 更新位置和速度(过阻尼运动) - currentPosition = slowCoeff * slowExponentialDecay + fastCoeff * fastExponentialDecay + adjustedTargetPosition; - currentVel = -slowDecayRate * slowCoeff * slowExponentialDecay - fastDecayRate * fastCoeff * fastExponentialDecay; + // 过阻尼位置更新:slowDecayCoeff用fastExponentialDecay,fastDecayCoeff用slowExponentialDecay + currentPosition = slowDecayCoeff * fastExponentialDecay + fastDecayCoeff * slowExponentialDecay + adjustedTargetPosition; + currentVel = -fastDecayRate * slowDecayCoeff * fastExponentialDecay - slowDecayRate * fastDecayCoeff * slowExponentialDecay; } newVelocity = (float)currentVel; @@ -164,7 +134,7 @@ public static float SpringElastic( /// 计算精度容差 /// 新的位移值 public static float SpringPrecise( - long timeElapsed, + float deltaTime, float currentValue, float currentVelocity, float targetValue, @@ -190,7 +160,6 @@ public static float SpringPrecise( } float adjustedDisplacement = currentValue - adjustedTargetPosition; - double deltaT = timeElapsed / 1000.0; // 转换为秒 double dampingRatioSquared = dampingRatio * dampingRatio; double r = -dampingRatio * naturalFreq; @@ -207,18 +176,18 @@ public static float SpringPrecise( // 过阻尼计算 double coeffB = (gammaMinus * adjustedDisplacement - currentVelocity) / (gammaMinus - gammaPlus); double coeffA = adjustedDisplacement - coeffB; - displacement = coeffA * Math.Exp(gammaMinus * deltaT) + coeffB * Math.Exp(gammaPlus * deltaT); - calculatedVelocity = coeffA * gammaMinus * Math.Exp(gammaMinus * deltaT) + - coeffB * gammaPlus * Math.Exp(gammaPlus * deltaT); + displacement = coeffA * Math.Exp(gammaMinus * deltaTime) + coeffB * Math.Exp(gammaPlus * deltaTime); + calculatedVelocity = coeffA * gammaMinus * Math.Exp(gammaMinus * deltaTime) + + coeffB * gammaPlus * Math.Exp(gammaPlus * deltaTime); } else if (Math.Abs(dampingRatio - 1.0f) < precision) { // 临界阻尼 double coeffA = adjustedDisplacement; double coeffB = currentVelocity + naturalFreq * adjustedDisplacement; - double nFdT = -naturalFreq * deltaT; - displacement = (coeffA + coeffB * deltaT) * Math.Exp(nFdT); - calculatedVelocity = ((coeffA + coeffB * deltaT) * Math.Exp(nFdT) * (-naturalFreq)) + + double nFdT = -naturalFreq * deltaTime; + displacement = (coeffA + coeffB * deltaTime) * Math.Exp(nFdT); + calculatedVelocity = ((coeffA + coeffB * deltaTime) * Math.Exp(nFdT) * (-naturalFreq)) + coeffB * Math.Exp(nFdT); } else @@ -227,17 +196,16 @@ public static float SpringPrecise( double dampedFreq = naturalFreq * Math.Sqrt(1 - dampingRatioSquared); double cosCoeff = adjustedDisplacement; double sinCoeff = (1.0 / dampedFreq) * ((-r * adjustedDisplacement) + currentVelocity); - double dFdT = dampedFreq * deltaT; - displacement = Math.Exp(r * deltaT) * (cosCoeff * Math.Cos(dFdT) + sinCoeff * Math.Sin(dFdT)); + double dFdT = dampedFreq * deltaTime; + displacement = Math.Exp(r * deltaTime) * (cosCoeff * Math.Cos(dFdT) + sinCoeff * Math.Sin(dFdT)); calculatedVelocity = displacement * r + - (Math.Exp(r * deltaT) * - ((-dampedFreq * cosCoeff * Math.Sin(dFdT) + + (Math.Exp(r * deltaTime) * + ((-dampedFreq * cosCoeff * Math.Sin(dFdT) + dampedFreq * sinCoeff * Math.Cos(dFdT)))); } float newValue = (float)(displacement + adjustedTargetPosition); newVelocity = (float)calculatedVelocity; - return newValue; } /// @@ -249,47 +217,39 @@ public static float SpringPrecise( /// 目标值 /// 输出新的速度 /// 中间位置(用于维护状态) - /// 目标速度(到达目标位置时的期望速度) + /// 平滑速度(需要平滑的线性速度) /// 阻尼比 /// 弹簧刚度(实际上直接作为自然频率使用) - /// 预期系数,用于预测未来目标位置 /// 新的位移值 public static float SpringSimpleVelocitySmoothing( - long timeElapsed, + float deltaTime, float currentValue, float currentVelocity, float targetValue, out float newVelocity, ref float intermediatePosition, - float targetVelocity = 0.0f, - float dampingRatio = 0.5f, - float stiffness = 1.0f, - float anticipation = 2.0f) + float smothingVelocity = 2f, + float stiffness = 1.0f) { - // 将stiffness参数重命名为naturalFreq进行内部计算 + // 按照原始版本的设计,直接使用stiffness作为自然频率 float naturalFreq = stiffness; - - // 从stiffness和dampingRatio计算弹簧物理参数 - double halfLife = DampingToHalfLife(2.0 * dampingRatio * naturalFreq); - double dampingCoeff = HalfLifeToDamping(halfLife); - double dampingHalf = dampingCoeff / 2.0d; - + // 计算速度方向 - float velocityDirection = (float)((targetValue - intermediatePosition) > 0.0d ? 1.0d : -1.0d) * targetVelocity; + float velocityDirection = ((targetValue - intermediatePosition) > 0.0f ? 1.0f : -1.0f) * smothingVelocity; // 计算预期时间 - float anticipatedTime = timeElapsed / 1000.0f + anticipation * (float)halfLife; + float anticipatedTime = 1 / naturalFreq; // 计算未来目标位置 - float futureTargetPosition = Math.Abs(targetValue - intermediatePosition) > anticipatedTime * targetVelocity ? + float futureTargetPosition = Math.Abs(targetValue - intermediatePosition) > anticipatedTime * smothingVelocity ? intermediatePosition + velocityDirection * anticipatedTime : targetValue; // 直接调用SpringSimple函数 - float result = SpringSimple(timeElapsed, currentValue, currentVelocity, futureTargetPosition, out newVelocity, dampingRatio, stiffness); + float result = SpringSimple(deltaTime, currentValue, currentVelocity, futureTargetPosition, out newVelocity, stiffness); // 更新中间位置 - intermediatePosition = Math.Abs(targetValue - intermediatePosition) > timeElapsed / 1000.0f * targetVelocity ? - intermediatePosition + velocityDirection * timeElapsed / 1000.0f : targetValue; + intermediatePosition = Math.Abs(targetValue - intermediatePosition) > deltaTime * smothingVelocity ? + intermediatePosition + velocityDirection * deltaTime : targetValue; return result; } @@ -309,43 +269,37 @@ public static float SpringSimpleVelocitySmoothing( /// 预期系数,用于预测未来目标位置 /// 新的位移值 public static float SpringSimpleDurationLimit( - long timeElapsed, + float deltaTime, float currentValue, float currentVelocity, float targetValue, out float newVelocity, ref float intermediatePosition, - float durationMillisecond = 200.0f, - float dampingRatio = 0.5f, - float stiffness = 1.0f, - float anticipation = 2.0f) + float durationSeconds = 0.2f, + float stiffness = 1.0f) { - // 将stiffness参数重命名为naturalFreq进行内部计算 + // 按照原始版本的设计,直接使用stiffness作为自然频率 float naturalFreq = stiffness; + float tGoal = durationSeconds; // 对应原始版本的 t_goal + + // 计算最小时间,对应原始版本的 min_time = t_goal > dt ? t_goal : dt + float minTime = tGoal > deltaTime ? tGoal : deltaTime; + + // 基于中间位置计算目标速度,对应原始版本的 v_goal = (x_goal - xi) / min_time + float targetVel = (targetValue - intermediatePosition) / minTime; - // 从stiffness和dampingRatio计算弹簧物理参数 - double halfLife = DampingToHalfLife(2.0 * dampingRatio * naturalFreq); - double dampingCoeff = HalfLifeToDamping(halfLife); - double dampingHalf = dampingCoeff / 2.0d; - - // 计算最小时间(转换为秒) - float minTimeSeconds = (durationMillisecond > timeElapsed ? durationMillisecond : timeElapsed) / 1000.0f; - - // 基于中间位置计算目标速度 - float targetVel = (targetValue - intermediatePosition) / minTimeSeconds; - - // 计算预期时间 - float anticipatedTime = timeElapsed / 1000.0f + anticipation * (float)halfLife; + // 计算预期时间,对应原始版本的 t_goal_future = halflife_to_lag(halflife) + float anticipatedTime = 1 / naturalFreq; // 对应 halflife_to_lag(halflife) - // 计算未来目标位置 - float futureTargetPosition = anticipatedTime < durationMillisecond ? + // 计算未来目标位置,对应原始版本的 x_goal_future + float futureTargetPosition = anticipatedTime < tGoal ? intermediatePosition + targetVel * anticipatedTime : targetValue; - // 直接调用SpringSimple函数 - float result = SpringSimple(timeElapsed, currentValue, currentVelocity, futureTargetPosition, out newVelocity, dampingRatio, stiffness); + // 直接调用SpringSimple函数,对应原始版本的 simple_spring_damper_exact + float result = SpringSimple(deltaTime, currentValue, currentVelocity, futureTargetPosition, out newVelocity, stiffness); - // 更新中间位置 - intermediatePosition += targetVel * timeElapsed / 1000.0f; + // 更新中间位置,对应原始版本的 xi += v_goal * dt + intermediatePosition += targetVel * deltaTime; return result; } @@ -364,21 +318,24 @@ public static float SpringSimpleDurationLimit( /// 弹簧刚度(实际上直接作为自然频率使用) /// 新的位移值 public static float SpringSimpleDoubleSmoothing( - long timeElapsed, + float deltaTime, float currentValue, float currentVelocity, float targetValue, out float newVelocity, ref float intermediatePosition, ref float intermediateVelocity, - float dampingRatio = 0.5f, float stiffness = 1.0f) { - // 第一层弹簧:从中间位置到目标位置 - float firstLayerResult = SpringSimple(timeElapsed, intermediatePosition, intermediateVelocity, targetValue, out intermediateVelocity, dampingRatio, stiffness); + float doubleStiffness = 2.0f * stiffness; + + // 第一层弹簧:从中间位置到目标位置,对应原始版本的 simple_spring_damper_exact(xi, vi, x_goal, 0.5f * halflife, dt) + // 直接修改intermediatePosition和intermediateVelocity + intermediatePosition = SpringSimple(deltaTime, intermediatePosition, intermediateVelocity, targetValue, out intermediateVelocity, doubleStiffness); - // 第二层弹簧:从当前位置到中间位置 - return SpringSimple(timeElapsed, currentValue, currentVelocity, firstLayerResult, out newVelocity, dampingRatio, stiffness); + // 第二层弹簧:从当前位置到中间位置,对应原始版本的 simple_spring_damper_exact(x, v, xi, 0.5f * halflife, dt) + // 使用修改后的intermediatePosition作为目标 + return SpringSimple(deltaTime, currentValue, currentVelocity, intermediatePosition, out newVelocity, doubleStiffness); } private static double HalfLifeToDamping(double halfLife, double eps = 1e-5f) @@ -406,6 +363,25 @@ private static double FrequencyToStiffness(double frequency) return Square(2.0d * Math.PI * frequency); } + /// + /// 将半衰期转换为自然频率(临界阻尼) + /// + /// 半衰期(秒) + /// 自然频率(rad/s) + private static float HalflifeToNaturalFreq(float halflife) + { + return 0.69314718056f / halflife; // ω₀ = ln(2) / τ₁/₂ + } + + /// + /// 将自然频率转换为半衰期(临界阻尼) + /// + /// 自然频率(rad/s) + /// 半衰期(秒) + private static float NaturalFreqToHalflife(float naturalFreq) + { + return 0.69314718056f / naturalFreq; // τ₁/₂ = ln(2) / ω₀ + } private static double FastNegExp(double x) { return 1.0d / (1.0d + x + 0.48d * x * x + 0.235d * x * x * x); @@ -416,6 +392,25 @@ private static double Square(double x) return x * x; } + /// + /// 快速反正切函数近似,比Math.Atan快2-5倍,精度损失很小 + /// + private static double FastAtan(double x) + { + double z = Math.Abs(x); + double w = z > 1.0 ? 1.0 / z : z; + double y = (Math.PI / 4.0) * w - w * (w - 1) * (0.2447 + 0.0663 * w); + return Math.Sign(x) * (z > 1.0 ? Math.PI / 2.0 - y : y); + } + + /// + /// 快速平方函数,与直接乘法性能相同 + /// + private static double FastSquare(double x) + { + return x * x; + } + /// /// 根据纳秒时间计算弹簧动画值 /// From d5b1ea8531ca8e8f6c18f036a6bb9148da18f01d Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Sun, 21 Sep 2025 04:54:51 +0800 Subject: [PATCH 20/55] =?UTF-8?q?=E6=94=B9=E4=B8=AA=E6=9B=B4=E9=80=9A?= =?UTF-8?q?=E7=94=A8=E7=9A=84=E5=90=8D=E5=AD=97=20=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E4=BD=BF=E7=94=A8double=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 暂时不知道为什么float比double慢一倍,先改成都用double了 增加了阻尼比和刚度的推荐值 --- .../{DamperUtility.cs => SpringUtility.cs} | 246 +++++++++--------- 1 file changed, 125 insertions(+), 121 deletions(-) rename src/LitMotion/Assets/LitMotion/Runtime/{DamperUtility.cs => SpringUtility.cs} (72%) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/DamperUtility.cs b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs similarity index 72% rename from src/LitMotion/Assets/LitMotion/Runtime/DamperUtility.cs rename to src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs index b0e3b10e..3bf34414 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/DamperUtility.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs @@ -1,9 +1,9 @@ using System; -using System.Diagnostics; -using Unity.Mathematics; +using Unity.Burst; +using static Unity.Mathematics.math; namespace LitMotion { - public static class DamperUtility + public static class SpringUtility { /// /// 简易弹簧阻尼器,只有临界阻尼,没有过阻尼和欠阻尼 @@ -16,13 +16,13 @@ public static class DamperUtility /// 阻尼比 /// 弹簧刚度(实际上直接作为自然频率使用) /// 新的位移值 - public static float SpringSimple( - float deltaTime, - float currentValue, - float currentVelocity, - float targetValue, - out float newVelocity, - float stiffness = 1.0f) + public static double SpringSimple( + double deltaTime, + double currentValue, + double currentVelocity, + double targetValue, + out double newVelocity, + double stiffness = 1.0d) { // SpringSimple是专门为临界阻尼设计的简化版本 // 直接使用stiffness作为自然频率,阻尼系数的一半等于自然频率 @@ -37,8 +37,8 @@ public static float SpringSimple( double newPosition = exponentialDecay * (displacementFromTarget + velocityWithDamping * deltaTime) + targetValue; // 新位置 double newVel = exponentialDecay * (currentVelocity - velocityWithDamping * naturalFreq * deltaTime); // 新速度 - newVelocity = (float)newVel; - return (float)newPosition; + newVelocity = newVel; + return newPosition; } /// @@ -50,20 +50,20 @@ public static float SpringSimple( /// 目标值 /// 输出新的速度 /// 目标速度(到达目标位置时的期望速度) - /// 阻尼比 - /// 弹簧刚度(实际上直接作为自然频率使用) + /// 阻尼比 0.6 = Q弹 1 = 临界 1.2 = 稍缓 + /// 弹簧刚度(实际上直接作为自然频率使用)5 = 1秒 10 = 0.5秒 16.5 = 0.2秒 /// 计算精度容差 /// 新的位移值 - public static float SpringElastic( - float deltaTime, - float currentValue, - float currentVelocity, - float targetValue, - out float newVelocity, - float targetVelocity = 0.0f, - float dampingRatio = 0.5f, - float stiffness = 1.0f, - float precision = 1e-5f) + public static double SpringElastic( + double deltaTime, + double currentValue, + double currentVelocity, + double targetValue, + out double newVelocity, + double targetVelocity = 0.0d, + double dampingRatio = 0.5f, + double stiffness = 1.0d, + double precision = 1e-5f) { // 使用有意义的变量名,提高代码可读性 double currentPosition = currentValue; @@ -74,10 +74,10 @@ public static float SpringElastic( double naturalFreq = stiffness; double stiffnessValue = naturalFreq * naturalFreq; // 刚度值 = naturalFreq² double dampingHalf = dampingRatio * naturalFreq; - double dampingCoeff = 2.0 * dampingHalf; // 阻尼系数 = 2 * 阻尼比 * naturalFreq + double dampingCoeff = 2.0d * dampingHalf; // 阻尼系数 = 2 * 阻尼比 * naturalFreq double adjustedTargetPosition = targetPosition + (dampingCoeff * targetVel) / (stiffnessValue + precision); - if (Math.Abs(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f) < precision) // Critically Damped + if (Math.Abs(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0d) < precision) // Critically Damped { double initialDisplacement = currentPosition - adjustedTargetPosition; double initialVelocityWithDamping = currentVel + initialDisplacement * dampingHalf; @@ -87,24 +87,24 @@ public static float SpringElastic( currentPosition = initialDisplacement * exponentialDecay + deltaTime * initialVelocityWithDamping * exponentialDecay + adjustedTargetPosition; currentVel = -dampingHalf * initialDisplacement * exponentialDecay - dampingHalf * deltaTime * initialVelocityWithDamping * exponentialDecay + initialVelocityWithDamping * exponentialDecay; } - else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f > 0.0) // Under Damped + else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0d > 0.0) // Under Damped { - double dampedFrequency = Math.Sqrt(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f); + double dampedFrequency = Math.Sqrt(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0d); double displacementFromTarget = currentPosition - adjustedTargetPosition; double amplitude = Math.Sqrt(FastSquare(currentVel + dampingHalf * displacementFromTarget) / (dampedFrequency * dampedFrequency + precision) + FastSquare(displacementFromTarget)); double phase = FastAtan((currentVel + displacementFromTarget * dampingHalf) / (-displacementFromTarget * dampedFrequency + precision)); - amplitude = displacementFromTarget > 0.0f ? amplitude : -amplitude; + amplitude = displacementFromTarget > 0.0d ? amplitude : -amplitude; double exponentialDecay = FastNegExp(dampingHalf * deltaTime); currentPosition = amplitude * exponentialDecay * Math.Cos(dampedFrequency * deltaTime + phase) + adjustedTargetPosition; currentVel = -dampingHalf * amplitude * exponentialDecay * Math.Cos(dampedFrequency * deltaTime + phase) - dampedFrequency * amplitude * exponentialDecay * Math.Sin(dampedFrequency * deltaTime + phase); } - else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f < 0.0) // Over Damped + else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0d < 0.0) // Over Damped { - double fastDecayRate = (dampingCoeff + Math.Sqrt(dampingCoeff * dampingCoeff - 4 * stiffnessValue)) / 2.0f; - double slowDecayRate = (dampingCoeff - Math.Sqrt(dampingCoeff * dampingCoeff - 4 * stiffnessValue)) / 2.0f; + double fastDecayRate = (dampingCoeff + Math.Sqrt(dampingCoeff * dampingCoeff - 4d * stiffnessValue)) / 2.0d; + double slowDecayRate = (dampingCoeff - Math.Sqrt(dampingCoeff * dampingCoeff - 4d * stiffnessValue)) / 2.0d; // 计算过阻尼系数:fastDecayCoeff对应fastDecayRate,slowDecayCoeff对应slowDecayRate double fastDecayCoeff = (adjustedTargetPosition * fastDecayRate - currentPosition * fastDecayRate - currentVel) / (slowDecayRate - fastDecayRate); double slowDecayCoeff = currentPosition - fastDecayCoeff - adjustedTargetPosition; @@ -117,8 +117,8 @@ public static float SpringElastic( currentVel = -fastDecayRate * slowDecayCoeff * fastExponentialDecay - slowDecayRate * fastDecayCoeff * slowExponentialDecay; } - newVelocity = (float)currentVel; - return (float)currentPosition; + newVelocity = (double)currentVel; + return (double)currentPosition; } /// /// 精确弹簧阻尼器,有过阻尼和欠阻尼和临界阻尼,采用精确算法 @@ -133,33 +133,33 @@ public static float SpringElastic( /// 目标速度(到达目标位置时的期望速度) /// 计算精度容差 /// 新的位移值 - public static float SpringPrecise( - float deltaTime, - float currentValue, - float currentVelocity, - float targetValue, - out float newVelocity, - float targetVelocity = 0.0f, - float dampingRatio = 0.5f, - float stiffness = 1.0f, - float precision = 1e-5f) + public static double SpringPrecise( + double deltaTime, + double currentValue, + double currentVelocity, + double targetValue, + out double newVelocity, + double targetVelocity = 0.0d, + double dampingRatio = 0.5d, + double stiffness = 1.0d, + double precision = 1e-5d) { // 将stiffness参数重命名为naturalFreq进行内部计算 - float naturalFreq = stiffness; + double naturalFreq = stiffness; // 根据targetVelocity调整目标位置(类似SpringElastic的逻辑) - float adjustedTargetPosition = targetValue; + double adjustedTargetPosition = targetValue; if (Math.Abs(targetVelocity) > precision) { // 计算调整后的目标位置,使系统在到达目标时具有指定速度 // 使用与SpringElastic相同的逻辑:c = g + (d * q) / (s + eps) // 其中 d = 2 * dampingRatio * naturalFreq, s = naturalFreq^2 - float dampingCoeff = 2.0f * dampingRatio * naturalFreq; - float stiffnessValue = naturalFreq * naturalFreq; + double dampingCoeff = 2.0d * dampingRatio * naturalFreq; + double stiffnessValue = naturalFreq * naturalFreq; adjustedTargetPosition = targetValue + (dampingCoeff * targetVelocity) / (stiffnessValue + precision); } - float adjustedDisplacement = currentValue - adjustedTargetPosition; + double adjustedDisplacement = currentValue - adjustedTargetPosition; double dampingRatioSquared = dampingRatio * dampingRatio; double r = -dampingRatio * naturalFreq; @@ -180,7 +180,7 @@ public static float SpringPrecise( calculatedVelocity = coeffA * gammaMinus * Math.Exp(gammaMinus * deltaTime) + coeffB * gammaPlus * Math.Exp(gammaPlus * deltaTime); } - else if (Math.Abs(dampingRatio - 1.0f) < precision) + else if (Math.Abs(dampingRatio - 1.0d) < precision) { // 临界阻尼 double coeffA = adjustedDisplacement; @@ -204,8 +204,8 @@ public static float SpringPrecise( dampedFreq * sinCoeff * Math.Cos(dFdT)))); } - float newValue = (float)(displacement + adjustedTargetPosition); - newVelocity = (float)calculatedVelocity; + double newValue = (double)(displacement + adjustedTargetPosition); + newVelocity = (double)calculatedVelocity; return newValue; } /// @@ -221,34 +221,38 @@ public static float SpringPrecise( /// 阻尼比 /// 弹簧刚度(实际上直接作为自然频率使用) /// 新的位移值 - public static float SpringSimpleVelocitySmoothing( - float deltaTime, - float currentValue, - float currentVelocity, - float targetValue, - out float newVelocity, - ref float intermediatePosition, - float smothingVelocity = 2f, - float stiffness = 1.0f) + public static double SpringSimpleVelocitySmoothing( + double deltaTime, + double currentValue, + double currentVelocity, + double targetValue, + out double newVelocity, + ref double intermediatePosition, + double smothingVelocity = 2d, + double stiffness = 1.0d) { // 按照原始版本的设计,直接使用stiffness作为自然频率 - float naturalFreq = stiffness; + double naturalFreq = stiffness; + + // 计算目标与中间位置的差值 + double targetIntermediateDiff = targetValue - intermediatePosition; + double absTargetIntermediateDiff = Math.Abs(targetIntermediateDiff); // 计算速度方向 - float velocityDirection = ((targetValue - intermediatePosition) > 0.0f ? 1.0f : -1.0f) * smothingVelocity; + double velocityDirection = (targetIntermediateDiff > 0.0d ? 1.0d : -1.0d) * smothingVelocity; // 计算预期时间 - float anticipatedTime = 1 / naturalFreq; + double anticipatedTime = 1d / naturalFreq; // 计算未来目标位置 - float futureTargetPosition = Math.Abs(targetValue - intermediatePosition) > anticipatedTime * smothingVelocity ? + double futureTargetPosition = absTargetIntermediateDiff > anticipatedTime * smothingVelocity ? intermediatePosition + velocityDirection * anticipatedTime : targetValue; // 直接调用SpringSimple函数 - float result = SpringSimple(deltaTime, currentValue, currentVelocity, futureTargetPosition, out newVelocity, stiffness); + double result = SpringSimple(deltaTime, currentValue, currentVelocity, futureTargetPosition, out newVelocity, stiffness); // 更新中间位置 - intermediatePosition = Math.Abs(targetValue - intermediatePosition) > deltaTime * smothingVelocity ? + intermediatePosition = absTargetIntermediateDiff > deltaTime * smothingVelocity ? intermediatePosition + velocityDirection * deltaTime : targetValue; return result; @@ -268,37 +272,37 @@ public static float SpringSimpleVelocitySmoothing( /// 弹簧刚度(实际上直接作为自然频率使用) /// 预期系数,用于预测未来目标位置 /// 新的位移值 - public static float SpringSimpleDurationLimit( - float deltaTime, - float currentValue, - float currentVelocity, - float targetValue, - out float newVelocity, - ref float intermediatePosition, - float durationSeconds = 0.2f, - float stiffness = 1.0f) + public static double SpringSimpleDurationLimit( + double deltaTime, + double currentValue, + double currentVelocity, + double targetValue, + out double newVelocity, + ref double intermediatePosition, + double durationSeconds = 0.2d, + double stiffness = 1.0d) { - // 按照原始版本的设计,直接使用stiffness作为自然频率 - float naturalFreq = stiffness; - float tGoal = durationSeconds; // 对应原始版本的 t_goal + // 直接使用stiffness作为自然频率 + double naturalFreq = stiffness; + double tGoal = durationSeconds; - // 计算最小时间,对应原始版本的 min_time = t_goal > dt ? t_goal : dt - float minTime = tGoal > deltaTime ? tGoal : deltaTime; + // 计算最小时间 + double minTime = tGoal > deltaTime ? tGoal : deltaTime; - // 基于中间位置计算目标速度,对应原始版本的 v_goal = (x_goal - xi) / min_time - float targetVel = (targetValue - intermediatePosition) / minTime; + // 基于中间位置计算目标速度 + double targetVel = (targetValue - intermediatePosition) / minTime; - // 计算预期时间,对应原始版本的 t_goal_future = halflife_to_lag(halflife) - float anticipatedTime = 1 / naturalFreq; // 对应 halflife_to_lag(halflife) + // 计算预期时间 + double anticipatedTime = 1d / naturalFreq; - // 计算未来目标位置,对应原始版本的 x_goal_future - float futureTargetPosition = anticipatedTime < tGoal ? + // 计算未来目标位置 + double futureTargetPosition = anticipatedTime < tGoal ? intermediatePosition + targetVel * anticipatedTime : targetValue; - // 直接调用SpringSimple函数,对应原始版本的 simple_spring_damper_exact - float result = SpringSimple(deltaTime, currentValue, currentVelocity, futureTargetPosition, out newVelocity, stiffness); + // 直接调用SpringSimple函数 + double result = SpringSimple(deltaTime, currentValue, currentVelocity, futureTargetPosition, out newVelocity, stiffness); - // 更新中间位置,对应原始版本的 xi += v_goal * dt + // 更新中间位置 intermediatePosition += targetVel * deltaTime; return result; @@ -317,45 +321,45 @@ public static float SpringSimpleDurationLimit( /// 阻尼比 /// 弹簧刚度(实际上直接作为自然频率使用) /// 新的位移值 - public static float SpringSimpleDoubleSmoothing( - float deltaTime, - float currentValue, - float currentVelocity, - float targetValue, - out float newVelocity, - ref float intermediatePosition, - ref float intermediateVelocity, - float stiffness = 1.0f) + public static double SpringSimpleDoubleSmoothing( + double deltaTime, + double currentValue, + double currentVelocity, + double targetValue, + out double newVelocity, + ref double intermediatePosition, + ref double intermediateVelocity, + double stiffness = 1.0d) { - float doubleStiffness = 2.0f * stiffness; + double doubleStiffness = 2.0d * stiffness; - // 第一层弹簧:从中间位置到目标位置,对应原始版本的 simple_spring_damper_exact(xi, vi, x_goal, 0.5f * halflife, dt) + // 第一层弹簧:从中间位置到目标位置 // 直接修改intermediatePosition和intermediateVelocity intermediatePosition = SpringSimple(deltaTime, intermediatePosition, intermediateVelocity, targetValue, out intermediateVelocity, doubleStiffness); - // 第二层弹簧:从当前位置到中间位置,对应原始版本的 simple_spring_damper_exact(x, v, xi, 0.5f * halflife, dt) + // 第二层弹簧:从当前位置到中间位置 // 使用修改后的intermediatePosition作为目标 return SpringSimple(deltaTime, currentValue, currentVelocity, intermediatePosition, out newVelocity, doubleStiffness); } - private static double HalfLifeToDamping(double halfLife, double eps = 1e-5f) + private static double HalfLifeToDamping(double halfLife, double eps = 1e-5d) { return (4.0d * 0.6931471805599453d) / (halfLife + eps); } - private static double DampingToHalfLife(double damping, double eps = 1e-5f) + private static double DampingToHalfLife(double damping, double eps = 1e-5d) { return (4.0d * 0.6931471805599453d) / (damping + eps); } private static double DampingRatioToStiffness(double ratio, double damping) { - return Square(damping / (ratio * 2.0f)); + return Square(damping / (ratio * 2.0d)); } private static double DampingRatioToDamping(double ratio, double stiffness) { - return ratio * 2.0f * Math.Sqrt(stiffness); + return ratio * 2.0d * Math.Sqrt(stiffness); } private static double FrequencyToStiffness(double frequency) @@ -368,9 +372,9 @@ private static double FrequencyToStiffness(double frequency) /// /// 半衰期(秒) /// 自然频率(rad/s) - private static float HalflifeToNaturalFreq(float halflife) + private static double HalflifeToNaturalFreq(double halflife) { - return 0.69314718056f / halflife; // ω₀ = ln(2) / τ₁/₂ + return 0.69314718056d / halflife; // ω₀ = ln(2) / τ₁/₂ } /// @@ -378,9 +382,9 @@ private static float HalflifeToNaturalFreq(float halflife) /// /// 自然频率(rad/s) /// 半衰期(秒) - private static float NaturalFreqToHalflife(float naturalFreq) + private static double NaturalFreqToHalflife(double naturalFreq) { - return 0.69314718056f / naturalFreq; // τ₁/₂ = ln(2) / ω₀ + return 0.69314718056d / naturalFreq; // τ₁/₂ = ln(2) / ω₀ } private static double FastNegExp(double x) { @@ -398,9 +402,9 @@ private static double Square(double x) private static double FastAtan(double x) { double z = Math.Abs(x); - double w = z > 1.0 ? 1.0 / z : z; - double y = (Math.PI / 4.0) * w - w * (w - 1) * (0.2447 + 0.0663 * w); - return Math.Sign(x) * (z > 1.0 ? Math.PI / 2.0 - y : y); + double w = z > 1.0d ? 1.0d / z : z; + double y = (Math.PI / 4.0d) * w - w * (w - 1) * (0.2447d + 0.0663d * w); + return Math.Sign(x) * (z > 1.0d ? Math.PI / 2.0d - y : y); } /// @@ -423,15 +427,15 @@ private static double FastSquare(double x) /// 目标速度(到达目标位置时的期望速度) /// 计算精度容差 /// 当前动画值 - public static float GetSpringValueAndVelocityFromNanos( + public static double GetSpringValueAndVelocityFromNanos( long playTimeNanos, - float initialValue, - float targetValue, - float initialVelocity, - float dampingRatio = 0.5f, - float stiffness = 1.0f, - float targetVelocity = 0.0f, - float precision = 1e-5f) + double initialValue, + double targetValue, + double initialVelocity, + double dampingRatio = 0.5f, + double stiffness = 1.0d, + double targetVelocity = 0.0d, + double precision = 1e-5f) { // TODO: 在弹簧实现中正确支持纳秒 long playTimeMillis = playTimeNanos / 1_000_000L; From 46ab302e97192b4e68cdd213a71b12424a312b3c Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Sun, 21 Sep 2025 06:08:25 +0800 Subject: [PATCH 21/55] =?UTF-8?q?=E6=96=B0=E5=A2=9ESpring=E5=8A=A8?= =?UTF-8?q?=E7=94=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按照原有的方式增加了Spring动画类型 按现在的写法性能会稍差,毕竟正常来说应该把热点逻辑和Tween一样放在update里 不过先按照第一版用着吧,先跑起来再说 --- .../Runtime/Adapters/SpringMotionAdapters.cs | 41 +++++++++ .../LitMotion/Runtime/Internal/MotionData.cs | 3 +- .../LitMotion/Runtime/LMotion.Spring.cs | 27 ++++++ .../Runtime/MotionEvaluationContext.cs | 5 ++ .../LitMotion/Runtime/MotionUpdateJob.cs | 2 +- .../Runtime/Options/SpringOptions.cs | 87 +++++++++++++++++++ 6 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs create mode 100644 src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs new file mode 100644 index 00000000..b76ce864 --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs @@ -0,0 +1,41 @@ +using Unity.Jobs; +using UnityEngine; +using LitMotion; +using LitMotion.Adapters; + +[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] + +namespace LitMotion.Adapters +{ + public readonly struct FloatSpringMotionAdapter : IMotionAdapter + { + public float Evaluate(ref float startValue, ref float endValue, ref SpringOptions options, in MotionEvaluationContext context) + { + // 更新SpringOptions中的当前状态 + options.CurrentValue = startValue; + options.TargetValue = endValue; + + // 使用MotionEvaluationContext中的DeltaTime + double deltaTime = context.DeltaTime; + + // 调用SpringElastic函数计算新的位置和速度 + double newVelocity; + double newPosition = SpringUtility.SpringElastic( + deltaTime, + options.CurrentValue, + options.CurrentVelocity, + options.TargetValue, + out newVelocity, + options.TargetVelocity, + options.DampingRatio, + options.Stiffness + ); + + // 更新SpringOptions中的状态 + options.CurrentValue = (float)newPosition; + options.CurrentVelocity = (float)newVelocity; + + return (float)newPosition; + } + } +} diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs index 54405a7a..3d9a5d2b 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs @@ -224,7 +224,7 @@ internal struct MotionData public TValue EndValue; public TOptions Options; - public void Update(double time, out TValue result) + public void Update(double time, double deltaTime, out TValue result) where TAdapter : unmanaged, IMotionAdapter { Core.Update(time, out var progress); @@ -233,6 +233,7 @@ public void Update(double time, out TValue result) { Progress = progress, Time = time, + DeltaTime = deltaTime, }); } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs new file mode 100644 index 00000000..405823dd --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs @@ -0,0 +1,27 @@ +using UnityEngine; +using LitMotion.Adapters; + +namespace LitMotion +{ + public static partial class LMotion + { + /// + /// API for creating Spring motions. + /// + public static class Spring + { + /// + /// Create a builder for building Spring motion. + /// + /// Start value + /// End value + /// Duration + /// Created motion builder + public static MotionBuilder Create(float startValue, float endValue, float duration, SpringOptions options) + { + return Create(startValue, endValue, duration) + .WithOptions(options); + } + } + } +} diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionEvaluationContext.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionEvaluationContext.cs index fe1ed479..a82206bf 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionEvaluationContext.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionEvaluationContext.cs @@ -14,5 +14,10 @@ public struct MotionEvaluationContext /// Current motion time /// public double Time; + + /// + /// Delta time for this frame + /// + public double DeltaTime; } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs index f61a4b2b..44fe826e 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs @@ -46,7 +46,7 @@ public void Execute([AssumeRange(0, int.MaxValue)] int index) }; var time = state.Time + deltaTime * state.PlaybackSpeed; - ptr->Update(time, out var result); + ptr->Update(time, deltaTime, out var result); Output[index] = result; } else if ((!state.IsPreserved && state.Status is MotionStatus.Completed) || state.Status is MotionStatus.Canceled) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs new file mode 100644 index 00000000..73378420 --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs @@ -0,0 +1,87 @@ +using System; + +namespace LitMotion +{ + /// + /// Options for spring motion. + /// + [Serializable] + public struct SpringOptions : IEquatable, IMotionOptions + { + public float CurrentValue; + public float CurrentVelocity; + public float TargetValue; + public float TargetVelocity; + public float Stiffness; + public float DampingRatio; + + public static SpringOptions Critical + { + get + { + return new SpringOptions() + { + Stiffness = 10.0f, + DampingRatio = 1.0f, + TargetVelocity = 0.0f, + CurrentValue = 0.0f, + CurrentVelocity = 0.0f, + TargetValue = 1.0f + }; + } + } + + public static SpringOptions Overdamped + { + get + { + return new SpringOptions() + { + Stiffness = 10.0f, + DampingRatio = 1.2f, + TargetVelocity = 0.0f, + CurrentValue = 0.0f, + CurrentVelocity = 0.0f, + TargetValue = 1.0f + }; + } + } + + public static SpringOptions Underdamped + { + get + { + return new SpringOptions() + { + Stiffness = 10.0f, + DampingRatio = 0.6f, + TargetVelocity = 0.0f, + CurrentValue = 0.0f, + CurrentVelocity = 0.0f, + TargetValue = 1.0f + }; + } + } + + public readonly bool Equals(SpringOptions other) + { + return Stiffness == other.Stiffness && + DampingRatio == other.DampingRatio && + TargetVelocity == other.TargetVelocity && + CurrentValue == other.CurrentValue && + CurrentVelocity == other.CurrentVelocity && + TargetValue == other.TargetValue; + } + + public override readonly bool Equals(object obj) + { + if (obj is SpringOptions options) return Equals(options); + return false; + } + + public override readonly int GetHashCode() + { + return HashCode.Combine(Stiffness, DampingRatio, TargetVelocity, CurrentValue, CurrentVelocity, TargetValue); + } + } +} From 0a0cd14251e6e1783853013f03705da1f2ca896a Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Mon, 22 Sep 2025 03:53:42 +0800 Subject: [PATCH 22/55] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8A=A8=E7=94=BB?= =?UTF-8?q?=E4=B8=AD=E5=8A=A8=E6=80=81=E4=BF=AE=E6=94=B9=E7=BB=93=E6=9D=9F?= =?UTF-8?q?=E5=80=BC=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=A2=9E=E5=8A=A0=E5=A4=9A?= =?UTF-8?q?=E7=BB=B4=E5=BC=B9=E7=B0=A7=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Runtime/Adapters/SpringMotionAdapters.cs | 141 ++++++++- .../Runtime/Internal/MotionManager.cs | 8 + .../Runtime/Internal/MotionStorage.cs | 13 +- .../LitMotion/Runtime/LMotion.Spring.cs | 43 +++ .../Assets/LitMotion/Runtime/MotionHandle.cs | 14 + .../Runtime/Options/SpringOptions.cs | 30 +- .../Assets/LitMotion/Runtime/SpringUtility.cs | 273 ++++++++++++++++++ 7 files changed, 490 insertions(+), 32 deletions(-) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs index b76ce864..7ae9f1e9 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs @@ -1,9 +1,13 @@ using Unity.Jobs; using UnityEngine; +using Unity.Mathematics; using LitMotion; using LitMotion.Adapters; [assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] +[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] +[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] +[assembly: RegisterGenericJobType(typeof(MotionUpdateJob))] namespace LitMotion.Adapters { @@ -11,10 +15,6 @@ namespace LitMotion.Adapters { public float Evaluate(ref float startValue, ref float endValue, ref SpringOptions options, in MotionEvaluationContext context) { - // 更新SpringOptions中的当前状态 - options.CurrentValue = startValue; - options.TargetValue = endValue; - // 使用MotionEvaluationContext中的DeltaTime double deltaTime = context.DeltaTime; @@ -22,20 +22,137 @@ public float Evaluate(ref float startValue, ref float endValue, ref SpringOption double newVelocity; double newPosition = SpringUtility.SpringElastic( deltaTime, - options.CurrentValue, - options.CurrentVelocity, - options.TargetValue, + startValue, + options.CurrentVelocity.x, + endValue, out newVelocity, - options.TargetVelocity, + options.TargetVelocity.x, options.DampingRatio, options.Stiffness ); + options.CurrentVelocity.x = (float)newVelocity; + startValue = (float)newPosition; + return (float)newPosition; + } + } + + /// + /// Vector2 Spring适配器,使用float4版本的SpringElastic方法 + /// + public readonly struct Vector2SpringMotionAdapter : IMotionAdapter + { + public Vector2 Evaluate(ref Vector2 startValue, ref Vector2 endValue, ref SpringOptions options, in MotionEvaluationContext context) + { + // 使用MotionEvaluationContext中的DeltaTime + float deltaTime = (float)context.DeltaTime; - // 更新SpringOptions中的状态 - options.CurrentValue = (float)newPosition; - options.CurrentVelocity = (float)newVelocity; + // 转换为float4进行计算 + float4 f4StartValue = new float4(startValue, 0, 0); + float4 f4EndValue = new float4(endValue, 0, 0); + float4 f4CurrentVelocity = new float4(options.CurrentVelocity.x, options.CurrentVelocity.y, 0, 0); + float4 f4TargetVelocity = new float4(options.TargetVelocity.x, options.TargetVelocity.y, 0, 0); - return (float)newPosition; + // 使用float4版本的SpringElastic + float4 f4NewPosition = SpringUtility.SpringElastic( + deltaTime, + f4StartValue, + f4CurrentVelocity, + f4EndValue, + out float4 f4NewVelocity, + f4TargetVelocity, + options.DampingRatio, + options.Stiffness + ); + + // 更新速度和位置(通过ref修改,不使用new) + options.CurrentVelocity.x = f4NewVelocity.x; + options.CurrentVelocity.y = f4NewVelocity.y; + startValue.x = f4NewPosition.x; + startValue.y = f4NewPosition.y; + + return startValue; + } + } + + /// + /// Vector3 Spring适配器,使用float4版本的SpringElastic方法 + /// + public readonly struct Vector3SpringMotionAdapter : IMotionAdapter + { + public Vector3 Evaluate(ref Vector3 startValue, ref Vector3 endValue, ref SpringOptions options, in MotionEvaluationContext context) + { + // 使用MotionEvaluationContext中的DeltaTime + float deltaTime = (float)context.DeltaTime; + + // 转换为float4进行计算 + float4 f4StartValue = new float4(startValue, 0); + float4 f4EndValue = new float4(endValue, 0); + float4 f4CurrentVelocity = new float4(options.CurrentVelocity.x, options.CurrentVelocity.y, options.CurrentVelocity.z, 0); + float4 f4TargetVelocity = new float4(options.TargetVelocity.x, options.TargetVelocity.y, options.TargetVelocity.z, 0); + + // 使用float4版本的SpringElastic + float4 f4NewPosition = SpringUtility.SpringElastic( + deltaTime, + f4StartValue, + f4CurrentVelocity, + f4EndValue, + out float4 f4NewVelocity, + f4TargetVelocity, + options.DampingRatio, + options.Stiffness + ); + + // 更新速度和位置(通过ref修改,不使用new) + options.CurrentVelocity.x = f4NewVelocity.x; + options.CurrentVelocity.y = f4NewVelocity.y; + options.CurrentVelocity.z = f4NewVelocity.z; + startValue.x = f4NewPosition.x; + startValue.y = f4NewPosition.y; + startValue.z = f4NewPosition.z; + + return startValue; + } + } + + /// + /// Vector4 Spring适配器,使用float4版本的SpringElastic方法 + /// + public readonly struct Vector4SpringMotionAdapter : IMotionAdapter + { + public Vector4 Evaluate(ref Vector4 startValue, ref Vector4 endValue, ref SpringOptions options, in MotionEvaluationContext context) + { + // 使用MotionEvaluationContext中的DeltaTime + float deltaTime = (float)context.DeltaTime; + + // 转换为float4进行计算 + float4 f4StartValue = startValue; + float4 f4EndValue = endValue; + float4 f4CurrentVelocity = options.CurrentVelocity; + float4 f4TargetVelocity = options.TargetVelocity; + + // 使用float4版本的SpringElastic + float4 f4NewPosition = SpringUtility.SpringElastic( + deltaTime, + f4StartValue, + f4CurrentVelocity, + f4EndValue, + out float4 f4NewVelocity, + f4TargetVelocity, + options.DampingRatio, + options.Stiffness + ); + + // 更新速度和位置(通过ref修改,不使用new) + options.CurrentVelocity.x = f4NewVelocity.x; + options.CurrentVelocity.y = f4NewVelocity.y; + options.CurrentVelocity.z = f4NewVelocity.z; + options.CurrentVelocity.w = f4NewVelocity.w; + startValue.x = f4NewPosition.x; + startValue.y = f4NewPosition.y; + startValue.z = f4NewPosition.z; + startValue.w = f4NewPosition.w; + + return startValue; } } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionManager.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionManager.cs index 940b5441..e6a5ad01 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionManager.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionManager.cs @@ -25,6 +25,14 @@ public static ref MotionData GetDataRef(MotionHandle handle, bool checkIsInSeque CheckTypeId(handle); return ref list[handle.StorageId].GetDataRef(handle, checkIsInSequence); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref MotionData GetTypeDataRef(MotionHandle handle, bool checkIsInSequence = true) + where TValue : unmanaged + where TOptions : unmanaged, IMotionOptions + { + CheckTypeId(handle); + return ref list[handle.StorageId].GetTypeDataRef(handle, checkIsInSequence); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref ManagedMotionData GetManagedDataRef(MotionHandle handle, bool checkIsInSequence = true) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStorage.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStorage.cs index 55d55177..2c252022 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStorage.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStorage.cs @@ -27,6 +27,9 @@ internal interface IMotionStorage void Complete(MotionHandle handle, bool checkIsInSequence = true); void SetTime(MotionHandle handle, double time, bool checkIsInSequence = true); ref MotionData GetDataRef(MotionHandle handle, bool checkIsInSequence = true); + ref MotionData GetTypeDataRef(MotionHandle handle, bool checkIsInSequence = true) + where ValueType : unmanaged + where OptionsType : unmanaged, IMotionOptions; ref ManagedMotionData GetManagedDataRef(MotionHandle handle, bool checkIsInSequence = true); void AddToSequence(MotionHandle handle, out double motionDuration); MotionDebugInfo GetDebugInfo(MotionHandle handle); @@ -377,7 +380,7 @@ public unsafe void SetTime(MotionHandle handle, double time, bool checkIsInSeque if (checkIsInSequence && state.IsInSequence) Error.MotionIsInSequence(); - dataPtr->Update(time, out var result); + dataPtr->Update(time, time - state.Time, out var result); var status = state.Status; ref var managedData = ref managedDataArray[denseIndex]; @@ -444,6 +447,14 @@ public ref MotionData GetDataRef(MotionHandle handle, bool checkIsInSequence = t return ref UnsafeUtility.As, MotionData>(ref unmanagedDataArray[slot.DenseIndex]); } + public ref MotionData GetTypeDataRef(MotionHandle handle, bool checkIsInSequence = true) + where ValueType : unmanaged + where OptionsType : unmanaged, IMotionOptions + { + ref var slot = ref GetSlotWithVarify(handle, checkIsInSequence); + return ref UnsafeUtility.As, MotionData>(ref unmanagedDataArray[slot.DenseIndex]); + } + public MotionDebugInfo GetDebugInfo(MotionHandle handle) { ref var slot = ref GetSlotWithVarify(handle, false); diff --git a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs index 405823dd..48e455f3 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs @@ -16,12 +16,55 @@ public static class Spring /// Start value /// End value /// Duration + /// Spring options /// Created motion builder public static MotionBuilder Create(float startValue, float endValue, float duration, SpringOptions options) { return Create(startValue, endValue, duration) .WithOptions(options); } + + /// + /// Create a builder for building Vector2 Spring motion. + /// + /// Start value + /// End value + /// Duration + /// Spring options + /// Created motion builder + public static MotionBuilder Create(Vector2 startValue, Vector2 endValue, float duration, SpringOptions options) + { + return Create(startValue, endValue, duration) + .WithOptions(options); + } + + /// + /// Create a builder for building Vector3 Spring motion. + /// + /// Start value + /// End value + /// Duration + /// Spring options + /// Created motion builder + public static MotionBuilder Create(Vector3 startValue, Vector3 endValue, float duration, SpringOptions options) + { + return Create(startValue, endValue, duration) + .WithOptions(options); + } + + /// + /// Create a builder for building Vector4 Spring motion. + /// + /// Start value + /// End value + /// Duration + /// Spring options + /// Created motion builder + public static MotionBuilder Create(Vector4 startValue, Vector4 endValue, float duration, SpringOptions options) + { + return Create(startValue, endValue, duration) + .WithOptions(options); + } } } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs index 46dbd84b..38455b7f 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs @@ -112,6 +112,20 @@ public readonly float PlaybackSpeed } } + public TValue GetEndValue(bool checkIsInSequence = true) + where TValue : unmanaged + where TOptions : unmanaged, IMotionOptions + { + return MotionManager.GetTypeDataRef(this, checkIsInSequence).EndValue; + } + + public void SetEndValue(TValue value, bool checkIsInSequence = true) + where TValue : unmanaged + where TOptions : unmanaged, IMotionOptions + { + MotionManager.GetTypeDataRef(this, checkIsInSequence).EndValue = value; + } + public override readonly string ToString() { return $"MotionHandle`{StorageId} ({Index}:{Version})"; diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs index 73378420..0898dcb6 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs @@ -1,4 +1,5 @@ using System; +using UnityEngine; namespace LitMotion { @@ -8,10 +9,8 @@ namespace LitMotion [Serializable] public struct SpringOptions : IEquatable, IMotionOptions { - public float CurrentValue; - public float CurrentVelocity; - public float TargetValue; - public float TargetVelocity; + public Vector4 CurrentVelocity; + public Vector4 TargetVelocity; public float Stiffness; public float DampingRatio; @@ -23,10 +22,8 @@ public static SpringOptions Critical { Stiffness = 10.0f, DampingRatio = 1.0f, - TargetVelocity = 0.0f, - CurrentValue = 0.0f, - CurrentVelocity = 0.0f, - TargetValue = 1.0f + CurrentVelocity = new Vector4(0.0f, 0.0f, 0.0f, 0.0f), + TargetVelocity = new Vector4(1.0f, 0.0f, 0.0f, 0.0f) }; } } @@ -39,10 +36,8 @@ public static SpringOptions Overdamped { Stiffness = 10.0f, DampingRatio = 1.2f, - TargetVelocity = 0.0f, - CurrentValue = 0.0f, - CurrentVelocity = 0.0f, - TargetValue = 1.0f + CurrentVelocity = new Vector4(0.0f, 0.0f, 0.0f, 0.0f), + TargetVelocity = new Vector4(1.0f, 0.0f, 0.0f, 0.0f) }; } } @@ -55,10 +50,8 @@ public static SpringOptions Underdamped { Stiffness = 10.0f, DampingRatio = 0.6f, - TargetVelocity = 0.0f, - CurrentValue = 0.0f, - CurrentVelocity = 0.0f, - TargetValue = 1.0f + CurrentVelocity = new Vector4(0.0f, 0.0f, 0.0f, 0.0f), + TargetVelocity = new Vector4(1.0f, 0.0f, 0.0f, 0.0f) }; } } @@ -68,9 +61,8 @@ public readonly bool Equals(SpringOptions other) return Stiffness == other.Stiffness && DampingRatio == other.DampingRatio && TargetVelocity == other.TargetVelocity && - CurrentValue == other.CurrentValue && CurrentVelocity == other.CurrentVelocity && - TargetValue == other.TargetValue; + TargetVelocity == other.TargetVelocity; } public override readonly bool Equals(object obj) @@ -81,7 +73,7 @@ public override readonly bool Equals(object obj) public override readonly int GetHashCode() { - return HashCode.Combine(Stiffness, DampingRatio, TargetVelocity, CurrentValue, CurrentVelocity, TargetValue); + return HashCode.Combine(Stiffness, DampingRatio, TargetVelocity, CurrentVelocity, TargetVelocity); } } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs index 3bf34414..c6c8459c 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs @@ -1,5 +1,7 @@ using System; using Unity.Burst; +using Unity.Mathematics; +using UnityEngine; using static Unity.Mathematics.math; namespace LitMotion { @@ -342,6 +344,261 @@ public static double SpringSimpleDoubleSmoothing( return SpringSimple(deltaTime, currentValue, currentVelocity, intermediatePosition, out newVelocity, doubleStiffness); } +#region float4版本的Spring函数 + + /// + /// 简易弹簧阻尼器,只有临界阻尼,没有过阻尼和欠阻尼 + /// + /// 经过时间(毫秒) + /// 当前值 + /// 当前速度 + /// 目标值 + /// 输出新的速度 + /// 阻尼比 + /// 弹簧刚度(实际上直接作为自然频率使用) + /// 新的位移值 + public static float4 SpringSimple( + float deltaTime, + float4 currentValue, + float4 currentVelocity, + float4 targetValue, + out float4 newVelocity, + float stiffness = 1.0f) + { + // SpringSimple是专门为临界阻尼设计的简化版本 + // 直接使用stiffness作为自然频率,阻尼系数的一半等于自然频率 + float naturalFreq = stiffness; + + // 临界阻尼的计算逻辑 + float4 displacementFromTarget = currentValue - targetValue; // 当前位置与目标的位移差 + float4 velocityWithDamping = currentVelocity + displacementFromTarget * naturalFreq; // 考虑阻尼的初始速度 + float4 exponentialDecay = (float4)FastNegExp(naturalFreq * deltaTime); // 指数衰减因子 + + // 临界阻尼的更新公式 + float4 newPosition = exponentialDecay * (displacementFromTarget + velocityWithDamping * deltaTime) + targetValue; // 新位置 + float4 newVel = exponentialDecay * (currentVelocity - velocityWithDamping * naturalFreq * deltaTime); // 新速度 + + newVelocity = newVel; + return newPosition; + } + + /// + /// 近似弹性弹簧阻尼器,float4版本,有过阻尼和欠阻尼和临界阻尼,采用高性能近似算法 + /// + /// 时间步长(秒) + /// 当前值 + /// 当前速度 + /// 目标值 + /// 输出新的速度 + /// 目标速度(到达目标位置时的期望速度) + /// 阻尼比 0.6 = Q弹 1 = 临界 1.2 = 稍缓 + /// 弹簧刚度(实际上直接作为自然频率使用)5 = 1秒 10 = 0.5秒 16.5 = 0.2秒 + /// 计算精度容差 + /// 新的位移值 + public static float4 SpringElastic( + float deltaTime, + float4 currentValue, + float4 currentVelocity, + float4 targetValue, + out float4 newVelocity, + float4 targetVelocity = default, + float dampingRatio = 0.5f, + float stiffness = 1.0f, + float precision = 1e-5f) + { + // 使用有意义的变量名,提高代码可读性 + float4 currentPosition = currentValue; + float4 currentVel = currentVelocity; + float4 targetPosition = targetValue; + float4 targetVel = targetVelocity; + // 将stiffness参数重命名为naturalFreq进行内部计算 + float naturalFreq = stiffness; + float stiffnessValue = naturalFreq * naturalFreq; // 刚度值 = naturalFreq² + float dampingHalf = dampingRatio * naturalFreq; + float dampingCoeff = 2.0f * dampingHalf; // 阻尼系数 = 2 * 阻尼比 * naturalFreq + float4 adjustedTargetPosition = targetPosition + (dampingCoeff * targetVel) / (stiffnessValue + precision); + + if (math.abs(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f) < precision) // Critically Damped + { + float4 initialDisplacement = currentPosition - adjustedTargetPosition; + float4 initialVelocityWithDamping = currentVel + initialDisplacement * dampingHalf; + + float exponentialDecay = (float)FastNegExp((double)(dampingHalf * deltaTime)); + + currentPosition = initialDisplacement * exponentialDecay + deltaTime * initialVelocityWithDamping * exponentialDecay + adjustedTargetPosition; + currentVel = -dampingHalf * initialDisplacement * exponentialDecay - dampingHalf * deltaTime * initialVelocityWithDamping * exponentialDecay + initialVelocityWithDamping * exponentialDecay; + } + else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f > 0.0f) // Under Damped + { + float dampedFrequency = math.sqrt(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f); + float4 displacementFromTarget = currentPosition - adjustedTargetPosition; + float4 amplitude = math.sqrt(Square(currentVel + dampingHalf * displacementFromTarget) / (dampedFrequency * dampedFrequency + precision) + Square(displacementFromTarget)); + float4 phase = FastAtan((currentVel + displacementFromTarget * dampingHalf) / (-displacementFromTarget * dampedFrequency + precision)); + + amplitude = math.select(-amplitude, amplitude, displacementFromTarget > 0.0f); + + float exponentialDecay = (float)FastNegExp((double)(dampingHalf * deltaTime)); + + currentPosition = amplitude * exponentialDecay * math.cos(dampedFrequency * deltaTime + phase) + adjustedTargetPosition; + currentVel = -dampingHalf * amplitude * exponentialDecay * math.cos(dampedFrequency * deltaTime + phase) - dampedFrequency * amplitude * exponentialDecay * math.sin(dampedFrequency * deltaTime + phase); + } + else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f < 0.0f) // Over Damped + { + float fastDecayRate = (dampingCoeff + math.sqrt(dampingCoeff * dampingCoeff - 4f * stiffnessValue)) / 2.0f; + float slowDecayRate = (dampingCoeff - math.sqrt(dampingCoeff * dampingCoeff - 4f * stiffnessValue)) / 2.0f; + // 计算过阻尼系数:fastDecayCoeff对应fastDecayRate,slowDecayCoeff对应slowDecayRate + float4 fastDecayCoeff = (adjustedTargetPosition * fastDecayRate - currentPosition * fastDecayRate - currentVel) / (slowDecayRate - fastDecayRate); + float4 slowDecayCoeff = currentPosition - fastDecayCoeff - adjustedTargetPosition; + + float fastExponentialDecay = (float)FastNegExp((double)(fastDecayRate * deltaTime)); + float slowExponentialDecay = (float)FastNegExp((double)(slowDecayRate * deltaTime)); + + // 过阻尼位置更新:slowDecayCoeff用fastExponentialDecay,fastDecayCoeff用slowExponentialDecay + currentPosition = slowDecayCoeff * fastExponentialDecay + fastDecayCoeff * slowExponentialDecay + adjustedTargetPosition; + currentVel = -fastDecayRate * slowDecayCoeff * fastExponentialDecay - slowDecayRate * fastDecayCoeff * slowExponentialDecay; + } + + newVelocity = currentVel; + return currentPosition; + } + + /// + /// 速度平滑弹簧阻尼器,float4版本,支持指定到达时间 + /// + /// 时间步长(秒) + /// 当前值 + /// 当前速度 + /// 目标值 + /// 输出新的速度 + /// 中间位置(用于维护状态) + /// 平滑速度 + /// 弹簧刚度(实际上直接作为自然频率使用) + /// 新的位移值 + public static float4 SpringSimpleVelocitySmoothing( + float deltaTime, + float4 currentValue, + float4 currentVelocity, + float4 targetValue, + out float4 newVelocity, + ref float4 intermediatePosition, + float smothingVelocity = 2f, + float stiffness = 1.0f) + { + // 按照原始版本的设计,直接使用stiffness作为自然频率 + float naturalFreq = stiffness; + + // 计算目标与中间位置的差值 + float4 targetIntermediateDiff = targetValue - intermediatePosition; + float4 absTargetIntermediateDiff = math.abs(targetIntermediateDiff); + + // 计算速度方向 + float4 velocityDirection = math.sign(targetIntermediateDiff) * smothingVelocity; + + // 计算预期时间 + float anticipatedTime = 1f / naturalFreq; + + // 计算未来目标位置 + float4 futureTargetPosition = math.select(targetValue, + intermediatePosition + velocityDirection * anticipatedTime, + absTargetIntermediateDiff > anticipatedTime * smothingVelocity); + + // 直接调用SpringSimple函数 + float4 result = SpringSimple(deltaTime, currentValue, currentVelocity, futureTargetPosition, out newVelocity, stiffness); + + // 更新中间位置 + intermediatePosition = math.select(targetValue, + intermediatePosition + velocityDirection * deltaTime, + absTargetIntermediateDiff > deltaTime * smothingVelocity); + + return result; + } + + /// + /// 时间限制弹簧阻尼器,float4版本,支持指定到达时间 + /// + /// 时间步长(秒) + /// 当前值 + /// 当前速度 + /// 目标值 + /// 输出新的速度 + /// 中间位置(用于维护状态) + /// 目标到达时间(秒) + /// 弹簧刚度(实际上直接作为自然频率使用) + /// 新的位移值 + public static float4 SpringSimpleDurationLimit( + float deltaTime, + float4 currentValue, + float4 currentVelocity, + float4 targetValue, + out float4 newVelocity, + ref float4 intermediatePosition, + float durationSeconds = 0.2f, + float stiffness = 1.0f) + { + // 直接使用stiffness作为自然频率 + float naturalFreq = stiffness; + float tGoal = durationSeconds; + + // 计算最小时间 + float minTime = math.max(tGoal, deltaTime); + + // 基于中间位置计算目标速度 + float4 targetVel = (targetValue - intermediatePosition) / minTime; + + // 计算预期时间 + float anticipatedTime = 1f / naturalFreq; + + // 计算未来目标位置 + float4 futureTargetPosition = math.select(targetValue, + intermediatePosition + targetVel * anticipatedTime, + anticipatedTime < tGoal); + + // 直接调用SpringSimple函数 + float4 result = SpringSimple(deltaTime, currentValue, currentVelocity, futureTargetPosition, out newVelocity, stiffness); + + // 更新中间位置 + intermediatePosition += targetVel * deltaTime; + + return result; + } + + /// + /// 双重平滑弹簧阻尼器,float4版本,使用两个串联的弹簧系统实现更平滑的运动 + /// + /// 时间步长(秒) + /// 当前值 + /// 当前速度 + /// 目标值 + /// 输出新的速度 + /// 中间位置(用于维护状态) + /// 中间速度(用于维护状态) + /// 弹簧刚度(实际上直接作为自然频率使用) + /// 新的位移值 + public static float4 SpringSimpleDoubleSmoothing( + float deltaTime, + float4 currentValue, + float4 currentVelocity, + float4 targetValue, + out float4 newVelocity, + ref float4 intermediatePosition, + ref float4 intermediateVelocity, + float stiffness = 1.0f) + { + float doubleStiffness = 2.0f * stiffness; + + // 第一层弹簧:从中间位置到目标位置 + // 直接修改intermediatePosition和intermediateVelocity + intermediatePosition = SpringSimple(deltaTime, intermediatePosition, intermediateVelocity, targetValue, out intermediateVelocity, doubleStiffness); + + // 第二层弹簧:从当前位置到中间位置 + // 使用修改后的intermediatePosition作为目标 + return SpringSimple(deltaTime, currentValue, currentVelocity, intermediatePosition, out newVelocity, doubleStiffness); + } + + #endregion + + + private static double HalfLifeToDamping(double halfLife, double eps = 1e-5d) { return (4.0d * 0.6931471805599453d) / (halfLife + eps); @@ -396,6 +653,11 @@ private static double Square(double x) return x * x; } + private static float4 Square(float4 x) + { + return x * x; + } + /// /// 快速反正切函数近似,比Math.Atan快2-5倍,精度损失很小 /// @@ -407,6 +669,17 @@ private static double FastAtan(double x) return Math.Sign(x) * (z > 1.0d ? Math.PI / 2.0d - y : y); } + /// + /// 快速反正切函数近似,float4版本 + /// + private static float4 FastAtan(float4 x) + { + float4 z = math.abs(x); + float4 w = math.select(1.0f / z, z, z <= 1.0f); + float4 y = (math.PI / 4.0f) * w - w * (w - 1.0f) * (0.2447f + 0.0663f * w); + return math.sign(x) * math.select(math.PI / 2.0f - y, y, z <= 1.0f); + } + /// /// 快速平方函数,与直接乘法性能相同 /// From fbcf242561fe52fed30cc637ea23bc1a78abea4c Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Tue, 23 Sep 2025 08:34:42 +0800 Subject: [PATCH 23/55] =?UTF-8?q?floatX=E7=9A=84=E5=A4=9A=E7=BB=B4?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E9=98=BB=E5=B0=BC=E5=99=A8=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E8=A6=81=E6=94=B9=E6=88=90ref=E6=89=8D=E8=83=BD=E9=80=9A?= =?UTF-8?q?=E8=BF=87burst=E7=BC=96=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Runtime/Adapters/SpringMotionAdapters.cs | 60 ++++---- .../Assets/LitMotion/Runtime/SpringUtility.cs | 136 +++++++++--------- 2 files changed, 105 insertions(+), 91 deletions(-) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs index 7ae9f1e9..1d220a11 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs @@ -51,15 +51,17 @@ public Vector2 Evaluate(ref Vector2 startValue, ref Vector2 endValue, ref Spring float4 f4EndValue = new float4(endValue, 0, 0); float4 f4CurrentVelocity = new float4(options.CurrentVelocity.x, options.CurrentVelocity.y, 0, 0); float4 f4TargetVelocity = new float4(options.TargetVelocity.x, options.TargetVelocity.y, 0, 0); - + float4 f4NewVelocity = default; + float4 f4NewPosition = default; // 新位置 // 使用float4版本的SpringElastic - float4 f4NewPosition = SpringUtility.SpringElastic( + SpringUtility.SpringElastic( deltaTime, - f4StartValue, - f4CurrentVelocity, - f4EndValue, - out float4 f4NewVelocity, - f4TargetVelocity, + ref f4StartValue, + ref f4CurrentVelocity, + ref f4EndValue, + ref f4NewVelocity, + ref f4TargetVelocity, + ref f4NewPosition, options.DampingRatio, options.Stiffness ); @@ -67,8 +69,8 @@ public Vector2 Evaluate(ref Vector2 startValue, ref Vector2 endValue, ref Spring // 更新速度和位置(通过ref修改,不使用new) options.CurrentVelocity.x = f4NewVelocity.x; options.CurrentVelocity.y = f4NewVelocity.y; - startValue.x = f4NewPosition.x; - startValue.y = f4NewPosition.y; + startValue.x = (float)f4NewPosition.x; + startValue.y = (float)f4NewPosition.y; return startValue; } @@ -83,7 +85,8 @@ public Vector3 Evaluate(ref Vector3 startValue, ref Vector3 endValue, ref Spring { // 使用MotionEvaluationContext中的DeltaTime float deltaTime = (float)context.DeltaTime; - + float4 f4NewVelocity = default; + float4 f4NewPosition = default; // 新位置 // 转换为float4进行计算 float4 f4StartValue = new float4(startValue, 0); float4 f4EndValue = new float4(endValue, 0); @@ -91,13 +94,14 @@ public Vector3 Evaluate(ref Vector3 startValue, ref Vector3 endValue, ref Spring float4 f4TargetVelocity = new float4(options.TargetVelocity.x, options.TargetVelocity.y, options.TargetVelocity.z, 0); // 使用float4版本的SpringElastic - float4 f4NewPosition = SpringUtility.SpringElastic( + SpringUtility.SpringElastic( deltaTime, - f4StartValue, - f4CurrentVelocity, - f4EndValue, - out float4 f4NewVelocity, - f4TargetVelocity, + ref f4StartValue, + ref f4CurrentVelocity, + ref f4EndValue, + ref f4NewVelocity, + ref f4TargetVelocity, + ref f4NewPosition, options.DampingRatio, options.Stiffness ); @@ -129,15 +133,17 @@ public Vector4 Evaluate(ref Vector4 startValue, ref Vector4 endValue, ref Spring float4 f4EndValue = endValue; float4 f4CurrentVelocity = options.CurrentVelocity; float4 f4TargetVelocity = options.TargetVelocity; - + float4 f4NewVelocity = default; + float4 f4NewPosition = default; // 新位置 // 使用float4版本的SpringElastic - float4 f4NewPosition = SpringUtility.SpringElastic( + SpringUtility.SpringElastic( deltaTime, - f4StartValue, - f4CurrentVelocity, - f4EndValue, - out float4 f4NewVelocity, - f4TargetVelocity, + ref f4StartValue, + ref f4CurrentVelocity, + ref f4EndValue, + ref f4NewVelocity, + ref f4TargetVelocity, + ref f4NewPosition, options.DampingRatio, options.Stiffness ); @@ -147,10 +153,10 @@ public Vector4 Evaluate(ref Vector4 startValue, ref Vector4 endValue, ref Spring options.CurrentVelocity.y = f4NewVelocity.y; options.CurrentVelocity.z = f4NewVelocity.z; options.CurrentVelocity.w = f4NewVelocity.w; - startValue.x = f4NewPosition.x; - startValue.y = f4NewPosition.y; - startValue.z = f4NewPosition.z; - startValue.w = f4NewPosition.w; + startValue.x = (float)f4NewPosition.x; + startValue.y = (float)f4NewPosition.y; + startValue.z = (float)f4NewPosition.z; + startValue.w = (float)f4NewPosition.w; return startValue; } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs index c6c8459c..8dc8b67d 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs @@ -5,6 +5,7 @@ using static Unity.Mathematics.math; namespace LitMotion { + [BurstCompile] public static class SpringUtility { /// @@ -29,7 +30,7 @@ public static double SpringSimple( // SpringSimple是专门为临界阻尼设计的简化版本 // 直接使用stiffness作为自然频率,阻尼系数的一半等于自然频率 double naturalFreq = stiffness; - + // 临界阻尼的计算逻辑 double displacementFromTarget = currentValue - targetValue; // 当前位置与目标的位移差 double velocityWithDamping = currentVelocity + displacementFromTarget * naturalFreq; // 考虑阻尼的初始速度 @@ -148,7 +149,7 @@ public static double SpringPrecise( { // 将stiffness参数重命名为naturalFreq进行内部计算 double naturalFreq = stiffness; - + // 根据targetVelocity调整目标位置(类似SpringElastic的逻辑) double adjustedTargetPosition = targetValue; if (Math.Abs(targetVelocity) > precision) @@ -160,7 +161,7 @@ public static double SpringPrecise( double stiffnessValue = naturalFreq * naturalFreq; adjustedTargetPosition = targetValue + (dampingCoeff * targetVelocity) / (stiffnessValue + precision); } - + double adjustedDisplacement = currentValue - adjustedTargetPosition; double dampingRatioSquared = dampingRatio * dampingRatio; double r = -dampingRatio * naturalFreq; @@ -235,17 +236,17 @@ public static double SpringSimpleVelocitySmoothing( { // 按照原始版本的设计,直接使用stiffness作为自然频率 double naturalFreq = stiffness; - + // 计算目标与中间位置的差值 double targetIntermediateDiff = targetValue - intermediatePosition; double absTargetIntermediateDiff = Math.Abs(targetIntermediateDiff); - + // 计算速度方向 double velocityDirection = (targetIntermediateDiff > 0.0d ? 1.0d : -1.0d) * smothingVelocity; // 计算预期时间 double anticipatedTime = 1d / naturalFreq; - + // 计算未来目标位置 double futureTargetPosition = absTargetIntermediateDiff > anticipatedTime * smothingVelocity ? intermediatePosition + velocityDirection * anticipatedTime : targetValue; @@ -254,7 +255,7 @@ public static double SpringSimpleVelocitySmoothing( double result = SpringSimple(deltaTime, currentValue, currentVelocity, futureTargetPosition, out newVelocity, stiffness); // 更新中间位置 - intermediatePosition = absTargetIntermediateDiff > deltaTime * smothingVelocity ? + intermediatePosition = absTargetIntermediateDiff > deltaTime * smothingVelocity ? intermediatePosition + velocityDirection * deltaTime : targetValue; return result; @@ -287,16 +288,16 @@ public static double SpringSimpleDurationLimit( // 直接使用stiffness作为自然频率 double naturalFreq = stiffness; double tGoal = durationSeconds; - + // 计算最小时间 double minTime = tGoal > deltaTime ? tGoal : deltaTime; - + // 基于中间位置计算目标速度 double targetVel = (targetValue - intermediatePosition) / minTime; // 计算预期时间 double anticipatedTime = 1d / naturalFreq; - + // 计算未来目标位置 double futureTargetPosition = anticipatedTime < tGoal ? intermediatePosition + targetVel * anticipatedTime : targetValue; @@ -334,7 +335,7 @@ public static double SpringSimpleDoubleSmoothing( double stiffness = 1.0d) { double doubleStiffness = 2.0d * stiffness; - + // 第一层弹簧:从中间位置到目标位置 // 直接修改intermediatePosition和intermediateVelocity intermediatePosition = SpringSimple(deltaTime, intermediatePosition, intermediateVelocity, targetValue, out intermediateVelocity, doubleStiffness); @@ -344,8 +345,8 @@ public static double SpringSimpleDoubleSmoothing( return SpringSimple(deltaTime, currentValue, currentVelocity, intermediatePosition, out newVelocity, doubleStiffness); } -#region float4版本的Spring函数 - + #region float4版本的Spring函数 + /// /// 简易弹簧阻尼器,只有临界阻尼,没有过阻尼和欠阻尼 /// @@ -357,12 +358,14 @@ public static double SpringSimpleDoubleSmoothing( /// 阻尼比 /// 弹簧刚度(实际上直接作为自然频率使用) /// 新的位移值 - public static float4 SpringSimple( + [BurstCompile] + public static void SpringSimple( float deltaTime, - float4 currentValue, - float4 currentVelocity, - float4 targetValue, - out float4 newVelocity, + ref float4 currentValue, + ref float4 currentVelocity, + ref float4 targetValue, + ref float4 newVelocity, + ref float4 result, float stiffness = 1.0f) { // SpringSimple是专门为临界阻尼设计的简化版本 @@ -375,11 +378,8 @@ public static float4 SpringSimple( float4 exponentialDecay = (float4)FastNegExp(naturalFreq * deltaTime); // 指数衰减因子 // 临界阻尼的更新公式 - float4 newPosition = exponentialDecay * (displacementFromTarget + velocityWithDamping * deltaTime) + targetValue; // 新位置 - float4 newVel = exponentialDecay * (currentVelocity - velocityWithDamping * naturalFreq * deltaTime); // 新速度 - - newVelocity = newVel; - return newPosition; + result = exponentialDecay * (displacementFromTarget + velocityWithDamping * deltaTime) + targetValue; // 新位置 + newVelocity = exponentialDecay * (currentVelocity - velocityWithDamping * naturalFreq * deltaTime); // 新速度 } /// @@ -395,13 +395,15 @@ public static float4 SpringSimple( /// 弹簧刚度(实际上直接作为自然频率使用)5 = 1秒 10 = 0.5秒 16.5 = 0.2秒 /// 计算精度容差 /// 新的位移值 - public static float4 SpringElastic( + [BurstCompile] + public static void SpringElastic( float deltaTime, - float4 currentValue, - float4 currentVelocity, - float4 targetValue, - out float4 newVelocity, - float4 targetVelocity = default, + ref float4 currentValue, + ref float4 currentVelocity, + ref float4 targetValue, + ref float4 newVelocity, + ref float4 targetVelocity, + ref float4 result, float dampingRatio = 0.5f, float stiffness = 1.0f, float precision = 1e-5f) @@ -459,7 +461,7 @@ public static float4 SpringElastic( } newVelocity = currentVel; - return currentPosition; + result = currentPosition; } /// @@ -474,43 +476,45 @@ public static float4 SpringElastic( /// 平滑速度 /// 弹簧刚度(实际上直接作为自然频率使用) /// 新的位移值 - public static float4 SpringSimpleVelocitySmoothing( + [BurstCompile] + public static void SpringSimpleVelocitySmoothing( float deltaTime, - float4 currentValue, - float4 currentVelocity, - float4 targetValue, - out float4 newVelocity, + ref float4 currentValue, + ref float4 currentVelocity, + ref float4 targetValue, + ref float4 newVelocity, ref float4 intermediatePosition, + ref float4 result, float smothingVelocity = 2f, float stiffness = 1.0f) { // 按照原始版本的设计,直接使用stiffness作为自然频率 float naturalFreq = stiffness; - + // 计算目标与中间位置的差值 float4 targetIntermediateDiff = targetValue - intermediatePosition; float4 absTargetIntermediateDiff = math.abs(targetIntermediateDiff); - + // 计算速度方向 float4 velocityDirection = math.sign(targetIntermediateDiff) * smothingVelocity; // 计算预期时间 float anticipatedTime = 1f / naturalFreq; - + // 计算未来目标位置 - float4 futureTargetPosition = math.select(targetValue, - intermediatePosition + velocityDirection * anticipatedTime, + float4 futureTargetPosition = math.select(targetValue, + intermediatePosition + velocityDirection * anticipatedTime, absTargetIntermediateDiff > anticipatedTime * smothingVelocity); // 直接调用SpringSimple函数 - float4 result = SpringSimple(deltaTime, currentValue, currentVelocity, futureTargetPosition, out newVelocity, stiffness); + SpringSimple(deltaTime, ref currentValue, ref currentVelocity, ref futureTargetPosition, ref newVelocity, ref result, stiffness); // 更新中间位置 - intermediatePosition = math.select(targetValue, - intermediatePosition + velocityDirection * deltaTime, + intermediatePosition = math.select(targetValue, + intermediatePosition + velocityDirection * deltaTime, absTargetIntermediateDiff > deltaTime * smothingVelocity); - return result; + // result已经在SpringSimple调用中设置 } /// @@ -525,41 +529,43 @@ public static float4 SpringSimpleVelocitySmoothing( /// 目标到达时间(秒) /// 弹簧刚度(实际上直接作为自然频率使用) /// 新的位移值 - public static float4 SpringSimpleDurationLimit( + [BurstCompile] + public static void SpringSimpleDurationLimit( float deltaTime, - float4 currentValue, - float4 currentVelocity, - float4 targetValue, - out float4 newVelocity, + ref float4 currentValue, + ref float4 currentVelocity, + ref float4 targetValue, + ref float4 newVelocity, ref float4 intermediatePosition, + ref float4 result, float durationSeconds = 0.2f, float stiffness = 1.0f) { // 直接使用stiffness作为自然频率 float naturalFreq = stiffness; float tGoal = durationSeconds; - + // 计算最小时间 float minTime = math.max(tGoal, deltaTime); - + // 基于中间位置计算目标速度 float4 targetVel = (targetValue - intermediatePosition) / minTime; // 计算预期时间 float anticipatedTime = 1f / naturalFreq; - + // 计算未来目标位置 float4 futureTargetPosition = math.select(targetValue, - intermediatePosition + targetVel * anticipatedTime, + intermediatePosition + targetVel * anticipatedTime, anticipatedTime < tGoal); // 直接调用SpringSimple函数 - float4 result = SpringSimple(deltaTime, currentValue, currentVelocity, futureTargetPosition, out newVelocity, stiffness); + SpringSimple(deltaTime, ref currentValue, ref currentVelocity, ref futureTargetPosition, ref newVelocity, ref result, stiffness); // 更新中间位置 intermediatePosition += targetVel * deltaTime; - return result; + // result已经在SpringSimple调用中设置 } /// @@ -574,25 +580,27 @@ public static float4 SpringSimpleDurationLimit( /// 中间速度(用于维护状态) /// 弹簧刚度(实际上直接作为自然频率使用) /// 新的位移值 - public static float4 SpringSimpleDoubleSmoothing( + [BurstCompile] + public static void SpringSimpleDoubleSmoothing( float deltaTime, - float4 currentValue, - float4 currentVelocity, - float4 targetValue, - out float4 newVelocity, + ref float4 currentValue, + ref float4 currentVelocity, + ref float4 targetValue, + ref float4 newVelocity, ref float4 intermediatePosition, ref float4 intermediateVelocity, + ref float4 result, float stiffness = 1.0f) { float doubleStiffness = 2.0f * stiffness; // 第一层弹簧:从中间位置到目标位置 // 直接修改intermediatePosition和intermediateVelocity - intermediatePosition = SpringSimple(deltaTime, intermediatePosition, intermediateVelocity, targetValue, out intermediateVelocity, doubleStiffness); + SpringSimple(deltaTime, ref intermediatePosition, ref intermediateVelocity, ref targetValue, ref intermediateVelocity, ref intermediatePosition, doubleStiffness); // 第二层弹簧:从当前位置到中间位置 // 使用修改后的intermediatePosition作为目标 - return SpringSimple(deltaTime, currentValue, currentVelocity, intermediatePosition, out newVelocity, doubleStiffness); + SpringSimple(deltaTime, ref currentValue, ref currentVelocity, ref intermediatePosition, ref newVelocity, ref result, doubleStiffness); } #endregion @@ -640,7 +648,7 @@ private static double HalflifeToNaturalFreq(double halflife) /// 自然频率(rad/s) /// 半衰期(秒) private static double NaturalFreqToHalflife(double naturalFreq) - { + { return 0.69314718056d / naturalFreq; // τ₁/₂ = ln(2) / ω₀ } private static double FastNegExp(double x) @@ -713,6 +721,6 @@ public static double GetSpringValueAndVelocityFromNanos( // TODO: 在弹簧实现中正确支持纳秒 long playTimeMillis = playTimeNanos / 1_000_000L; return SpringPrecise(playTimeMillis, initialValue, initialVelocity, targetValue, out _, targetVelocity, dampingRatio, stiffness, precision); + } } } -} From b6e44f6d1cfd264f77be5f2f2374b80901966c78 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Tue, 23 Sep 2025 09:12:30 +0800 Subject: [PATCH 24/55] =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=B8=8D=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E7=9A=84=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets/LitMotion/Runtime/SpringUtility.cs | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs index 8dc8b67d..ca9ad081 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs @@ -695,32 +695,5 @@ private static double FastSquare(double x) { return x * x; } - - /// - /// 根据纳秒时间计算弹簧动画值 - /// - /// 播放时间(纳秒) - /// 初始值 - /// 目标值 - /// 初始速度 - /// 阻尼比 - /// 弹簧刚度(实际上直接作为自然频率使用) - /// 目标速度(到达目标位置时的期望速度) - /// 计算精度容差 - /// 当前动画值 - public static double GetSpringValueAndVelocityFromNanos( - long playTimeNanos, - double initialValue, - double targetValue, - double initialVelocity, - double dampingRatio = 0.5f, - double stiffness = 1.0d, - double targetVelocity = 0.0d, - double precision = 1e-5f) - { - // TODO: 在弹簧实现中正确支持纳秒 - long playTimeMillis = playTimeNanos / 1_000_000L; - return SpringPrecise(playTimeMillis, initialValue, initialVelocity, targetValue, out _, targetVelocity, dampingRatio, stiffness, precision); - } } } From 6ad07bafb9553892aa9e0aa99d172fef0b911c24 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Tue, 23 Sep 2025 09:13:30 +0800 Subject: [PATCH 25/55] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=88=9A=E5=BA=A6?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets/LitMotion/Runtime/SpringUtility.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs index ca9ad081..6586e7c5 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs @@ -25,7 +25,7 @@ public static double SpringSimple( double currentVelocity, double targetValue, out double newVelocity, - double stiffness = 1.0d) + double stiffness = 10.0d) { // SpringSimple是专门为临界阻尼设计的简化版本 // 直接使用stiffness作为自然频率,阻尼系数的一半等于自然频率 @@ -65,7 +65,7 @@ public static double SpringElastic( out double newVelocity, double targetVelocity = 0.0d, double dampingRatio = 0.5f, - double stiffness = 1.0d, + double stiffness = 10.0d, double precision = 1e-5f) { // 使用有意义的变量名,提高代码可读性 @@ -144,7 +144,7 @@ public static double SpringPrecise( out double newVelocity, double targetVelocity = 0.0d, double dampingRatio = 0.5d, - double stiffness = 1.0d, + double stiffness = 10.0d, double precision = 1e-5d) { // 将stiffness参数重命名为naturalFreq进行内部计算 @@ -232,7 +232,7 @@ public static double SpringSimpleVelocitySmoothing( out double newVelocity, ref double intermediatePosition, double smothingVelocity = 2d, - double stiffness = 1.0d) + double stiffness = 10.0d) { // 按照原始版本的设计,直接使用stiffness作为自然频率 double naturalFreq = stiffness; @@ -283,7 +283,7 @@ public static double SpringSimpleDurationLimit( out double newVelocity, ref double intermediatePosition, double durationSeconds = 0.2d, - double stiffness = 1.0d) + double stiffness = 10.0d) { // 直接使用stiffness作为自然频率 double naturalFreq = stiffness; @@ -332,7 +332,7 @@ public static double SpringSimpleDoubleSmoothing( out double newVelocity, ref double intermediatePosition, ref double intermediateVelocity, - double stiffness = 1.0d) + double stiffness = 10.0d) { double doubleStiffness = 2.0d * stiffness; From bc7f335e0fcf037bff4457ad8f9fb1df2801ae58 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Tue, 23 Sep 2025 10:40:25 +0800 Subject: [PATCH 26/55] =?UTF-8?q?=E6=94=B9=E4=BA=86=E4=B8=8B=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E9=99=90=E5=88=B6=E9=98=BB=E5=B0=BC=E5=99=A8=EF=BC=8C?= =?UTF-8?q?=E7=AE=80=E5=8C=96=E5=8F=82=E6=95=B0=E8=BE=93=E5=85=A5=EF=BC=8C?= =?UTF-8?q?=E6=94=B6=E6=95=9B=E6=97=B6=E9=97=B4=E6=9B=B4=E6=8E=A5=E8=BF=91?= =?UTF-8?q?=E7=BB=99=E5=87=BA=E7=9A=84=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets/LitMotion/Runtime/SpringUtility.cs | 81 ++++++------------- 1 file changed, 23 insertions(+), 58 deletions(-) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs index 6586e7c5..b6ce4949 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs @@ -262,18 +262,15 @@ public static double SpringSimpleVelocitySmoothing( } /// - /// 时间限制弹簧阻尼器,支持指定到达时间 + /// 时间限制弹簧阻尼器,根据指定到达时间自动计算合适的刚度 /// - /// 经过时间(毫秒) + /// 时间步长(秒) /// 当前值 /// 当前速度 /// 目标值 /// 输出新的速度 /// 中间位置(用于维护状态) - /// 目标到达时间(毫秒) - /// 阻尼比 - /// 弹簧刚度(实际上直接作为自然频率使用) - /// 预期系数,用于预测未来目标位置 + /// 目标到达时间(秒) /// 新的位移值 public static double SpringSimpleDurationLimit( double deltaTime, @@ -281,32 +278,17 @@ public static double SpringSimpleDurationLimit( double currentVelocity, double targetValue, out double newVelocity, - ref double intermediatePosition, - double durationSeconds = 0.2d, - double stiffness = 10.0d) + double durationSeconds = 0.2d) { - // 直接使用stiffness作为自然频率 - double naturalFreq = stiffness; - double tGoal = durationSeconds; - - // 计算最小时间 - double minTime = tGoal > deltaTime ? tGoal : deltaTime; - - // 基于中间位置计算目标速度 - double targetVel = (targetValue - intermediatePosition) / minTime; - - // 计算预期时间 - double anticipatedTime = 1d / naturalFreq; - - // 计算未来目标位置 - double futureTargetPosition = anticipatedTime < tGoal ? - intermediatePosition + targetVel * anticipatedTime : targetValue; - - // 直接调用SpringSimple函数 - double result = SpringSimple(deltaTime, currentValue, currentVelocity, futureTargetPosition, out newVelocity, stiffness); + // 根据目标时间计算合适的自然频率 + // 对于临界阻尼系统,收敛时间约为 3-4 倍的时间常数 + // 时间常数 = 1 / naturalFreq,所以 naturalFreq = 4.6 / durationSeconds + // 这样可以在durationSeconds时间内达到约99%收敛 + double naturalFreq = 4.6d / durationSeconds; - // 更新中间位置 - intermediatePosition += targetVel * deltaTime; + // 直接使用目标值,不需要复杂的中间目标逻辑 + // 让弹簧直接收敛到最终目标 + double result = SpringSimple(deltaTime, currentValue, currentVelocity, targetValue, out newVelocity, naturalFreq); return result; } @@ -518,7 +500,7 @@ public static void SpringSimpleVelocitySmoothing( } /// - /// 时间限制弹簧阻尼器,float4版本,支持指定到达时间 + /// 时间限制弹簧阻尼器,float4版本,根据指定到达时间自动计算合适的刚度 /// /// 时间步长(秒) /// 当前值 @@ -527,7 +509,6 @@ public static void SpringSimpleVelocitySmoothing( /// 输出新的速度 /// 中间位置(用于维护状态) /// 目标到达时间(秒) - /// 弹簧刚度(实际上直接作为自然频率使用) /// 新的位移值 [BurstCompile] public static void SpringSimpleDurationLimit( @@ -536,34 +517,18 @@ public static void SpringSimpleDurationLimit( ref float4 currentVelocity, ref float4 targetValue, ref float4 newVelocity, - ref float4 intermediatePosition, ref float4 result, - float durationSeconds = 0.2f, - float stiffness = 1.0f) + float durationSeconds = 0.2f) { - // 直接使用stiffness作为自然频率 - float naturalFreq = stiffness; - float tGoal = durationSeconds; - - // 计算最小时间 - float minTime = math.max(tGoal, deltaTime); - - // 基于中间位置计算目标速度 - float4 targetVel = (targetValue - intermediatePosition) / minTime; - - // 计算预期时间 - float anticipatedTime = 1f / naturalFreq; - - // 计算未来目标位置 - float4 futureTargetPosition = math.select(targetValue, - intermediatePosition + targetVel * anticipatedTime, - anticipatedTime < tGoal); - - // 直接调用SpringSimple函数 - SpringSimple(deltaTime, ref currentValue, ref currentVelocity, ref futureTargetPosition, ref newVelocity, ref result, stiffness); - - // 更新中间位置 - intermediatePosition += targetVel * deltaTime; + // 根据目标时间计算合适的自然频率 + // 对于临界阻尼系统,收敛时间约为 3-4 倍的时间常数 + // 时间常数 = 1 / naturalFreq,所以 naturalFreq = 4.6 / durationSeconds + // 这样可以在durationSeconds时间内达到约99%收敛 + float naturalFreq = 4.6f / durationSeconds; + + // 直接使用目标值,不需要复杂的中间目标逻辑 + // 让弹簧直接收敛到最终目标 + SpringSimple(deltaTime, ref currentValue, ref currentVelocity, ref targetValue, ref newVelocity, ref result, naturalFreq); // result已经在SpringSimple调用中设置 } From bb2d67853013b9e108b38f2f2384bf1a7306f3df Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Tue, 23 Sep 2025 23:18:50 +0800 Subject: [PATCH 27/55] =?UTF-8?q?=E5=8F=82=E6=95=B0=E9=83=BD=E6=94=B9?= =?UTF-8?q?=E6=88=90=E5=BC=95=E7=94=A8=E4=BC=A0=E9=80=92=EF=BC=8C=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E7=9B=B4=E6=8E=A5=E4=BD=BF=E7=94=A8option=E7=9A=84?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 虽然测试结果比double慢1倍,但是也够用了 float比double慢1倍是Unity的bug! --- .../Runtime/Adapters/SpringMotionAdapters.cs | 95 +--- .../LitMotion/Runtime/LMotion.Spring.cs | 4 + .../Assets/LitMotion/Runtime/MotionHandle.cs | 14 + .../Runtime/Options/SpringOptions.cs | 29 +- .../Assets/LitMotion/Runtime/SpringUtility.cs | 437 ++++++++---------- 5 files changed, 257 insertions(+), 322 deletions(-) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs index 1d220a11..ba8f9fca 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs @@ -15,24 +15,17 @@ namespace LitMotion.Adapters { public float Evaluate(ref float startValue, ref float endValue, ref SpringOptions options, in MotionEvaluationContext context) { - // 使用MotionEvaluationContext中的DeltaTime - double deltaTime = context.DeltaTime; - // 调用SpringElastic函数计算新的位置和速度 - double newVelocity; - double newPosition = SpringUtility.SpringElastic( - deltaTime, - startValue, - options.CurrentVelocity.x, + SpringUtility.SpringElastic( + (float)context.DeltaTime, + ref options.CurrentValue.x, + ref options.CurrentVelocity.x, endValue, - out newVelocity, options.TargetVelocity.x, options.DampingRatio, options.Stiffness ); - options.CurrentVelocity.x = (float)newVelocity; - startValue = (float)newPosition; - return (float)newPosition; + return options.CurrentValue.x; } } @@ -47,32 +40,18 @@ public Vector2 Evaluate(ref Vector2 startValue, ref Vector2 endValue, ref Spring float deltaTime = (float)context.DeltaTime; // 转换为float4进行计算 - float4 f4StartValue = new float4(startValue, 0, 0); float4 f4EndValue = new float4(endValue, 0, 0); - float4 f4CurrentVelocity = new float4(options.CurrentVelocity.x, options.CurrentVelocity.y, 0, 0); - float4 f4TargetVelocity = new float4(options.TargetVelocity.x, options.TargetVelocity.y, 0, 0); - float4 f4NewVelocity = default; - float4 f4NewPosition = default; // 新位置 // 使用float4版本的SpringElastic SpringUtility.SpringElastic( deltaTime, - ref f4StartValue, - ref f4CurrentVelocity, - ref f4EndValue, - ref f4NewVelocity, - ref f4TargetVelocity, - ref f4NewPosition, + ref options.CurrentValue, + ref options.CurrentVelocity, + f4EndValue, + options.TargetVelocity, options.DampingRatio, options.Stiffness ); - - // 更新速度和位置(通过ref修改,不使用new) - options.CurrentVelocity.x = f4NewVelocity.x; - options.CurrentVelocity.y = f4NewVelocity.y; - startValue.x = (float)f4NewPosition.x; - startValue.y = (float)f4NewPosition.y; - - return startValue; + return options.CurrentValue.xy; } } @@ -85,36 +64,19 @@ public Vector3 Evaluate(ref Vector3 startValue, ref Vector3 endValue, ref Spring { // 使用MotionEvaluationContext中的DeltaTime float deltaTime = (float)context.DeltaTime; - float4 f4NewVelocity = default; - float4 f4NewPosition = default; // 新位置 // 转换为float4进行计算 - float4 f4StartValue = new float4(startValue, 0); float4 f4EndValue = new float4(endValue, 0); - float4 f4CurrentVelocity = new float4(options.CurrentVelocity.x, options.CurrentVelocity.y, options.CurrentVelocity.z, 0); - float4 f4TargetVelocity = new float4(options.TargetVelocity.x, options.TargetVelocity.y, options.TargetVelocity.z, 0); - // 使用float4版本的SpringElastic SpringUtility.SpringElastic( deltaTime, - ref f4StartValue, - ref f4CurrentVelocity, - ref f4EndValue, - ref f4NewVelocity, - ref f4TargetVelocity, - ref f4NewPosition, + ref options.CurrentValue, + ref options.CurrentVelocity, + f4EndValue, + options.TargetVelocity, options.DampingRatio, options.Stiffness ); - - // 更新速度和位置(通过ref修改,不使用new) - options.CurrentVelocity.x = f4NewVelocity.x; - options.CurrentVelocity.y = f4NewVelocity.y; - options.CurrentVelocity.z = f4NewVelocity.z; - startValue.x = f4NewPosition.x; - startValue.y = f4NewPosition.y; - startValue.z = f4NewPosition.z; - - return startValue; + return options.CurrentValue.xyz; } } @@ -129,36 +91,19 @@ public Vector4 Evaluate(ref Vector4 startValue, ref Vector4 endValue, ref Spring float deltaTime = (float)context.DeltaTime; // 转换为float4进行计算 - float4 f4StartValue = startValue; float4 f4EndValue = endValue; - float4 f4CurrentVelocity = options.CurrentVelocity; - float4 f4TargetVelocity = options.TargetVelocity; - float4 f4NewVelocity = default; - float4 f4NewPosition = default; // 新位置 // 使用float4版本的SpringElastic SpringUtility.SpringElastic( deltaTime, - ref f4StartValue, - ref f4CurrentVelocity, - ref f4EndValue, - ref f4NewVelocity, - ref f4TargetVelocity, - ref f4NewPosition, + ref options.CurrentValue, + ref options.CurrentVelocity, + f4EndValue, + options.TargetVelocity, options.DampingRatio, options.Stiffness ); - // 更新速度和位置(通过ref修改,不使用new) - options.CurrentVelocity.x = f4NewVelocity.x; - options.CurrentVelocity.y = f4NewVelocity.y; - options.CurrentVelocity.z = f4NewVelocity.z; - options.CurrentVelocity.w = f4NewVelocity.w; - startValue.x = (float)f4NewPosition.x; - startValue.y = (float)f4NewPosition.y; - startValue.z = (float)f4NewPosition.z; - startValue.w = (float)f4NewPosition.w; - - return startValue; + return options.CurrentValue; } } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs index 48e455f3..5f34da6e 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs @@ -20,6 +20,7 @@ public static class Spring /// Created motion builder public static MotionBuilder Create(float startValue, float endValue, float duration, SpringOptions options) { + options.CurrentValue.x = startValue; return Create(startValue, endValue, duration) .WithOptions(options); } @@ -34,6 +35,7 @@ public static MotionBuilder Crea /// Created motion builder public static MotionBuilder Create(Vector2 startValue, Vector2 endValue, float duration, SpringOptions options) { + options.CurrentValue.xy = startValue; return Create(startValue, endValue, duration) .WithOptions(options); } @@ -48,6 +50,7 @@ public static MotionBuilder /// Created motion builder public static MotionBuilder Create(Vector3 startValue, Vector3 endValue, float duration, SpringOptions options) { + options.CurrentValue.xyz = startValue; return Create(startValue, endValue, duration) .WithOptions(options); } @@ -62,6 +65,7 @@ public static MotionBuilder /// Created motion builder public static MotionBuilder Create(Vector4 startValue, Vector4 endValue, float duration, SpringOptions options) { + options.CurrentValue.xyzw = startValue; return Create(startValue, endValue, duration) .WithOptions(options); } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs index 38455b7f..04592721 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs @@ -126,6 +126,20 @@ public void SetEndValue(TValue value, bool checkIsInSequence = MotionManager.GetTypeDataRef(this, checkIsInSequence).EndValue = value; } + public ref TValue GetEndValueRef(bool checkIsInSequence = true) + where TValue : unmanaged + where TOptions : unmanaged, IMotionOptions + { + return ref MotionManager.GetTypeDataRef(this, checkIsInSequence).EndValue; + } + + public ref TOptions GetOptions(bool checkIsInSequence = true) + where TValue : unmanaged + where TOptions : unmanaged, IMotionOptions + { + return ref MotionManager.GetTypeDataRef(this, checkIsInSequence).Options; + } + public override readonly string ToString() { return $"MotionHandle`{StorageId} ({Index}:{Version})"; diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs index 0898dcb6..74597290 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs @@ -1,4 +1,5 @@ using System; +using Unity.Mathematics; using UnityEngine; namespace LitMotion @@ -9,8 +10,9 @@ namespace LitMotion [Serializable] public struct SpringOptions : IEquatable, IMotionOptions { - public Vector4 CurrentVelocity; - public Vector4 TargetVelocity; + public float4 CurrentValue; + public float4 CurrentVelocity; + public float4 TargetVelocity; public float Stiffness; public float DampingRatio; @@ -22,8 +24,9 @@ public static SpringOptions Critical { Stiffness = 10.0f, DampingRatio = 1.0f, - CurrentVelocity = new Vector4(0.0f, 0.0f, 0.0f, 0.0f), - TargetVelocity = new Vector4(1.0f, 0.0f, 0.0f, 0.0f) + CurrentVelocity = new float4(0.0f, 0.0f, 0.0f, 0.0f), + TargetVelocity = new float4(1.0f, 0.0f, 0.0f, 0.0f), + CurrentValue = new float4(0.0f, 0.0f, 0.0f, 0.0f) }; } } @@ -36,8 +39,9 @@ public static SpringOptions Overdamped { Stiffness = 10.0f, DampingRatio = 1.2f, - CurrentVelocity = new Vector4(0.0f, 0.0f, 0.0f, 0.0f), - TargetVelocity = new Vector4(1.0f, 0.0f, 0.0f, 0.0f) + CurrentVelocity = new float4(0.0f, 0.0f, 0.0f, 0.0f), + TargetVelocity = new float4(1.0f, 0.0f, 0.0f, 0.0f), + CurrentValue = new float4(0.0f, 0.0f, 0.0f, 0.0f) }; } } @@ -50,8 +54,9 @@ public static SpringOptions Underdamped { Stiffness = 10.0f, DampingRatio = 0.6f, - CurrentVelocity = new Vector4(0.0f, 0.0f, 0.0f, 0.0f), - TargetVelocity = new Vector4(1.0f, 0.0f, 0.0f, 0.0f) + CurrentVelocity = new float4(0.0f, 0.0f, 0.0f, 0.0f), + TargetVelocity = new float4(1.0f, 0.0f, 0.0f, 0.0f), + CurrentValue = new float4(0.0f, 0.0f, 0.0f, 0.0f) }; } } @@ -60,9 +65,9 @@ public readonly bool Equals(SpringOptions other) { return Stiffness == other.Stiffness && DampingRatio == other.DampingRatio && - TargetVelocity == other.TargetVelocity && - CurrentVelocity == other.CurrentVelocity && - TargetVelocity == other.TargetVelocity; + TargetVelocity.Equals(other.TargetVelocity) && + CurrentVelocity.Equals(other.CurrentVelocity) && + CurrentValue.Equals(other.CurrentValue); } public override readonly bool Equals(object obj) @@ -73,7 +78,7 @@ public override readonly bool Equals(object obj) public override readonly int GetHashCode() { - return HashCode.Combine(Stiffness, DampingRatio, TargetVelocity, CurrentVelocity, TargetVelocity); + return HashCode.Combine(Stiffness, DampingRatio, TargetVelocity, CurrentVelocity, CurrentValue); } } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs index b6ce4949..2b9ea657 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs @@ -19,29 +19,25 @@ public static class SpringUtility /// 阻尼比 /// 弹簧刚度(实际上直接作为自然频率使用) /// 新的位移值 - public static double SpringSimple( - double deltaTime, - double currentValue, - double currentVelocity, - double targetValue, - out double newVelocity, - double stiffness = 10.0d) + public static void SpringSimple( + in float deltaTime, + ref float currentValue, + ref float currentVelocity, + in float targetValue, + in float stiffness = 10.0f) { // SpringSimple是专门为临界阻尼设计的简化版本 // 直接使用stiffness作为自然频率,阻尼系数的一半等于自然频率 - double naturalFreq = stiffness; + float naturalFreq = stiffness; // 临界阻尼的计算逻辑 - double displacementFromTarget = currentValue - targetValue; // 当前位置与目标的位移差 - double velocityWithDamping = currentVelocity + displacementFromTarget * naturalFreq; // 考虑阻尼的初始速度 - double exponentialDecay = FastNegExp(naturalFreq * deltaTime); // 指数衰减因子 + float displacementFromTarget = currentValue - targetValue; // 当前位置与目标的位移差 + float velocityWithDamping = currentVelocity + displacementFromTarget * naturalFreq; // 考虑阻尼的初始速度 + float exponentialDecay = FastNegExp(naturalFreq * deltaTime); // 指数衰减因子 // 临界阻尼的更新公式 - double newPosition = exponentialDecay * (displacementFromTarget + velocityWithDamping * deltaTime) + targetValue; // 新位置 - double newVel = exponentialDecay * (currentVelocity - velocityWithDamping * naturalFreq * deltaTime); // 新速度 - - newVelocity = newVel; - return newPosition; + currentValue = exponentialDecay * (displacementFromTarget + velocityWithDamping * deltaTime) + targetValue; // 新位置 + currentVelocity = exponentialDecay * (currentVelocity - velocityWithDamping * naturalFreq * deltaTime); // 新速度 } /// @@ -57,71 +53,65 @@ public static double SpringSimple( /// 弹簧刚度(实际上直接作为自然频率使用)5 = 1秒 10 = 0.5秒 16.5 = 0.2秒 /// 计算精度容差 /// 新的位移值 - public static double SpringElastic( - double deltaTime, - double currentValue, - double currentVelocity, - double targetValue, - out double newVelocity, - double targetVelocity = 0.0d, - double dampingRatio = 0.5f, - double stiffness = 10.0d, - double precision = 1e-5f) + public static void SpringElastic( + in float deltaTime, + ref float currentValue, + ref float currentVelocity, + in float targetValue, + in float targetVelocity = 0.0f, + in float dampingRatio = 0.5f, + in float stiffness = 10.0f, + in float precision = 1e-5f) { // 使用有意义的变量名,提高代码可读性 - double currentPosition = currentValue; - double currentVel = currentVelocity; - double targetPosition = targetValue; - double targetVel = targetVelocity; + float targetPosition = targetValue; + float targetVel = targetVelocity; // 将stiffness参数重命名为naturalFreq进行内部计算 - double naturalFreq = stiffness; - double stiffnessValue = naturalFreq * naturalFreq; // 刚度值 = naturalFreq² - double dampingHalf = dampingRatio * naturalFreq; - double dampingCoeff = 2.0d * dampingHalf; // 阻尼系数 = 2 * 阻尼比 * naturalFreq - double adjustedTargetPosition = targetPosition + (dampingCoeff * targetVel) / (stiffnessValue + precision); + float naturalFreq = stiffness; + float stiffnessValue = naturalFreq * naturalFreq; // 刚度值 = naturalFreq² + float dampingHalf = dampingRatio * naturalFreq; + float dampingCoeff = 2.0f * dampingHalf; // 阻尼系数 = 2 * 阻尼比 * naturalFreq + float adjustedTargetPosition = targetPosition + (dampingCoeff * targetVel) / (stiffnessValue + precision); - if (Math.Abs(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0d) < precision) // Critically Damped + if (Math.Abs(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f) < precision) // Critically Damped { - double initialDisplacement = currentPosition - adjustedTargetPosition; - double initialVelocityWithDamping = currentVel + initialDisplacement * dampingHalf; + float initialDisplacement = currentValue - adjustedTargetPosition; + float initialVelocityWithDamping = currentVelocity + initialDisplacement * dampingHalf; - double exponentialDecay = FastNegExp(dampingHalf * deltaTime); + float exponentialDecay = FastNegExp(dampingHalf * deltaTime); - currentPosition = initialDisplacement * exponentialDecay + deltaTime * initialVelocityWithDamping * exponentialDecay + adjustedTargetPosition; - currentVel = -dampingHalf * initialDisplacement * exponentialDecay - dampingHalf * deltaTime * initialVelocityWithDamping * exponentialDecay + initialVelocityWithDamping * exponentialDecay; + currentValue = initialDisplacement * exponentialDecay + deltaTime * initialVelocityWithDamping * exponentialDecay + adjustedTargetPosition; + currentVelocity = -dampingHalf * initialDisplacement * exponentialDecay - dampingHalf * deltaTime * initialVelocityWithDamping * exponentialDecay + initialVelocityWithDamping * exponentialDecay; } - else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0d > 0.0) // Under Damped + else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f > 0.0f) // Under Damped { - double dampedFrequency = Math.Sqrt(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0d); - double displacementFromTarget = currentPosition - adjustedTargetPosition; - double amplitude = Math.Sqrt(FastSquare(currentVel + dampingHalf * displacementFromTarget) / (dampedFrequency * dampedFrequency + precision) + FastSquare(displacementFromTarget)); - double phase = FastAtan((currentVel + displacementFromTarget * dampingHalf) / (-displacementFromTarget * dampedFrequency + precision)); + float dampedFrequency = math.sqrt(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f); + float displacementFromTarget = currentValue - adjustedTargetPosition; + float amplitude = math.sqrt(FastSquare(currentVelocity + dampingHalf * displacementFromTarget) / (dampedFrequency * dampedFrequency + precision) + FastSquare(displacementFromTarget)); + float phase = FastAtan((currentVelocity + displacementFromTarget * dampingHalf) / (-displacementFromTarget * dampedFrequency + precision)); - amplitude = displacementFromTarget > 0.0d ? amplitude : -amplitude; + amplitude = displacementFromTarget > 0.0f ? amplitude : -amplitude; - double exponentialDecay = FastNegExp(dampingHalf * deltaTime); + float exponentialDecay = FastNegExp(dampingHalf * deltaTime); - currentPosition = amplitude * exponentialDecay * Math.Cos(dampedFrequency * deltaTime + phase) + adjustedTargetPosition; - currentVel = -dampingHalf * amplitude * exponentialDecay * Math.Cos(dampedFrequency * deltaTime + phase) - dampedFrequency * amplitude * exponentialDecay * Math.Sin(dampedFrequency * deltaTime + phase); + currentValue = amplitude * exponentialDecay * math.cos(dampedFrequency * deltaTime + phase) + adjustedTargetPosition; + currentVelocity = -dampingHalf * amplitude * exponentialDecay * math.cos(dampedFrequency * deltaTime + phase) - dampedFrequency * amplitude * exponentialDecay * math.sin(dampedFrequency * deltaTime + phase); } - else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0d < 0.0) // Over Damped + else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f < 0.0f) // Over Damped { - double fastDecayRate = (dampingCoeff + Math.Sqrt(dampingCoeff * dampingCoeff - 4d * stiffnessValue)) / 2.0d; - double slowDecayRate = (dampingCoeff - Math.Sqrt(dampingCoeff * dampingCoeff - 4d * stiffnessValue)) / 2.0d; + float fastDecayRate = (dampingCoeff + math.sqrt(dampingCoeff * dampingCoeff - 4f * stiffnessValue)) / 2.0f; + float slowDecayRate = (dampingCoeff - math.sqrt(dampingCoeff * dampingCoeff - 4f * stiffnessValue)) / 2.0f; // 计算过阻尼系数:fastDecayCoeff对应fastDecayRate,slowDecayCoeff对应slowDecayRate - double fastDecayCoeff = (adjustedTargetPosition * fastDecayRate - currentPosition * fastDecayRate - currentVel) / (slowDecayRate - fastDecayRate); - double slowDecayCoeff = currentPosition - fastDecayCoeff - adjustedTargetPosition; + float fastDecayCoeff = (adjustedTargetPosition * fastDecayRate - currentValue * fastDecayRate - currentVelocity) / (slowDecayRate - fastDecayRate); + float slowDecayCoeff = currentValue - fastDecayCoeff - adjustedTargetPosition; - double fastExponentialDecay = FastNegExp(fastDecayRate * deltaTime); - double slowExponentialDecay = FastNegExp(slowDecayRate * deltaTime); + float fastExponentialDecay = FastNegExp(fastDecayRate * deltaTime); + float slowExponentialDecay = FastNegExp(slowDecayRate * deltaTime); // 过阻尼位置更新:slowDecayCoeff用fastExponentialDecay,fastDecayCoeff用slowExponentialDecay - currentPosition = slowDecayCoeff * fastExponentialDecay + fastDecayCoeff * slowExponentialDecay + adjustedTargetPosition; - currentVel = -fastDecayRate * slowDecayCoeff * fastExponentialDecay - slowDecayRate * fastDecayCoeff * slowExponentialDecay; + currentValue = slowDecayCoeff * fastExponentialDecay + fastDecayCoeff * slowExponentialDecay + adjustedTargetPosition; + currentVelocity = -fastDecayRate * slowDecayCoeff * fastExponentialDecay - slowDecayRate * fastDecayCoeff * slowExponentialDecay; } - - newVelocity = (double)currentVel; - return (double)currentPosition; } /// /// 精确弹簧阻尼器,有过阻尼和欠阻尼和临界阻尼,采用精确算法 @@ -136,80 +126,78 @@ public static double SpringElastic( /// 目标速度(到达目标位置时的期望速度) /// 计算精度容差 /// 新的位移值 - public static double SpringPrecise( - double deltaTime, - double currentValue, - double currentVelocity, - double targetValue, - out double newVelocity, - double targetVelocity = 0.0d, - double dampingRatio = 0.5d, - double stiffness = 10.0d, - double precision = 1e-5d) + public static void SpringPrecise( + in float deltaTime, + ref float currentValue, + ref float currentVelocity, + in float targetValue, + in float targetVelocity = 0.0f, + in float dampingRatio = 0.5f, + in float stiffness = 10.0f, + in float precision = 1e-5f) { // 将stiffness参数重命名为naturalFreq进行内部计算 - double naturalFreq = stiffness; + float naturalFreq = stiffness; // 根据targetVelocity调整目标位置(类似SpringElastic的逻辑) - double adjustedTargetPosition = targetValue; - if (Math.Abs(targetVelocity) > precision) + float adjustedTargetPosition = targetValue; + if (math.abs(targetVelocity) > precision) { // 计算调整后的目标位置,使系统在到达目标时具有指定速度 // 使用与SpringElastic相同的逻辑:c = g + (d * q) / (s + eps) // 其中 d = 2 * dampingRatio * naturalFreq, s = naturalFreq^2 - double dampingCoeff = 2.0d * dampingRatio * naturalFreq; - double stiffnessValue = naturalFreq * naturalFreq; + float dampingCoeff = 2.0f * dampingRatio * naturalFreq; + float stiffnessValue = naturalFreq * naturalFreq; adjustedTargetPosition = targetValue + (dampingCoeff * targetVelocity) / (stiffnessValue + precision); } - double adjustedDisplacement = currentValue - adjustedTargetPosition; - double dampingRatioSquared = dampingRatio * dampingRatio; - double r = -dampingRatio * naturalFreq; + float adjustedDisplacement = currentValue - adjustedTargetPosition; + float dampingRatioSquared = dampingRatio * dampingRatio; + float r = -dampingRatio * naturalFreq; - double displacement; - double calculatedVelocity; + float displacement; + float calculatedVelocity; if (dampingRatio > 1) { // 过阻尼 - double s = naturalFreq * Math.Sqrt(dampingRatioSquared - 1); - double gammaPlus = r + s; - double gammaMinus = r - s; + float s = naturalFreq * math.sqrt(dampingRatioSquared - 1); + float gammaPlus = r + s; + float gammaMinus = r - s; // 过阻尼计算 - double coeffB = (gammaMinus * adjustedDisplacement - currentVelocity) / (gammaMinus - gammaPlus); - double coeffA = adjustedDisplacement - coeffB; - displacement = coeffA * Math.Exp(gammaMinus * deltaTime) + coeffB * Math.Exp(gammaPlus * deltaTime); - calculatedVelocity = coeffA * gammaMinus * Math.Exp(gammaMinus * deltaTime) + - coeffB * gammaPlus * Math.Exp(gammaPlus * deltaTime); + float coeffB = (gammaMinus * adjustedDisplacement - currentVelocity) / (gammaMinus - gammaPlus); + float coeffA = adjustedDisplacement - coeffB; + displacement = coeffA * FastExp(gammaMinus * deltaTime) + coeffB * FastExp(gammaPlus * deltaTime); + calculatedVelocity = coeffA * gammaMinus * FastExp(gammaMinus * deltaTime) + + coeffB * gammaPlus * FastExp(gammaPlus * deltaTime); } - else if (Math.Abs(dampingRatio - 1.0d) < precision) + else if (math.abs(dampingRatio - 1.0f) < precision) { // 临界阻尼 - double coeffA = adjustedDisplacement; - double coeffB = currentVelocity + naturalFreq * adjustedDisplacement; - double nFdT = -naturalFreq * deltaTime; - displacement = (coeffA + coeffB * deltaTime) * Math.Exp(nFdT); - calculatedVelocity = ((coeffA + coeffB * deltaTime) * Math.Exp(nFdT) * (-naturalFreq)) + - coeffB * Math.Exp(nFdT); + float coeffA = adjustedDisplacement; + float coeffB = currentVelocity + naturalFreq * adjustedDisplacement; + float nFdT = -naturalFreq * deltaTime; + displacement = (coeffA + coeffB * deltaTime) * FastExp(nFdT); + calculatedVelocity = ((coeffA + coeffB * deltaTime) * FastExp(nFdT) * (-naturalFreq)) + + coeffB * FastExp(nFdT); } else { // 欠阻尼 - double dampedFreq = naturalFreq * Math.Sqrt(1 - dampingRatioSquared); - double cosCoeff = adjustedDisplacement; - double sinCoeff = (1.0 / dampedFreq) * ((-r * adjustedDisplacement) + currentVelocity); - double dFdT = dampedFreq * deltaTime; - displacement = Math.Exp(r * deltaTime) * (cosCoeff * Math.Cos(dFdT) + sinCoeff * Math.Sin(dFdT)); + float dampedFreq = naturalFreq * math.sqrt(1 - dampingRatioSquared); + float cosCoeff = adjustedDisplacement; + float sinCoeff = (1.0f / dampedFreq) * ((-r * adjustedDisplacement) + currentVelocity); + float dFdT = dampedFreq * deltaTime; + displacement = FastExp(r * deltaTime) * (cosCoeff * math.cos(dFdT) + sinCoeff * math.sin(dFdT)); calculatedVelocity = displacement * r + - (Math.Exp(r * deltaTime) * - ((-dampedFreq * cosCoeff * Math.Sin(dFdT) + - dampedFreq * sinCoeff * Math.Cos(dFdT)))); + (FastExp(r * deltaTime) * + ((-dampedFreq * cosCoeff * math.sin(dFdT) + + dampedFreq * sinCoeff * math.cos(dFdT)))); } - double newValue = (double)(displacement + adjustedTargetPosition); - newVelocity = (double)calculatedVelocity; - return newValue; + currentValue = displacement + adjustedTargetPosition; + currentVelocity = calculatedVelocity; } /// /// 速度平滑弹簧阻尼器,支持目标速度的连续运动 @@ -224,41 +212,38 @@ public static double SpringPrecise( /// 阻尼比 /// 弹簧刚度(实际上直接作为自然频率使用) /// 新的位移值 - public static double SpringSimpleVelocitySmoothing( - double deltaTime, - double currentValue, - double currentVelocity, - double targetValue, - out double newVelocity, - ref double intermediatePosition, - double smothingVelocity = 2d, - double stiffness = 10.0d) + public static void SpringSimpleVelocitySmoothing( + in float deltaTime, + ref float currentValue, + ref float currentVelocity, + in float targetValue, + ref float intermediatePosition, + in float smothingVelocity = 2f, + in float stiffness = 10.0f) { // 按照原始版本的设计,直接使用stiffness作为自然频率 - double naturalFreq = stiffness; + float naturalFreq = stiffness; // 计算目标与中间位置的差值 - double targetIntermediateDiff = targetValue - intermediatePosition; - double absTargetIntermediateDiff = Math.Abs(targetIntermediateDiff); + float targetIntermediateDiff = targetValue - intermediatePosition; + float absTargetIntermediateDiff = math.abs(targetIntermediateDiff); // 计算速度方向 - double velocityDirection = (targetIntermediateDiff > 0.0d ? 1.0d : -1.0d) * smothingVelocity; + float velocityDirection = (targetIntermediateDiff > 0.0f ? 1.0f : -1.0f) * smothingVelocity; // 计算预期时间 - double anticipatedTime = 1d / naturalFreq; + float anticipatedTime = 1f / naturalFreq; // 计算未来目标位置 - double futureTargetPosition = absTargetIntermediateDiff > anticipatedTime * smothingVelocity ? + float futureTargetPosition = absTargetIntermediateDiff > anticipatedTime * smothingVelocity ? intermediatePosition + velocityDirection * anticipatedTime : targetValue; // 直接调用SpringSimple函数 - double result = SpringSimple(deltaTime, currentValue, currentVelocity, futureTargetPosition, out newVelocity, stiffness); + SpringSimple(deltaTime, ref currentValue, ref currentVelocity, futureTargetPosition, stiffness); // 更新中间位置 intermediatePosition = absTargetIntermediateDiff > deltaTime * smothingVelocity ? intermediatePosition + velocityDirection * deltaTime : targetValue; - - return result; } /// @@ -272,25 +257,22 @@ public static double SpringSimpleVelocitySmoothing( /// 中间位置(用于维护状态) /// 目标到达时间(秒) /// 新的位移值 - public static double SpringSimpleDurationLimit( - double deltaTime, - double currentValue, - double currentVelocity, - double targetValue, - out double newVelocity, - double durationSeconds = 0.2d) + public static void SpringSimpleDurationLimit( + in float deltaTime, + ref float currentValue, + ref float currentVelocity, + in float targetValue, + in float durationSeconds = 0.2f) { // 根据目标时间计算合适的自然频率 // 对于临界阻尼系统,收敛时间约为 3-4 倍的时间常数 // 时间常数 = 1 / naturalFreq,所以 naturalFreq = 4.6 / durationSeconds // 这样可以在durationSeconds时间内达到约99%收敛 - double naturalFreq = 4.6d / durationSeconds; + float naturalFreq = 4.6f / durationSeconds; // 直接使用目标值,不需要复杂的中间目标逻辑 // 让弹簧直接收敛到最终目标 - double result = SpringSimple(deltaTime, currentValue, currentVelocity, targetValue, out newVelocity, naturalFreq); - - return result; + SpringSimple(deltaTime, ref currentValue, ref currentVelocity, targetValue, naturalFreq); } /// @@ -306,25 +288,24 @@ public static double SpringSimpleDurationLimit( /// 阻尼比 /// 弹簧刚度(实际上直接作为自然频率使用) /// 新的位移值 - public static double SpringSimpleDoubleSmoothing( - double deltaTime, - double currentValue, - double currentVelocity, - double targetValue, - out double newVelocity, - ref double intermediatePosition, - ref double intermediateVelocity, - double stiffness = 10.0d) + public static void SpringSimpleDoubleSmoothing( + in float deltaTime, + ref float currentValue, + ref float currentVelocity, + in float targetValue, + ref float intermediatePosition, + ref float intermediateVelocity, + in float stiffness = 10.0f) { - double doubleStiffness = 2.0d * stiffness; + float floatStiffness = 2.0f * stiffness; // 第一层弹簧:从中间位置到目标位置 // 直接修改intermediatePosition和intermediateVelocity - intermediatePosition = SpringSimple(deltaTime, intermediatePosition, intermediateVelocity, targetValue, out intermediateVelocity, doubleStiffness); + SpringSimple(deltaTime, ref intermediatePosition, ref intermediateVelocity, targetValue, floatStiffness); // 第二层弹簧:从当前位置到中间位置 // 使用修改后的intermediatePosition作为目标 - return SpringSimple(deltaTime, currentValue, currentVelocity, intermediatePosition, out newVelocity, doubleStiffness); + SpringSimple(deltaTime, ref currentValue, ref currentVelocity, intermediatePosition, floatStiffness); } #region float4版本的Spring函数 @@ -342,13 +323,11 @@ public static double SpringSimpleDoubleSmoothing( /// 新的位移值 [BurstCompile] public static void SpringSimple( - float deltaTime, + in float deltaTime, ref float4 currentValue, ref float4 currentVelocity, - ref float4 targetValue, - ref float4 newVelocity, - ref float4 result, - float stiffness = 1.0f) + in float4 targetValue, + in float stiffness = 1.0f) { // SpringSimple是专门为临界阻尼设计的简化版本 // 直接使用stiffness作为自然频率,阻尼系数的一半等于自然频率 @@ -360,8 +339,8 @@ public static void SpringSimple( float4 exponentialDecay = (float4)FastNegExp(naturalFreq * deltaTime); // 指数衰减因子 // 临界阻尼的更新公式 - result = exponentialDecay * (displacementFromTarget + velocityWithDamping * deltaTime) + targetValue; // 新位置 - newVelocity = exponentialDecay * (currentVelocity - velocityWithDamping * naturalFreq * deltaTime); // 新速度 + currentValue = exponentialDecay * (displacementFromTarget + velocityWithDamping * deltaTime) + targetValue; // 新位置 + currentVelocity = exponentialDecay * (currentVelocity - velocityWithDamping * naturalFreq * deltaTime); // 新速度 } /// @@ -379,71 +358,61 @@ public static void SpringSimple( /// 新的位移值 [BurstCompile] public static void SpringElastic( - float deltaTime, + in float deltaTime, ref float4 currentValue, ref float4 currentVelocity, - ref float4 targetValue, - ref float4 newVelocity, - ref float4 targetVelocity, - ref float4 result, - float dampingRatio = 0.5f, - float stiffness = 1.0f, - float precision = 1e-5f) + in float4 targetValue, + in float4 targetVelocity, + in float dampingRatio = 0.5f, + in float stiffness = 1.0f, + in float precision = 1e-5f) { - // 使用有意义的变量名,提高代码可读性 - float4 currentPosition = currentValue; - float4 currentVel = currentVelocity; - float4 targetPosition = targetValue; - float4 targetVel = targetVelocity; // 将stiffness参数重命名为naturalFreq进行内部计算 float naturalFreq = stiffness; float stiffnessValue = naturalFreq * naturalFreq; // 刚度值 = naturalFreq² float dampingHalf = dampingRatio * naturalFreq; float dampingCoeff = 2.0f * dampingHalf; // 阻尼系数 = 2 * 阻尼比 * naturalFreq - float4 adjustedTargetPosition = targetPosition + (dampingCoeff * targetVel) / (stiffnessValue + precision); + float4 adjustedtargetValue = targetValue + (dampingCoeff * targetVelocity) / (stiffnessValue + precision); if (math.abs(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f) < precision) // Critically Damped { - float4 initialDisplacement = currentPosition - adjustedTargetPosition; - float4 initialVelocityWithDamping = currentVel + initialDisplacement * dampingHalf; + float4 initialDisplacement = currentValue - adjustedtargetValue; + float4 initialVelocityWithDamping = currentVelocity + initialDisplacement * dampingHalf; - float exponentialDecay = (float)FastNegExp((double)(dampingHalf * deltaTime)); + float exponentialDecay = (float)FastNegExp((float)(dampingHalf * deltaTime)); - currentPosition = initialDisplacement * exponentialDecay + deltaTime * initialVelocityWithDamping * exponentialDecay + adjustedTargetPosition; - currentVel = -dampingHalf * initialDisplacement * exponentialDecay - dampingHalf * deltaTime * initialVelocityWithDamping * exponentialDecay + initialVelocityWithDamping * exponentialDecay; + currentValue = initialDisplacement * exponentialDecay + deltaTime * initialVelocityWithDamping * exponentialDecay + adjustedtargetValue; + currentVelocity = -dampingHalf * initialDisplacement * exponentialDecay - dampingHalf * deltaTime * initialVelocityWithDamping * exponentialDecay + initialVelocityWithDamping * exponentialDecay; } else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f > 0.0f) // Under Damped { float dampedFrequency = math.sqrt(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f); - float4 displacementFromTarget = currentPosition - adjustedTargetPosition; - float4 amplitude = math.sqrt(Square(currentVel + dampingHalf * displacementFromTarget) / (dampedFrequency * dampedFrequency + precision) + Square(displacementFromTarget)); - float4 phase = FastAtan((currentVel + displacementFromTarget * dampingHalf) / (-displacementFromTarget * dampedFrequency + precision)); + float4 displacementFromTarget = currentValue - adjustedtargetValue; + float4 amplitude = math.sqrt(Square(currentVelocity + dampingHalf * displacementFromTarget) / (dampedFrequency * dampedFrequency + precision) + Square(displacementFromTarget)); + float4 phase = FastAtan((currentVelocity + displacementFromTarget * dampingHalf) / (-displacementFromTarget * dampedFrequency + precision)); amplitude = math.select(-amplitude, amplitude, displacementFromTarget > 0.0f); - float exponentialDecay = (float)FastNegExp((double)(dampingHalf * deltaTime)); + float exponentialDecay = (float)FastNegExp((float)(dampingHalf * deltaTime)); - currentPosition = amplitude * exponentialDecay * math.cos(dampedFrequency * deltaTime + phase) + adjustedTargetPosition; - currentVel = -dampingHalf * amplitude * exponentialDecay * math.cos(dampedFrequency * deltaTime + phase) - dampedFrequency * amplitude * exponentialDecay * math.sin(dampedFrequency * deltaTime + phase); + currentValue = amplitude * exponentialDecay * math.cos(dampedFrequency * deltaTime + phase) + adjustedtargetValue; + currentVelocity = -dampingHalf * amplitude * exponentialDecay * math.cos(dampedFrequency * deltaTime + phase) - dampedFrequency * amplitude * exponentialDecay * math.sin(dampedFrequency * deltaTime + phase); } else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f < 0.0f) // Over Damped { float fastDecayRate = (dampingCoeff + math.sqrt(dampingCoeff * dampingCoeff - 4f * stiffnessValue)) / 2.0f; float slowDecayRate = (dampingCoeff - math.sqrt(dampingCoeff * dampingCoeff - 4f * stiffnessValue)) / 2.0f; // 计算过阻尼系数:fastDecayCoeff对应fastDecayRate,slowDecayCoeff对应slowDecayRate - float4 fastDecayCoeff = (adjustedTargetPosition * fastDecayRate - currentPosition * fastDecayRate - currentVel) / (slowDecayRate - fastDecayRate); - float4 slowDecayCoeff = currentPosition - fastDecayCoeff - adjustedTargetPosition; + float4 fastDecayCoeff = (adjustedtargetValue * fastDecayRate - currentValue * fastDecayRate - currentVelocity) / (slowDecayRate - fastDecayRate); + float4 slowDecayCoeff = currentValue - fastDecayCoeff - adjustedtargetValue; - float fastExponentialDecay = (float)FastNegExp((double)(fastDecayRate * deltaTime)); - float slowExponentialDecay = (float)FastNegExp((double)(slowDecayRate * deltaTime)); + float fastExponentialDecay = (float)FastNegExp((float)(fastDecayRate * deltaTime)); + float slowExponentialDecay = (float)FastNegExp((float)(slowDecayRate * deltaTime)); // 过阻尼位置更新:slowDecayCoeff用fastExponentialDecay,fastDecayCoeff用slowExponentialDecay - currentPosition = slowDecayCoeff * fastExponentialDecay + fastDecayCoeff * slowExponentialDecay + adjustedTargetPosition; - currentVel = -fastDecayRate * slowDecayCoeff * fastExponentialDecay - slowDecayRate * fastDecayCoeff * slowExponentialDecay; + currentValue = slowDecayCoeff * fastExponentialDecay + fastDecayCoeff * slowExponentialDecay + adjustedtargetValue; + currentVelocity = -fastDecayRate * slowDecayCoeff * fastExponentialDecay - slowDecayRate * fastDecayCoeff * slowExponentialDecay; } - - newVelocity = currentVel; - result = currentPosition; } /// @@ -460,15 +429,13 @@ public static void SpringElastic( /// 新的位移值 [BurstCompile] public static void SpringSimpleVelocitySmoothing( - float deltaTime, + in float deltaTime, ref float4 currentValue, ref float4 currentVelocity, - ref float4 targetValue, - ref float4 newVelocity, + in float4 targetValue, ref float4 intermediatePosition, - ref float4 result, - float smothingVelocity = 2f, - float stiffness = 1.0f) + in float smothingVelocity = 2f, + in float stiffness = 1.0f) { // 按照原始版本的设计,直接使用stiffness作为自然频率 float naturalFreq = stiffness; @@ -489,7 +456,7 @@ public static void SpringSimpleVelocitySmoothing( absTargetIntermediateDiff > anticipatedTime * smothingVelocity); // 直接调用SpringSimple函数 - SpringSimple(deltaTime, ref currentValue, ref currentVelocity, ref futureTargetPosition, ref newVelocity, ref result, stiffness); + SpringSimple(deltaTime, ref currentValue, ref currentVelocity, futureTargetPosition, stiffness); // 更新中间位置 intermediatePosition = math.select(targetValue, @@ -512,13 +479,11 @@ public static void SpringSimpleVelocitySmoothing( /// 新的位移值 [BurstCompile] public static void SpringSimpleDurationLimit( - float deltaTime, + in float deltaTime, ref float4 currentValue, ref float4 currentVelocity, ref float4 targetValue, - ref float4 newVelocity, - ref float4 result, - float durationSeconds = 0.2f) + in float durationSeconds = 0.2f) { // 根据目标时间计算合适的自然频率 // 对于临界阻尼系统,收敛时间约为 3-4 倍的时间常数 @@ -528,9 +493,7 @@ public static void SpringSimpleDurationLimit( // 直接使用目标值,不需要复杂的中间目标逻辑 // 让弹簧直接收敛到最终目标 - SpringSimple(deltaTime, ref currentValue, ref currentVelocity, ref targetValue, ref newVelocity, ref result, naturalFreq); - - // result已经在SpringSimple调用中设置 + SpringSimple(deltaTime, ref currentValue, ref currentVelocity, targetValue, naturalFreq); } /// @@ -547,54 +510,52 @@ public static void SpringSimpleDurationLimit( /// 新的位移值 [BurstCompile] public static void SpringSimpleDoubleSmoothing( - float deltaTime, + in float deltaTime, ref float4 currentValue, ref float4 currentVelocity, - ref float4 targetValue, - ref float4 newVelocity, + in float4 targetValue, ref float4 intermediatePosition, ref float4 intermediateVelocity, - ref float4 result, - float stiffness = 1.0f) + in float stiffness = 1.0f) { - float doubleStiffness = 2.0f * stiffness; + float floatStiffness = 2.0f * stiffness; // 第一层弹簧:从中间位置到目标位置 // 直接修改intermediatePosition和intermediateVelocity - SpringSimple(deltaTime, ref intermediatePosition, ref intermediateVelocity, ref targetValue, ref intermediateVelocity, ref intermediatePosition, doubleStiffness); + SpringSimple(deltaTime, ref intermediatePosition, ref intermediateVelocity, targetValue, floatStiffness); // 第二层弹簧:从当前位置到中间位置 // 使用修改后的intermediatePosition作为目标 - SpringSimple(deltaTime, ref currentValue, ref currentVelocity, ref intermediatePosition, ref newVelocity, ref result, doubleStiffness); + SpringSimple(deltaTime, ref currentValue, ref currentVelocity, intermediatePosition, floatStiffness); } #endregion - private static double HalfLifeToDamping(double halfLife, double eps = 1e-5d) + private static float HalfLifeToDamping(float halfLife, float eps = 1e-5f) { - return (4.0d * 0.6931471805599453d) / (halfLife + eps); + return (4.0f * 0.6931471805599453f) / (halfLife + eps); } - private static double DampingToHalfLife(double damping, double eps = 1e-5d) + private static float DampingToHalfLife(float damping, float eps = 1e-5f) { - return (4.0d * 0.6931471805599453d) / (damping + eps); + return (4.0f * 0.6931471805599453f) / (damping + eps); } - private static double DampingRatioToStiffness(double ratio, double damping) + private static float DampingRatioToStiffness(float ratio, float damping) { - return Square(damping / (ratio * 2.0d)); + return Square(damping / (ratio * 2.0f)); } - private static double DampingRatioToDamping(double ratio, double stiffness) + private static float DampingRatioToDamping(float ratio, float stiffness) { - return ratio * 2.0d * Math.Sqrt(stiffness); + return ratio * 2.0f * math.sqrt(stiffness); } - private static double FrequencyToStiffness(double frequency) + private static float FrequencyToStiffness(float frequency) { - return Square(2.0d * Math.PI * frequency); + return Square(2.0f * math.PI * frequency); } /// @@ -602,9 +563,9 @@ private static double FrequencyToStiffness(double frequency) /// /// 半衰期(秒) /// 自然频率(rad/s) - private static double HalflifeToNaturalFreq(double halflife) + private static float HalflifeToNaturalFreq(float halflife) { - return 0.69314718056d / halflife; // ω₀ = ln(2) / τ₁/₂ + return 0.69314718056f / halflife; // ω₀ = ln(2) / τ₁/₂ } /// @@ -612,16 +573,16 @@ private static double HalflifeToNaturalFreq(double halflife) /// /// 自然频率(rad/s) /// 半衰期(秒) - private static double NaturalFreqToHalflife(double naturalFreq) + private static float NaturalFreqToHalflife(float naturalFreq) { - return 0.69314718056d / naturalFreq; // τ₁/₂ = ln(2) / ω₀ + return 0.69314718056f / naturalFreq; // τ₁/₂ = ln(2) / ω₀ } - private static double FastNegExp(double x) + private static float FastNegExp(float x) { - return 1.0d / (1.0d + x + 0.48d * x * x + 0.235d * x * x * x); + return 1.0f / (1.0f + x + 0.48f * x * x + 0.235f * x * x * x); } - private static double Square(double x) + private static float Square(float x) { return x * x; } @@ -634,12 +595,12 @@ private static float4 Square(float4 x) /// /// 快速反正切函数近似,比Math.Atan快2-5倍,精度损失很小 /// - private static double FastAtan(double x) + private static float FastAtan(float x) { - double z = Math.Abs(x); - double w = z > 1.0d ? 1.0d / z : z; - double y = (Math.PI / 4.0d) * w - w * (w - 1) * (0.2447d + 0.0663d * w); - return Math.Sign(x) * (z > 1.0d ? Math.PI / 2.0d - y : y); + float z = math.abs(x); + float w = z > 1.0f ? 1.0f / z : z; + float y = (math.PI / 4.0f) * w - w * (w - 1) * (0.2447f + 0.0663f * w); + return math.sign(x) * (z > 1.0f ? math.PI / 2.0f - y : y); } /// @@ -656,9 +617,15 @@ private static float4 FastAtan(float4 x) /// /// 快速平方函数,与直接乘法性能相同 /// - private static double FastSquare(double x) + private static float FastSquare(float x) { return x * x; } + + private static float FastExp(float x) + { + // 快速指数函数近似,适用于 Burst + return 1.0f / (1.0f - x + 0.5f * x * x - 0.1667f * x * x * x); + } } } From 153736c46f2a303ce5839d7036c8af92a20808f5 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Thu, 25 Sep 2025 03:27:20 +0800 Subject: [PATCH 28/55] =?UTF-8?q?=E7=9C=81=E7=95=A5=E7=B2=BE=E5=BA=A6?= =?UTF-8?q?=E5=AE=B9=E5=B7=AE=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets/LitMotion/Runtime/SpringUtility.cs | 44 ++++++++----------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs index 2b9ea657..917cce13 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs @@ -51,7 +51,6 @@ public static void SpringSimple( /// 目标速度(到达目标位置时的期望速度) /// 阻尼比 0.6 = Q弹 1 = 临界 1.2 = 稍缓 /// 弹簧刚度(实际上直接作为自然频率使用)5 = 1秒 10 = 0.5秒 16.5 = 0.2秒 - /// 计算精度容差 /// 新的位移值 public static void SpringElastic( in float deltaTime, @@ -60,8 +59,7 @@ public static void SpringElastic( in float targetValue, in float targetVelocity = 0.0f, in float dampingRatio = 0.5f, - in float stiffness = 10.0f, - in float precision = 1e-5f) + in float stiffness = 10.0f) { // 使用有意义的变量名,提高代码可读性 float targetPosition = targetValue; @@ -71,9 +69,9 @@ public static void SpringElastic( float stiffnessValue = naturalFreq * naturalFreq; // 刚度值 = naturalFreq² float dampingHalf = dampingRatio * naturalFreq; float dampingCoeff = 2.0f * dampingHalf; // 阻尼系数 = 2 * 阻尼比 * naturalFreq - float adjustedTargetPosition = targetPosition + (dampingCoeff * targetVel) / (stiffnessValue + precision); + float adjustedTargetPosition = targetPosition + (dampingCoeff * targetVel) / stiffnessValue; - if (Math.Abs(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f) < precision) // Critically Damped + if (Math.Abs(dampingRatio - 1.0f) < 1e-5f) // Critically Damped { float initialDisplacement = currentValue - adjustedTargetPosition; float initialVelocityWithDamping = currentVelocity + initialDisplacement * dampingHalf; @@ -83,12 +81,12 @@ public static void SpringElastic( currentValue = initialDisplacement * exponentialDecay + deltaTime * initialVelocityWithDamping * exponentialDecay + adjustedTargetPosition; currentVelocity = -dampingHalf * initialDisplacement * exponentialDecay - dampingHalf * deltaTime * initialVelocityWithDamping * exponentialDecay + initialVelocityWithDamping * exponentialDecay; } - else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f > 0.0f) // Under Damped + else if (dampingRatio < 1.0f) // Under Damped { float dampedFrequency = math.sqrt(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f); float displacementFromTarget = currentValue - adjustedTargetPosition; - float amplitude = math.sqrt(FastSquare(currentVelocity + dampingHalf * displacementFromTarget) / (dampedFrequency * dampedFrequency + precision) + FastSquare(displacementFromTarget)); - float phase = FastAtan((currentVelocity + displacementFromTarget * dampingHalf) / (-displacementFromTarget * dampedFrequency + precision)); + float amplitude = math.sqrt(FastSquare(currentVelocity + dampingHalf * displacementFromTarget) / (dampedFrequency * dampedFrequency) + FastSquare(displacementFromTarget)); + float phase = FastAtan((currentVelocity + displacementFromTarget * dampingHalf) / (-displacementFromTarget * dampedFrequency)); amplitude = displacementFromTarget > 0.0f ? amplitude : -amplitude; @@ -97,7 +95,7 @@ public static void SpringElastic( currentValue = amplitude * exponentialDecay * math.cos(dampedFrequency * deltaTime + phase) + adjustedTargetPosition; currentVelocity = -dampingHalf * amplitude * exponentialDecay * math.cos(dampedFrequency * deltaTime + phase) - dampedFrequency * amplitude * exponentialDecay * math.sin(dampedFrequency * deltaTime + phase); } - else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f < 0.0f) // Over Damped + else // Over Damped (dampingRatio > 1.0f) { float fastDecayRate = (dampingCoeff + math.sqrt(dampingCoeff * dampingCoeff - 4f * stiffnessValue)) / 2.0f; float slowDecayRate = (dampingCoeff - math.sqrt(dampingCoeff * dampingCoeff - 4f * stiffnessValue)) / 2.0f; @@ -124,7 +122,6 @@ public static void SpringElastic( /// 阻尼比 /// 弹簧刚度(实际上直接作为自然频率使用) /// 目标速度(到达目标位置时的期望速度) - /// 计算精度容差 /// 新的位移值 public static void SpringPrecise( in float deltaTime, @@ -133,22 +130,21 @@ public static void SpringPrecise( in float targetValue, in float targetVelocity = 0.0f, in float dampingRatio = 0.5f, - in float stiffness = 10.0f, - in float precision = 1e-5f) + in float stiffness = 10.0f) { // 将stiffness参数重命名为naturalFreq进行内部计算 float naturalFreq = stiffness; // 根据targetVelocity调整目标位置(类似SpringElastic的逻辑) float adjustedTargetPosition = targetValue; - if (math.abs(targetVelocity) > precision) + if (math.abs(targetVelocity) > 1e-5f) { // 计算调整后的目标位置,使系统在到达目标时具有指定速度 - // 使用与SpringElastic相同的逻辑:c = g + (d * q) / (s + eps) + // 使用与SpringElastic相同的逻辑:c = g + (d * q) / s // 其中 d = 2 * dampingRatio * naturalFreq, s = naturalFreq^2 float dampingCoeff = 2.0f * dampingRatio * naturalFreq; float stiffnessValue = naturalFreq * naturalFreq; - adjustedTargetPosition = targetValue + (dampingCoeff * targetVelocity) / (stiffnessValue + precision); + adjustedTargetPosition = targetValue + (dampingCoeff * targetVelocity) / stiffnessValue; } float adjustedDisplacement = currentValue - adjustedTargetPosition; @@ -172,7 +168,7 @@ public static void SpringPrecise( calculatedVelocity = coeffA * gammaMinus * FastExp(gammaMinus * deltaTime) + coeffB * gammaPlus * FastExp(gammaPlus * deltaTime); } - else if (math.abs(dampingRatio - 1.0f) < precision) + else if (math.abs(dampingRatio - 1.0f) < 1e-5f) { // 临界阻尼 float coeffA = adjustedDisplacement; @@ -354,7 +350,6 @@ public static void SpringSimple( /// 目标速度(到达目标位置时的期望速度) /// 阻尼比 0.6 = Q弹 1 = 临界 1.2 = 稍缓 /// 弹簧刚度(实际上直接作为自然频率使用)5 = 1秒 10 = 0.5秒 16.5 = 0.2秒 - /// 计算精度容差 /// 新的位移值 [BurstCompile] public static void SpringElastic( @@ -364,17 +359,16 @@ public static void SpringElastic( in float4 targetValue, in float4 targetVelocity, in float dampingRatio = 0.5f, - in float stiffness = 1.0f, - in float precision = 1e-5f) + in float stiffness = 10.0f) { // 将stiffness参数重命名为naturalFreq进行内部计算 float naturalFreq = stiffness; float stiffnessValue = naturalFreq * naturalFreq; // 刚度值 = naturalFreq² float dampingHalf = dampingRatio * naturalFreq; float dampingCoeff = 2.0f * dampingHalf; // 阻尼系数 = 2 * 阻尼比 * naturalFreq - float4 adjustedtargetValue = targetValue + (dampingCoeff * targetVelocity) / (stiffnessValue + precision); + float4 adjustedtargetValue = targetValue + (dampingCoeff * targetVelocity) / stiffnessValue; - if (math.abs(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f) < precision) // Critically Damped + if (math.abs(dampingRatio - 1.0f) < 1e-5f) // Critically Damped { float4 initialDisplacement = currentValue - adjustedtargetValue; float4 initialVelocityWithDamping = currentVelocity + initialDisplacement * dampingHalf; @@ -384,12 +378,12 @@ public static void SpringElastic( currentValue = initialDisplacement * exponentialDecay + deltaTime * initialVelocityWithDamping * exponentialDecay + adjustedtargetValue; currentVelocity = -dampingHalf * initialDisplacement * exponentialDecay - dampingHalf * deltaTime * initialVelocityWithDamping * exponentialDecay + initialVelocityWithDamping * exponentialDecay; } - else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f > 0.0f) // Under Damped + else if (dampingRatio < 1.0f) // Under Damped { float dampedFrequency = math.sqrt(stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f); float4 displacementFromTarget = currentValue - adjustedtargetValue; - float4 amplitude = math.sqrt(Square(currentVelocity + dampingHalf * displacementFromTarget) / (dampedFrequency * dampedFrequency + precision) + Square(displacementFromTarget)); - float4 phase = FastAtan((currentVelocity + displacementFromTarget * dampingHalf) / (-displacementFromTarget * dampedFrequency + precision)); + float4 amplitude = math.sqrt(Square(currentVelocity + dampingHalf * displacementFromTarget) / (dampedFrequency * dampedFrequency) + Square(displacementFromTarget)); + float4 phase = FastAtan((currentVelocity + displacementFromTarget * dampingHalf) / (-displacementFromTarget * dampedFrequency)); amplitude = math.select(-amplitude, amplitude, displacementFromTarget > 0.0f); @@ -398,7 +392,7 @@ public static void SpringElastic( currentValue = amplitude * exponentialDecay * math.cos(dampedFrequency * deltaTime + phase) + adjustedtargetValue; currentVelocity = -dampingHalf * amplitude * exponentialDecay * math.cos(dampedFrequency * deltaTime + phase) - dampedFrequency * amplitude * exponentialDecay * math.sin(dampedFrequency * deltaTime + phase); } - else if (stiffnessValue - (dampingCoeff * dampingCoeff) / 4.0f < 0.0f) // Over Damped + else // Over Damped (dampingRatio > 1.0f) { float fastDecayRate = (dampingCoeff + math.sqrt(dampingCoeff * dampingCoeff - 4f * stiffnessValue)) / 2.0f; float slowDecayRate = (dampingCoeff - math.sqrt(dampingCoeff * dampingCoeff - 4f * stiffnessValue)) / 2.0f; From 7f63441640c3afdaff082bbcc68c9532950f8bea Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Thu, 25 Sep 2025 03:58:23 +0800 Subject: [PATCH 29/55] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=98=88=E5=80=BC?= =?UTF-8?q?=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets/LitMotion/Runtime/SpringUtility.cs | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs index 917cce13..c4a444f9 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs @@ -1,5 +1,6 @@ using System; using Unity.Burst; +using Unity.Burst.CompilerServices; using Unity.Mathematics; using UnityEngine; using static Unity.Mathematics.math; @@ -61,6 +62,12 @@ public static void SpringElastic( in float dampingRatio = 0.5f, in float stiffness = 10.0f) { + if (Hint.Unlikely(Approximately(currentValue, targetValue))) + { + currentValue = targetValue; + currentVelocity = 0.0f; + return; + } // 使用有意义的变量名,提高代码可读性 float targetPosition = targetValue; float targetVel = targetVelocity; @@ -325,6 +332,14 @@ public static void SpringSimple( in float4 targetValue, in float stiffness = 1.0f) { + // 检查是否已经收敛到目标值 + if (Hint.Unlikely(Approximately(currentValue, targetValue))) + { + currentValue = targetValue; + currentVelocity = new float4(0.0f); + return; + } + // SpringSimple是专门为临界阻尼设计的简化版本 // 直接使用stiffness作为自然频率,阻尼系数的一半等于自然频率 float naturalFreq = stiffness; @@ -361,6 +376,14 @@ public static void SpringElastic( in float dampingRatio = 0.5f, in float stiffness = 10.0f) { + // 检查是否已经收敛到目标值 + if (Hint.Unlikely(Approximately(currentValue, targetValue))) + { + currentValue = targetValue; + currentVelocity = new float4(0.0f); + return; + } + // 将stiffness参数重命名为naturalFreq进行内部计算 float naturalFreq = stiffness; float stiffnessValue = naturalFreq * naturalFreq; // 刚度值 = naturalFreq² @@ -513,7 +536,7 @@ public static void SpringSimpleDoubleSmoothing( in float stiffness = 1.0f) { float floatStiffness = 2.0f * stiffness; - + // 第一层弹簧:从中间位置到目标位置 // 直接修改intermediatePosition和intermediateVelocity SpringSimple(deltaTime, ref intermediatePosition, ref intermediateVelocity, targetValue, floatStiffness); @@ -621,5 +644,30 @@ private static float FastExp(float x) // 快速指数函数近似,适用于 Burst return 1.0f / (1.0f - x + 0.5f * x * x - 0.1667f * x * x * x); } + /// + /// 检查两个float值是否近似相等 + /// + /// 第一个值 + /// 第二个值 + /// 精度阈值 + /// 如果近似相等则返回true + [BurstCompile] + public static bool Approximately(in float a, in float b, in float precision = 1e-5f) + { + return math.abs(b - a) < math.max(1E-06f * math.max(math.abs(a), math.abs(b)), precision); + } + + /// + /// 检查两个float4值是否近似相等 + /// + /// 第一个值 + /// 第二个值 + /// 精度阈值 + /// 如果所有维度都近似相等则返回true + [BurstCompile] + public static bool Approximately(in float4 a, in float4 b, in float precision = 1e-5f) + { + return math.all(math.abs(b - a) < math.max(1E-06f * math.max(math.abs(a), math.abs(b)), precision)); + } } } From 975a44744ab15f06b8d7772b18643aba94160561 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Sat, 27 Sep 2025 07:19:08 +0800 Subject: [PATCH 30/55] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=AF=B9Delay=E3=80=81?= =?UTF-8?q?Loops=E3=80=81Compeleted=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 这一步我不得不对MotionData大改,不然无法处理这些功能的兼容 --- .../Runtime/Adapters/SpringMotionAdapters.cs | 61 ++++++-- .../LitMotion/Runtime/IMotionAdapter.cs | 7 + .../LitMotion/Runtime/IMotionOptions.cs | 5 +- .../LitMotion/Runtime/Internal/MotionData.cs | 138 +++++++++++++++--- .../LitMotion/Runtime/LMotion.Spring.cs | 26 ++-- .../LitMotion/Runtime/MotionUpdateJob.cs | 4 +- .../Runtime/Options/SpringOptions.cs | 66 ++++++++- .../Assets/LitMotion/Runtime/SpringUtility.cs | 4 +- 8 files changed, 254 insertions(+), 57 deletions(-) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs index ba8f9fca..848e1093 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs @@ -15,18 +15,30 @@ namespace LitMotion.Adapters { public float Evaluate(ref float startValue, ref float endValue, ref SpringOptions options, in MotionEvaluationContext context) { + ref float targetValue = ref options.TargetValue.x; + targetValue = endValue; // 调用SpringElastic函数计算新的位置和速度 SpringUtility.SpringElastic( (float)context.DeltaTime, ref options.CurrentValue.x, ref options.CurrentVelocity.x, - endValue, + options.TargetValue.x, options.TargetVelocity.x, options.DampingRatio, options.Stiffness ); return options.CurrentValue.x; } + + public bool IsCompleted(ref float startValue, ref float endValue, ref SpringOptions options) + { + // 使用阈值比较,避免精确相等比较的Burst问题 + bool isCompleted = SpringUtility.Approximately(options.CurrentValue.x, options.TargetValue.x); + + return isCompleted; + } + + public bool IsDurationBased => false; } /// @@ -38,21 +50,29 @@ public Vector2 Evaluate(ref Vector2 startValue, ref Vector2 endValue, ref Spring { // 使用MotionEvaluationContext中的DeltaTime float deltaTime = (float)context.DeltaTime; - - // 转换为float4进行计算 - float4 f4EndValue = new float4(endValue, 0, 0); + options.TargetValue.xy = endValue; // 使用float4版本的SpringElastic SpringUtility.SpringElastic( deltaTime, ref options.CurrentValue, ref options.CurrentVelocity, - f4EndValue, + options.TargetValue, options.TargetVelocity, options.DampingRatio, options.Stiffness ); return options.CurrentValue.xy; } + + public bool IsCompleted(ref Vector2 startValue, ref Vector2 endValue, ref SpringOptions options) + { + // 检查是否收敛到目标值(使用阈值比较) + bool isCompleted = SpringUtility.Approximately(options.CurrentValue, options.TargetValue); + + return isCompleted; + } + + public bool IsDurationBased => false; } /// @@ -64,20 +84,30 @@ public Vector3 Evaluate(ref Vector3 startValue, ref Vector3 endValue, ref Spring { // 使用MotionEvaluationContext中的DeltaTime float deltaTime = (float)context.DeltaTime; - // 转换为float4进行计算 - float4 f4EndValue = new float4(endValue, 0); + ref float4 targetValue = ref options.TargetValue; + options.TargetValue.xyz = endValue; // 使用float4版本的SpringElastic SpringUtility.SpringElastic( deltaTime, ref options.CurrentValue, ref options.CurrentVelocity, - f4EndValue, + options.TargetValue, options.TargetVelocity, options.DampingRatio, options.Stiffness ); return options.CurrentValue.xyz; } + + public bool IsCompleted(ref Vector3 startValue, ref Vector3 endValue, ref SpringOptions options) + { + // 检查是否收敛到目标值(使用阈值比较) + bool isCompleted = SpringUtility.Approximately(options.CurrentValue, options.TargetValue); + + return isCompleted; + } + + public bool IsDurationBased => false; } /// @@ -89,15 +119,14 @@ public Vector4 Evaluate(ref Vector4 startValue, ref Vector4 endValue, ref Spring { // 使用MotionEvaluationContext中的DeltaTime float deltaTime = (float)context.DeltaTime; - - // 转换为float4进行计算 - float4 f4EndValue = endValue; + ref float4 targetValue = ref options.TargetValue; + targetValue = endValue; // 使用float4版本的SpringElastic SpringUtility.SpringElastic( deltaTime, ref options.CurrentValue, ref options.CurrentVelocity, - f4EndValue, + options.TargetValue, options.TargetVelocity, options.DampingRatio, options.Stiffness @@ -105,5 +134,13 @@ public Vector4 Evaluate(ref Vector4 startValue, ref Vector4 endValue, ref Spring return options.CurrentValue; } + + public bool IsCompleted(ref Vector4 startValue, ref Vector4 endValue, ref SpringOptions options) + { + bool isCompleted = SpringUtility.Approximately(options.CurrentValue, options.TargetValue); + return isCompleted; + } + + public bool IsDurationBased => false; } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/IMotionAdapter.cs b/src/LitMotion/Assets/LitMotion/Runtime/IMotionAdapter.cs index f3313e3d..83df8a5b 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/IMotionAdapter.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/IMotionAdapter.cs @@ -18,5 +18,12 @@ public interface IMotionAdapter /// Animation context /// Current value TValue Evaluate(ref TValue startValue, ref TValue endValue, ref TOptions options, in MotionEvaluationContext context); + + bool IsCompleted(ref TValue startValue, ref TValue endValue, ref TOptions options) + { + return false; + } + + bool IsDurationBased => true; } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/IMotionOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/IMotionOptions.cs index d1ddaa7f..7e498e6d 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/IMotionOptions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/IMotionOptions.cs @@ -3,5 +3,8 @@ namespace LitMotion /// /// Implement this interface to define special options that can be applied to motion. /// - public interface IMotionOptions { } + public interface IMotionOptions + { + void Restart() { } + } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs index 3d9a5d2b..7764ca0d 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs @@ -54,10 +54,11 @@ public readonly double TotalDuration public MotionState State; public MotionParameters Parameters; + public double CurrentLoopStartTime; public readonly double TimeSinceStart => State.Time - Parameters.Delay; - public void Update(double time, out float progress) + public void UpdateDurationBasedState(double time, out float progress) { State.PrevCompletedLoops = State.CompletedLoops; State.PrevStatus = State.Status; @@ -172,6 +173,41 @@ public void Update(double time, out float progress) } } + public void UpdateIterationState(double time, double deltaTime,bool isOnceCompleted) + { + State.PrevCompletedLoops = State.CompletedLoops; + State.PrevStatus = State.Status; + State.Time = time; + bool isDelayed; + if(time == 0 || (isOnceCompleted && State.CompletedLoops <= Parameters.Loops - 1)) + { + CurrentLoopStartTime = time; + } + if (Parameters.DelayType == DelayType.FirstLoop) + isDelayed = TimeSinceStart < 0f; + else + { + isDelayed = State.Time - CurrentLoopStartTime - Parameters.Delay < 0f; + } + + if (isOnceCompleted) + { + State.CompletedLoops++; + } + if (isOnceCompleted && Parameters.Loops >= 0 && State.CompletedLoops > Parameters.Loops - 1) + { + State.Status = MotionStatus.Completed; + } + else if (isDelayed || State.Time < 0) + { + State.Status = MotionStatus.Delayed; + } + else + { + State.Status = MotionStatus.Playing; + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Complete(out float progress) { @@ -227,32 +263,96 @@ internal struct MotionData public void Update(double time, double deltaTime, out TValue result) where TAdapter : unmanaged, IMotionAdapter { - Core.Update(time, out var progress); - - result = default(TAdapter).Evaluate(ref StartValue, ref EndValue, ref Options, new MotionEvaluationContext() + bool isDurationBased = default(TAdapter).IsDurationBased; + if (isDurationBased) { - Progress = progress, - Time = time, - DeltaTime = deltaTime, - }); + Core.UpdateDurationBasedState(time, out var progress); + result = default(TAdapter).Evaluate(ref StartValue, ref EndValue, ref Options, new MotionEvaluationContext() + { + Progress = progress, + Time = time, + DeltaTime = deltaTime, + }); + } + else + { + bool isOnceCompleted = false; + if (time <= 0 || Core.State.Status == MotionStatus.Scheduled) + Core.UpdateIterationState(time, deltaTime, false); + + if (Core.State.Status == MotionStatus.Delayed) + result = StartValue; + else if (Core.State.Status == MotionStatus.Completed) + result = EndValue; + else + { + if (Core.Parameters.LoopType == LoopType.Restart) + { + result = default(TAdapter).Evaluate(ref StartValue, ref EndValue, ref Options, new MotionEvaluationContext() + { + Time = time, + DeltaTime = deltaTime, + }); + isOnceCompleted = default(TAdapter).IsCompleted(ref StartValue, ref EndValue, ref Options); + if (isOnceCompleted && Core.State.Status == MotionStatus.Playing) + Options.Restart(); + } + else if (Core.Parameters.LoopType == LoopType.Flip || Core.Parameters.LoopType == LoopType.Yoyo) + { + var isOdd = Core.State.CompletedLoops % 2 == 1; + result = isOdd + ? default(TAdapter).Evaluate(ref EndValue, ref StartValue, ref Options, new MotionEvaluationContext() + { + Time = time, + DeltaTime = deltaTime, + }) + : default(TAdapter).Evaluate(ref StartValue, ref EndValue, ref Options, new MotionEvaluationContext() + { + Time = time, + DeltaTime = deltaTime, + }); + isOnceCompleted = isOdd + ? default(TAdapter).IsCompleted(ref EndValue, ref StartValue, ref Options) + : default(TAdapter).IsCompleted(ref StartValue, ref EndValue, ref Options); + } + else + { + + result = default(TAdapter).Evaluate(ref StartValue, ref EndValue, ref Options, new MotionEvaluationContext() + { + Time = time, + DeltaTime = deltaTime, + }); + isOnceCompleted = default(TAdapter).IsCompleted(ref StartValue, ref EndValue, ref Options); + } + } + Core.UpdateIterationState(time, deltaTime, isOnceCompleted); + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Complete(out TValue result) where TAdapter : unmanaged, IMotionAdapter { + bool isDurationBased = default(TAdapter).IsDurationBased; Core.Complete(out var progress); - - result = default(TAdapter).Evaluate( - ref StartValue, - ref EndValue, - ref Options, - new() - { - Progress = progress, - Time = Core.State.Time, - } - ); + if (isDurationBased) + { + result = default(TAdapter).Evaluate( + ref StartValue, + ref EndValue, + ref Options, + new() + { + Progress = progress, + Time = Core.State.Time, + } + ); + } + else + { + result = EndValue; + } } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs index 5f34da6e..8ba3fecc 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs @@ -1,6 +1,6 @@ using UnityEngine; using LitMotion.Adapters; - +using Unity.Mathematics; namespace LitMotion { public static partial class LMotion @@ -18,10 +18,10 @@ public static class Spring /// Duration /// Spring options /// Created motion builder - public static MotionBuilder Create(float startValue, float endValue, float duration, SpringOptions options) + public static MotionBuilder Create(float startValue, float endValue, SpringOptions options = default) { - options.CurrentValue.x = startValue; - return Create(startValue, endValue, duration) + options.Init(new float4(startValue, 0.0f, 0.0f, 0.0f), new float4(endValue, 0.0f, 0.0f, 0.0f)); + return Create(startValue, endValue, 0.0f) .WithOptions(options); } @@ -33,10 +33,10 @@ public static MotionBuilder Crea /// Duration /// Spring options /// Created motion builder - public static MotionBuilder Create(Vector2 startValue, Vector2 endValue, float duration, SpringOptions options) + public static MotionBuilder Create(Vector2 startValue, Vector2 endValue,SpringOptions options = default, Vector2 targetVelocity = default) { - options.CurrentValue.xy = startValue; - return Create(startValue, endValue, duration) + options.Init(new float4(startValue, 0.0f, 0.0f), new float4(endValue, 0.0f,0.0f)); + return Create(startValue, endValue, 0.0f) .WithOptions(options); } @@ -48,10 +48,10 @@ public static MotionBuilder /// Duration /// Spring options /// Created motion builder - public static MotionBuilder Create(Vector3 startValue, Vector3 endValue, float duration, SpringOptions options) + public static MotionBuilder Create(Vector3 startValue, Vector3 endValue,SpringOptions options = default, Vector3 targetVelocity = default) { - options.CurrentValue.xyz = startValue; - return Create(startValue, endValue, duration) + options.Init(new float4(startValue, 0.0f), new float4(endValue, 0.0f)); + return Create(startValue, endValue, 0.0f) .WithOptions(options); } @@ -63,10 +63,10 @@ public static MotionBuilder /// Duration /// Spring options /// Created motion builder - public static MotionBuilder Create(Vector4 startValue, Vector4 endValue, float duration, SpringOptions options) + public static MotionBuilder Create(Vector4 startValue, Vector4 endValue,SpringOptions options = default, Vector4 targetVelocity = default) { - options.CurrentValue.xyzw = startValue; - return Create(startValue, endValue, duration) + options.Init(new float4(startValue), new float4(endValue)); + return Create(startValue, endValue, 0.0f) .WithOptions(options); } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs index 44fe826e..4cbb0725 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs @@ -43,9 +43,9 @@ public void Execute([AssumeRange(0, int.MaxValue)] int index) MotionTimeKind.UnscaledTime => UnscaledDeltaTime, MotionTimeKind.Realtime => RealDeltaTime, _ => default - }; + } * state.PlaybackSpeed; - var time = state.Time + deltaTime * state.PlaybackSpeed; + var time = state.Time + deltaTime; ptr->Update(time, deltaTime, out var result); Output[index] = result; } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs index 74597290..b0c0df97 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs @@ -10,12 +10,30 @@ namespace LitMotion [Serializable] public struct SpringOptions : IEquatable, IMotionOptions { + private float4 _startValue; + private float4 _startVelocity; public float4 CurrentValue; public float4 CurrentVelocity; + public float4 TargetValue; public float4 TargetVelocity; public float Stiffness; public float DampingRatio; + /// + /// 默认构造函数,创建临界阻尼的Spring选项 + /// + public SpringOptions(float stiffness = 10.0f, float dampingRatio = 1.0f,float4 startVelocity = default,float4 targetVelocity = default) + { + Stiffness = stiffness; + DampingRatio = dampingRatio; + CurrentValue = new float4(0.0f, 0.0f, 0.0f, 0.0f); + CurrentVelocity = startVelocity; + TargetValue = new float4(0.0f, 0.0f, 0.0f, 0.0f); + TargetVelocity = targetVelocity; + _startValue = new float4(0.0f, 0.0f, 0.0f, 0.0f); + _startVelocity = startVelocity; + } + //public CompleteMode CompleteMode; public static SpringOptions Critical { get @@ -25,10 +43,10 @@ public static SpringOptions Critical Stiffness = 10.0f, DampingRatio = 1.0f, CurrentVelocity = new float4(0.0f, 0.0f, 0.0f, 0.0f), - TargetVelocity = new float4(1.0f, 0.0f, 0.0f, 0.0f), + TargetVelocity = new float4(0.0f, 0.0f, 0.0f, 0.0f), CurrentValue = new float4(0.0f, 0.0f, 0.0f, 0.0f) }; - } + } } public static SpringOptions Overdamped @@ -40,11 +58,11 @@ public static SpringOptions Overdamped Stiffness = 10.0f, DampingRatio = 1.2f, CurrentVelocity = new float4(0.0f, 0.0f, 0.0f, 0.0f), - TargetVelocity = new float4(1.0f, 0.0f, 0.0f, 0.0f), + TargetVelocity = new float4(0.0f, 0.0f, 0.0f, 0.0f), CurrentValue = new float4(0.0f, 0.0f, 0.0f, 0.0f) }; } - } + } public static SpringOptions Underdamped { @@ -55,19 +73,35 @@ public static SpringOptions Underdamped Stiffness = 10.0f, DampingRatio = 0.6f, CurrentVelocity = new float4(0.0f, 0.0f, 0.0f, 0.0f), - TargetVelocity = new float4(1.0f, 0.0f, 0.0f, 0.0f), + TargetVelocity = new float4(0.0f, 0.0f, 0.0f, 0.0f), CurrentValue = new float4(0.0f, 0.0f, 0.0f, 0.0f) }; } } + public void Init(float4 startValue, float4 targetValue, float4 startVelocity = default, float4 targetVelocity = default) + { + CurrentValue = startValue; + TargetValue = targetValue; + CurrentVelocity = startVelocity; + TargetVelocity = targetVelocity; + _startValue = startValue; + _startVelocity = startVelocity; + } + + public void Restart() + { + CurrentValue = _startValue; + CurrentVelocity = _startVelocity; + } + public readonly bool Equals(SpringOptions other) { return Stiffness == other.Stiffness && DampingRatio == other.DampingRatio && - TargetVelocity.Equals(other.TargetVelocity) && - CurrentVelocity.Equals(other.CurrentVelocity) && - CurrentValue.Equals(other.CurrentValue); + math.all(TargetVelocity == other.TargetVelocity) && + math.all(CurrentVelocity == other.CurrentVelocity) && + math.all(CurrentValue == other.CurrentValue); } public override readonly bool Equals(object obj) @@ -81,4 +115,20 @@ public override readonly int GetHashCode() return HashCode.Combine(Stiffness, DampingRatio, TargetVelocity, CurrentVelocity, CurrentValue); } } + + public enum CompleteMode : byte + { + /// + /// 根据给出的持续时间计算出适当的刚度,只支持临界阻尼 + /// + DurationBased, + /// + /// 持续时间不定,收敛到阈值后结束。支持三种阻尼 + /// + ConvergeToThreshold, + /// + /// 无线持续,必须手动结束。支持三种阻尼 + /// + Infinite, + } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs index c4a444f9..d6534dd3 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs @@ -652,7 +652,7 @@ private static float FastExp(float x) /// 精度阈值 /// 如果近似相等则返回true [BurstCompile] - public static bool Approximately(in float a, in float b, in float precision = 1e-5f) + public static bool Approximately(in float a, in float b, in float precision = 1e-2f) { return math.abs(b - a) < math.max(1E-06f * math.max(math.abs(a), math.abs(b)), precision); } @@ -665,7 +665,7 @@ public static bool Approximately(in float a, in float b, in float precision = 1e /// 精度阈值 /// 如果所有维度都近似相等则返回true [BurstCompile] - public static bool Approximately(in float4 a, in float4 b, in float precision = 1e-5f) + public static bool Approximately(in float4 a, in float4 b, in float precision = 1e-2f) { return math.all(math.abs(b - a) < math.max(1E-06f * math.max(math.abs(a), math.abs(b)), precision)); } From b21770a28e7a371f014182da972c2fe666534335 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Sun, 28 Sep 2025 03:31:51 +0800 Subject: [PATCH 31/55] =?UTF-8?q?=E5=88=A0=E6=8E=89=E6=9C=AA=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E4=BB=A3=E7=A0=81=EF=BC=8C=E6=B3=A8=E9=87=8A=E6=9B=B4?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E4=B8=AD=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Runtime/Adapters/SpringMotionAdapters.cs | 38 +++++-------------- .../LitMotion/Runtime/LMotion.Spring.cs | 12 ++---- .../Runtime/Options/SpringOptions.cs | 34 ++++++++--------- 3 files changed, 29 insertions(+), 55 deletions(-) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs index 848e1093..d0f9a7df 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Adapters/SpringMotionAdapters.cs @@ -15,9 +15,7 @@ namespace LitMotion.Adapters { public float Evaluate(ref float startValue, ref float endValue, ref SpringOptions options, in MotionEvaluationContext context) { - ref float targetValue = ref options.TargetValue.x; - targetValue = endValue; - // 调用SpringElastic函数计算新的位置和速度 + options.TargetValue.x = endValue; SpringUtility.SpringElastic( (float)context.DeltaTime, ref options.CurrentValue.x, @@ -32,26 +30,21 @@ public float Evaluate(ref float startValue, ref float endValue, ref SpringOption public bool IsCompleted(ref float startValue, ref float endValue, ref SpringOptions options) { - // 使用阈值比较,避免精确相等比较的Burst问题 - bool isCompleted = SpringUtility.Approximately(options.CurrentValue.x, options.TargetValue.x); - - return isCompleted; + return SpringUtility.Approximately(options.CurrentValue.x, options.TargetValue.x); } public bool IsDurationBased => false; } /// - /// Vector2 Spring适配器,使用float4版本的SpringElastic方法 + /// Spring motion adapter for Vector2 using float4 SpringElastic method. /// public readonly struct Vector2SpringMotionAdapter : IMotionAdapter { public Vector2 Evaluate(ref Vector2 startValue, ref Vector2 endValue, ref SpringOptions options, in MotionEvaluationContext context) { - // 使用MotionEvaluationContext中的DeltaTime float deltaTime = (float)context.DeltaTime; options.TargetValue.xy = endValue; - // 使用float4版本的SpringElastic SpringUtility.SpringElastic( deltaTime, ref options.CurrentValue, @@ -66,27 +59,21 @@ public Vector2 Evaluate(ref Vector2 startValue, ref Vector2 endValue, ref Spring public bool IsCompleted(ref Vector2 startValue, ref Vector2 endValue, ref SpringOptions options) { - // 检查是否收敛到目标值(使用阈值比较) - bool isCompleted = SpringUtility.Approximately(options.CurrentValue, options.TargetValue); - - return isCompleted; + return SpringUtility.Approximately(options.CurrentValue, options.TargetValue); } public bool IsDurationBased => false; } /// - /// Vector3 Spring适配器,使用float4版本的SpringElastic方法 + /// Spring motion adapter for Vector3 using float4 SpringElastic method. /// public readonly struct Vector3SpringMotionAdapter : IMotionAdapter { public Vector3 Evaluate(ref Vector3 startValue, ref Vector3 endValue, ref SpringOptions options, in MotionEvaluationContext context) { - // 使用MotionEvaluationContext中的DeltaTime float deltaTime = (float)context.DeltaTime; - ref float4 targetValue = ref options.TargetValue; options.TargetValue.xyz = endValue; - // 使用float4版本的SpringElastic SpringUtility.SpringElastic( deltaTime, ref options.CurrentValue, @@ -101,27 +88,21 @@ public Vector3 Evaluate(ref Vector3 startValue, ref Vector3 endValue, ref Spring public bool IsCompleted(ref Vector3 startValue, ref Vector3 endValue, ref SpringOptions options) { - // 检查是否收敛到目标值(使用阈值比较) - bool isCompleted = SpringUtility.Approximately(options.CurrentValue, options.TargetValue); - - return isCompleted; + return SpringUtility.Approximately(options.CurrentValue, options.TargetValue); } public bool IsDurationBased => false; } /// - /// Vector4 Spring适配器,使用float4版本的SpringElastic方法 + /// Spring motion adapter for Vector4 using float4 SpringElastic method. /// public readonly struct Vector4SpringMotionAdapter : IMotionAdapter { public Vector4 Evaluate(ref Vector4 startValue, ref Vector4 endValue, ref SpringOptions options, in MotionEvaluationContext context) { - // 使用MotionEvaluationContext中的DeltaTime float deltaTime = (float)context.DeltaTime; - ref float4 targetValue = ref options.TargetValue; - targetValue = endValue; - // 使用float4版本的SpringElastic + options.TargetValue = endValue; SpringUtility.SpringElastic( deltaTime, ref options.CurrentValue, @@ -137,8 +118,7 @@ public Vector4 Evaluate(ref Vector4 startValue, ref Vector4 endValue, ref Spring public bool IsCompleted(ref Vector4 startValue, ref Vector4 endValue, ref SpringOptions options) { - bool isCompleted = SpringUtility.Approximately(options.CurrentValue, options.TargetValue); - return isCompleted; + return SpringUtility.Approximately(options.CurrentValue, options.TargetValue); } public bool IsDurationBased => false; diff --git a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs index 8ba3fecc..082c85b1 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Spring.cs @@ -15,7 +15,6 @@ public static class Spring /// /// Start value /// End value - /// Duration /// Spring options /// Created motion builder public static MotionBuilder Create(float startValue, float endValue, SpringOptions options = default) @@ -30,12 +29,11 @@ public static MotionBuilder Crea /// /// Start value /// End value - /// Duration /// Spring options /// Created motion builder - public static MotionBuilder Create(Vector2 startValue, Vector2 endValue,SpringOptions options = default, Vector2 targetVelocity = default) + public static MotionBuilder Create(Vector2 startValue, Vector2 endValue, SpringOptions options = default) { - options.Init(new float4(startValue, 0.0f, 0.0f), new float4(endValue, 0.0f,0.0f)); + options.Init(new float4(startValue, 0.0f, 0.0f), new float4(endValue, 0.0f, 0.0f)); return Create(startValue, endValue, 0.0f) .WithOptions(options); } @@ -45,10 +43,9 @@ public static MotionBuilder /// /// Start value /// End value - /// Duration /// Spring options /// Created motion builder - public static MotionBuilder Create(Vector3 startValue, Vector3 endValue,SpringOptions options = default, Vector3 targetVelocity = default) + public static MotionBuilder Create(Vector3 startValue, Vector3 endValue, SpringOptions options = default) { options.Init(new float4(startValue, 0.0f), new float4(endValue, 0.0f)); return Create(startValue, endValue, 0.0f) @@ -60,10 +57,9 @@ public static MotionBuilder /// /// Start value /// End value - /// Duration /// Spring options /// Created motion builder - public static MotionBuilder Create(Vector4 startValue, Vector4 endValue,SpringOptions options = default, Vector4 targetVelocity = default) + public static MotionBuilder Create(Vector4 startValue, Vector4 endValue, SpringOptions options = default) { options.Init(new float4(startValue), new float4(endValue)); return Create(startValue, endValue, 0.0f) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs index b0c0df97..8488086f 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/SpringOptions.cs @@ -20,9 +20,13 @@ public struct SpringOptions : IEquatable, IMotionOptions public float DampingRatio; /// - /// 默认构造函数,创建临界阻尼的Spring选项 + /// Creates a new SpringOptions with specified parameters. /// - public SpringOptions(float stiffness = 10.0f, float dampingRatio = 1.0f,float4 startVelocity = default,float4 targetVelocity = default) + /// Spring stiffness (higher = faster convergence) + /// Damping ratio (1.0 = critical damping) + /// Initial velocity + /// Target velocity + public SpringOptions(float stiffness = 10.0f, float dampingRatio = 1.0f, float4 startVelocity = default, float4 targetVelocity = default) { Stiffness = stiffness; DampingRatio = dampingRatio; @@ -33,7 +37,10 @@ public SpringOptions(float stiffness = 10.0f, float dampingRatio = 1.0f,float4 s _startValue = new float4(0.0f, 0.0f, 0.0f, 0.0f); _startVelocity = startVelocity; } - //public CompleteMode CompleteMode; + + /// + /// Critical damping configuration (fastest convergence without oscillation). + /// public static SpringOptions Critical { get @@ -49,6 +56,9 @@ public static SpringOptions Critical } } + /// + /// Overdamped configuration (smooth, slow convergence without oscillation). + /// public static SpringOptions Overdamped { get @@ -64,6 +74,9 @@ public static SpringOptions Overdamped } } + /// + /// Underdamped configuration (bouncy, oscillating motion before settling). + /// public static SpringOptions Underdamped { get @@ -116,19 +129,4 @@ public override readonly int GetHashCode() } } - public enum CompleteMode : byte - { - /// - /// 根据给出的持续时间计算出适当的刚度,只支持临界阻尼 - /// - DurationBased, - /// - /// 持续时间不定,收敛到阈值后结束。支持三种阻尼 - /// - ConvergeToThreshold, - /// - /// 无线持续,必须手动结束。支持三种阻尼 - /// - Infinite, - } } From b1998fa93bdaa7e5b2bf711e2d46bd5c17da0f9b Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Sun, 28 Sep 2025 04:04:05 +0800 Subject: [PATCH 32/55] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E5=92=8C=E5=9C=BA=E6=99=AF=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Tests/BurstPerformanceUICreator.cs | 309 + .../Tests/BurstPerformanceUITest.cs | 858 + .../Tests/BurstTestUsageGuide.cs | 79 + .../LitMotion.Spring/Tests/DamperTest.asmdef | 22 + .../Tests/DamperUtilityTestUI.cs | 913 + .../Tests/DamperUtilityTestUISetup.cs | 423 + .../Tests/DamperUtilityTestUI_README.md | 226 + .../Editor/DamperUtilityPerformanceTest.cs | 546 + .../DamperUtilityPerformanceTest_README.md | 219 + .../DamperUtilitySimplePerformanceTest.cs | 301 + .../Editor/EaseUtilityPerformanceTest.cs | 329 + .../Tests/LitMotionSpringTestLauncher.cs | 129 + .../Tests/LitMotionSpringTestUI.cs | 1524 + .../Tests/LitMotionSpringTestUISetup.cs | 540 + .../Tests/LitMotionSpringTest_ButtonLabels.md | 83 + .../Tests/LitMotionSpringTest_README.md | 156 + .../Tests/LitMotionSpringTest_Summary.md | 159 + .../LitMotionSpringTest_Troubleshooting.md | 198 + .../Tests/README_BurstPerformanceTest.md | 148 + .../Tests/SpringUtilityTest.unity | 29375 ++++++++++++++++ 20 files changed, 36537 insertions(+) create mode 100644 samples/LitMotion.Spring/Tests/BurstPerformanceUICreator.cs create mode 100644 samples/LitMotion.Spring/Tests/BurstPerformanceUITest.cs create mode 100644 samples/LitMotion.Spring/Tests/BurstTestUsageGuide.cs create mode 100644 samples/LitMotion.Spring/Tests/DamperTest.asmdef create mode 100644 samples/LitMotion.Spring/Tests/DamperUtilityTestUI.cs create mode 100644 samples/LitMotion.Spring/Tests/DamperUtilityTestUISetup.cs create mode 100644 samples/LitMotion.Spring/Tests/DamperUtilityTestUI_README.md create mode 100644 samples/LitMotion.Spring/Tests/Editor/DamperUtilityPerformanceTest.cs create mode 100644 samples/LitMotion.Spring/Tests/Editor/DamperUtilityPerformanceTest_README.md create mode 100644 samples/LitMotion.Spring/Tests/Editor/DamperUtilitySimplePerformanceTest.cs create mode 100644 samples/LitMotion.Spring/Tests/Editor/EaseUtilityPerformanceTest.cs create mode 100644 samples/LitMotion.Spring/Tests/LitMotionSpringTestLauncher.cs create mode 100644 samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs create mode 100644 samples/LitMotion.Spring/Tests/LitMotionSpringTestUISetup.cs create mode 100644 samples/LitMotion.Spring/Tests/LitMotionSpringTest_ButtonLabels.md create mode 100644 samples/LitMotion.Spring/Tests/LitMotionSpringTest_README.md create mode 100644 samples/LitMotion.Spring/Tests/LitMotionSpringTest_Summary.md create mode 100644 samples/LitMotion.Spring/Tests/LitMotionSpringTest_Troubleshooting.md create mode 100644 samples/LitMotion.Spring/Tests/README_BurstPerformanceTest.md create mode 100644 samples/LitMotion.Spring/Tests/SpringUtilityTest.unity diff --git a/samples/LitMotion.Spring/Tests/BurstPerformanceUICreator.cs b/samples/LitMotion.Spring/Tests/BurstPerformanceUICreator.cs new file mode 100644 index 00000000..01676680 --- /dev/null +++ b/samples/LitMotion.Spring/Tests/BurstPerformanceUICreator.cs @@ -0,0 +1,309 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace ASUI.Test +{ + /// + /// 自动创建Burst性能测试UI的脚本 + /// 在编辑器中运行此脚本来创建测试界面 + /// + public class BurstPerformanceUICreator : MonoBehaviour + { + [ContextMenu("创建Burst性能测试UI")] + public void CreateBurstPerformanceUI() + { + // 创建Canvas + GameObject canvasGO = new GameObject("BurstPerformanceTestCanvas"); + Canvas canvas = canvasGO.AddComponent(); + canvas.renderMode = RenderMode.ScreenSpaceOverlay; + canvas.sortingOrder = 100; + + CanvasScaler scaler = canvasGO.AddComponent(); + scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; + scaler.referenceResolution = new Vector2(1920, 1080); + scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; + scaler.matchWidthOrHeight = 0.5f; + + canvasGO.AddComponent(); + + // 创建背景面板 + GameObject backgroundGO = new GameObject("Background"); + backgroundGO.transform.SetParent(canvasGO.transform, false); + + RectTransform backgroundRect = backgroundGO.AddComponent(); + backgroundRect.anchorMin = Vector2.zero; + backgroundRect.anchorMax = Vector2.one; + backgroundRect.offsetMin = Vector2.zero; + backgroundRect.offsetMax = Vector2.zero; + + Image backgroundImage = backgroundGO.AddComponent(); + backgroundImage.color = new Color(0, 0, 0, 0.8f); + + // 创建主面板 + GameObject mainPanelGO = new GameObject("MainPanel"); + mainPanelGO.transform.SetParent(backgroundGO.transform, false); + + RectTransform mainPanelRect = mainPanelGO.AddComponent(); + mainPanelRect.anchorMin = new Vector2(0.1f, 0.1f); + mainPanelRect.anchorMax = new Vector2(0.9f, 0.9f); + mainPanelRect.offsetMin = Vector2.zero; + mainPanelRect.offsetMax = Vector2.zero; + + Image mainPanelImage = mainPanelGO.AddComponent(); + mainPanelImage.color = new Color(0.2f, 0.2f, 0.2f, 0.9f); + + // 添加圆角效果 + mainPanelGO.AddComponent(); + + // 创建标题 + GameObject titleGO = new GameObject("Title"); + titleGO.transform.SetParent(mainPanelGO.transform, false); + + RectTransform titleRect = titleGO.AddComponent(); + titleRect.anchorMin = new Vector2(0, 0.85f); + titleRect.anchorMax = new Vector2(1, 1); + titleRect.offsetMin = new Vector2(20, 0); + titleRect.offsetMax = new Vector2(-20, -10); + + Text titleText = titleGO.AddComponent(); + titleText.text = "Burst性能测试工具"; + titleText.fontSize = 32; + titleText.color = Color.white; + titleText.alignment = TextAnchor.MiddleCenter; + titleText.fontStyle = FontStyle.Bold; + + // 创建控制面板 + GameObject controlPanelGO = new GameObject("ControlPanel"); + controlPanelGO.transform.SetParent(mainPanelGO.transform, false); + + RectTransform controlPanelRect = controlPanelGO.AddComponent(); + controlPanelRect.anchorMin = new Vector2(0, 0.7f); + controlPanelRect.anchorMax = new Vector2(1, 0.85f); + controlPanelRect.offsetMin = new Vector2(20, 0); + controlPanelRect.offsetMax = new Vector2(-20, -10); + + // 创建迭代次数滑块 + GameObject sliderGO = new GameObject("IterationSlider"); + sliderGO.transform.SetParent(controlPanelGO.transform, false); + + RectTransform sliderRect = sliderGO.AddComponent(); + sliderRect.anchorMin = new Vector2(0, 0.5f); + sliderRect.anchorMax = new Vector2(0.7f, 1); + sliderRect.offsetMin = Vector2.zero; + sliderRect.offsetMax = new Vector2(-10, 0); + + Slider slider = sliderGO.AddComponent(); + slider.minValue = 0f; + slider.maxValue = 1f; + slider.value = 0.5f; + + // 滑块背景 + GameObject sliderBackgroundGO = new GameObject("Background"); + sliderBackgroundGO.transform.SetParent(sliderGO.transform, false); + + RectTransform sliderBackgroundRect = sliderBackgroundGO.AddComponent(); + sliderBackgroundRect.anchorMin = Vector2.zero; + sliderBackgroundRect.anchorMax = Vector2.one; + sliderBackgroundRect.offsetMin = Vector2.zero; + sliderBackgroundRect.offsetMax = Vector2.zero; + + Image sliderBackgroundImage = sliderBackgroundGO.AddComponent(); + sliderBackgroundImage.color = new Color(0.3f, 0.3f, 0.3f, 1f); + + // 滑块填充 + GameObject sliderFillGO = new GameObject("Fill Area"); + sliderFillGO.transform.SetParent(sliderGO.transform, false); + + RectTransform sliderFillAreaRect = sliderFillGO.AddComponent(); + sliderFillAreaRect.anchorMin = Vector2.zero; + sliderFillAreaRect.anchorMax = Vector2.one; + sliderFillAreaRect.offsetMin = Vector2.zero; + sliderFillAreaRect.offsetMax = Vector2.zero; + + GameObject sliderFillGO2 = new GameObject("Fill"); + sliderFillGO2.transform.SetParent(sliderFillGO.transform, false); + + RectTransform sliderFillRect = sliderFillGO2.AddComponent(); + sliderFillRect.anchorMin = Vector2.zero; + sliderFillRect.anchorMax = Vector2.one; + sliderFillRect.offsetMin = Vector2.zero; + sliderFillRect.offsetMax = Vector2.zero; + + Image sliderFillImage = sliderFillGO2.AddComponent(); + sliderFillImage.color = new Color(0.2f, 0.6f, 1f, 1f); + + // 滑块手柄 + GameObject sliderHandleGO = new GameObject("Handle Slide Area"); + sliderHandleGO.transform.SetParent(sliderGO.transform, false); + + RectTransform sliderHandleAreaRect = sliderHandleGO.AddComponent(); + sliderHandleAreaRect.anchorMin = Vector2.zero; + sliderHandleAreaRect.anchorMax = Vector2.one; + sliderHandleAreaRect.offsetMin = Vector2.zero; + sliderHandleAreaRect.offsetMax = Vector2.zero; + + GameObject sliderHandleGO2 = new GameObject("Handle"); + sliderHandleGO2.transform.SetParent(sliderHandleGO.transform, false); + + RectTransform sliderHandleRect = sliderHandleGO2.AddComponent(); + sliderHandleRect.sizeDelta = new Vector2(20, 20); + + Image sliderHandleImage = sliderHandleGO2.AddComponent(); + sliderHandleImage.color = Color.white; + + // 设置滑块的引用 + slider.fillRect = sliderFillRect; + slider.handleRect = sliderHandleRect; + + // 创建迭代次数标签 + GameObject iterationLabelGO = new GameObject("IterationLabel"); + iterationLabelGO.transform.SetParent(controlPanelGO.transform, false); + + RectTransform iterationLabelRect = iterationLabelGO.AddComponent(); + iterationLabelRect.anchorMin = new Vector2(0.7f, 0.5f); + iterationLabelRect.anchorMax = new Vector2(1, 1); + iterationLabelRect.offsetMin = new Vector2(10, 0); + iterationLabelRect.offsetMax = Vector2.zero; + + Text iterationLabelText = iterationLabelGO.AddComponent(); + iterationLabelText.text = "迭代次数: 500,000"; + iterationLabelText.fontSize = 16; + iterationLabelText.color = Color.white; + iterationLabelText.alignment = TextAnchor.MiddleLeft; + + // 创建按钮面板 + GameObject buttonPanelGO = new GameObject("ButtonPanel"); + buttonPanelGO.transform.SetParent(controlPanelGO.transform, false); + + RectTransform buttonPanelRect = buttonPanelGO.AddComponent(); + buttonPanelRect.anchorMin = new Vector2(0, 0); + buttonPanelRect.anchorMax = new Vector2(1, 0.5f); + buttonPanelRect.offsetMin = new Vector2(0, 0); + buttonPanelRect.offsetMax = new Vector2(0, -5); + + // 创建运行测试按钮 + GameObject runButtonGO = new GameObject("RunTestButton"); + runButtonGO.transform.SetParent(buttonPanelGO.transform, false); + + RectTransform runButtonRect = runButtonGO.AddComponent(); + runButtonRect.anchorMin = new Vector2(0, 0); + runButtonRect.anchorMax = new Vector2(0.5f, 1); + runButtonRect.offsetMin = Vector2.zero; + runButtonRect.offsetMax = new Vector2(-5, 0); + + Image runButtonImage = runButtonGO.AddComponent(); + runButtonImage.color = new Color(0.2f, 0.8f, 0.2f, 1f); + + Button runButton = runButtonGO.AddComponent /// The type of value to animate - /// The type of vectorized value for internal processing /// The type of special parameters given to the motion data - /// The type of animation specification + /// The type of adapter that support value animation /// This builder /// Observable of the created motion. - public static Observable ToObservable(this MotionBuilder builder) + public static Observable ToObservable(this MotionBuilder builder) where TValue : unmanaged - where VValue : unmanaged - where TOptions : unmanaged, ITweenOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TOptions : unmanaged, IMotionOptions + where TAdapter : unmanaged, IMotionAdapter { var subject = new Subject(); builder.SetCallbackData(subject, static (x, subject) => subject.OnNext(x)); @@ -32,17 +30,15 @@ public static Observable ToObservable /// The type of value to animate - /// The type of vectorized value for internal processing /// The type of special parameters given to the motion data - /// The type of animation specification + /// The type of adapter that support value animation /// This builder - /// Target ReactiveProperty to bind to + /// Target object that implements IProgress /// Handle of the created motion data. - public static MotionHandle BindToReactiveProperty(this MotionBuilder builder, ReactiveProperty reactiveProperty) + public static MotionHandle BindToReactiveProperty(this MotionBuilder builder, ReactiveProperty reactiveProperty) where TValue : unmanaged - where VValue : unmanaged - where TOptions : unmanaged, ITweenOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TOptions : unmanaged, IMotionOptions + where TAdapter : unmanaged, IMotionAdapter { Error.IsNull(reactiveProperty); return builder.Bind(reactiveProperty, static (x, target) => diff --git a/src/LitMotion/Assets/LitMotion/Runtime/IMotionAdapter.cs b/src/LitMotion/Assets/LitMotion/Runtime/IMotionAdapter.cs index b68ba60f..83df8a5b 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/IMotionAdapter.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/IMotionAdapter.cs @@ -4,11 +4,9 @@ namespace LitMotion /// Implement this interface to define animating values of a particular type. /// /// The type of value to animate - /// The vectorized type for internal calculations /// The type of special parameters given to the motion entity - public interface IMotionAdapter : ITwoWayConverter + public interface IMotionAdapter where TValue : unmanaged - where VValue : unmanaged where TOptions : unmanaged, IMotionOptions { /// diff --git a/src/LitMotion/Assets/LitMotion/Runtime/IMotionScheduler.cs b/src/LitMotion/Assets/LitMotion/Runtime/IMotionScheduler.cs index c42b27b1..fcb22b96 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/IMotionScheduler.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/IMotionScheduler.cs @@ -9,16 +9,14 @@ public interface IMotionScheduler /// Schedule the motion. /// /// The type of value to animate - /// The type of vectorized value for internal processing /// The type of special parameters given to the motion data - /// The type of animation specification + /// The type of adapter that support value animation /// Motion builder /// Motion handle - MotionHandle Schedule(ref MotionBuilder builder) + MotionHandle Schedule(ref MotionBuilder builder) where TValue : unmanaged - where VValue : unmanaged - where TOptions : unmanaged, ITweenOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec; + where TOptions : unmanaged, IMotionOptions + where TAdapter : unmanaged, IMotionAdapter; } /// diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/ManagedMotionData.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/ManagedMotionData.cs index 62a37e1c..16d85870 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/ManagedMotionData.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/ManagedMotionData.cs @@ -88,36 +88,5 @@ public readonly void InvokeOnLoopComplete(int completedLoops) MotionDispatcher.GetUnhandledExceptionHandler()?.Invoke(ex); } } - - /// - /// Initialize the managed motion data with builder buffer values - /// - /// The type of value to animate - /// The options type - /// The motion builder buffer containing initialization data - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void Initialize(in MotionBuilderBuffer buffer, TValue startValue) - where TValue : unmanaged - where TOptions : unmanaged, IMotionOptions - { - CancelOnError = buffer.CancelOnError; - SkipValuesDuringDelay = buffer.SkipValuesDuringDelay; - UpdateAction = buffer.UpdateAction; - OnLoopCompleteAction = buffer.OnLoopCompleteAction; - OnCancelAction = buffer.OnCancelAction; - OnCompleteAction = buffer.OnCompleteAction; - StateCount = buffer.StateCount; - State0 = buffer.State0; - State1 = buffer.State1; - State2 = buffer.State2; - -#if LITMOTION_DEBUG - DebugName = buffer.DebugName; -#endif - if (buffer.ImmediateBind && buffer.UpdateAction != null) - { - UpdateUnsafe(startValue); - } - } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs index 7012115c..7764ca0d 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs @@ -260,32 +260,6 @@ internal struct MotionData public TValue EndValue; public TOptions Options; - // 新增泛型Initialize方法 - public void Initialize(TweenOption option) - { - Core.Parameters.Duration = option.DurationNanos / AnimationConstants.SecondsToNanos; - Core.Parameters.Delay = option.DelayNanos / AnimationConstants.SecondsToNanos; - Core.Parameters.DelayType = option.DelayType; - Core.Parameters.Ease = option.Ease; - Core.Parameters.Loops = option.Loops; - Core.Parameters.LoopType = option.LoopType; - } - - public TValue GetFirstValue() - where TAdapter : unmanaged, IMotionAdapter - { - return default(TAdapter).Evaluate(ref StartValue,ref EndValue,ref Options, - new() - { - Progress = Core.Parameters.Ease switch - { - Ease.CustomAnimationCurve => Core.Parameters.AnimationCurve.Evaluate(0f), - _ => EaseUtility.Evaluate(0f, Core.Parameters.Ease) - }, - Time = Core.State.Time, - }); - } - public void Update(double time, double deltaTime, out TValue result) where TAdapter : unmanaged, IMotionAdapter { @@ -358,7 +332,7 @@ public void Update(double time, double deltaTime, out TValue result) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Complete(out TValue result) - where TAdapter : unmanaged, IMotionAdapter + where TAdapter : unmanaged, IMotionAdapter { bool isDurationBased = default(TAdapter).IsDurationBased; Core.Complete(out var progress); diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionManager.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionManager.cs index 9d50af3a..e6a5ad01 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionManager.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionManager.cs @@ -10,22 +10,20 @@ internal static class MotionManager public static int MotionTypeCount { get; private set; } - public static void Register( - MotionStorage storage) + public static void Register(MotionStorage storage) where TValue : unmanaged - where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { list.Add(storage); MotionTypeCount++; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref AnimationState GetStateRef(MotionHandle handle, bool checkIsInSequence = true) + public static ref MotionData GetDataRef(MotionHandle handle, bool checkIsInSequence = true) { CheckTypeId(handle); - return ref list[handle.StorageId].GetStateRef(handle, checkIsInSequence); + return ref list[handle.StorageId].GetDataRef(handle, checkIsInSequence); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref MotionData GetTypeDataRef(MotionHandle handle, bool checkIsInSequence = true) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStatus.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStatus.cs index 77e5d8ae..b6a47986 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStatus.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStatus.cs @@ -3,7 +3,7 @@ namespace LitMotion /// /// Motion status. /// - public enum MotionStatus : byte + internal enum MotionStatus : byte { None = 0, Scheduled = 1, diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStorage.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStorage.cs index a6c3a17b..2c252022 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStorage.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStorage.cs @@ -36,11 +36,10 @@ ref MotionData GetTypeDataRef(Mo void Reset(); } - internal sealed class MotionStorage : IMotionStorage + internal sealed class MotionStorage : IMotionStorage where TValue : unmanaged - where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { const int InitialCapacity = 32; @@ -49,7 +48,7 @@ internal sealed class MotionStorage : SparseSetCore sparseSetCore = new(InitialCapacity); SparseIndex[] sparseIndexLookup = new SparseIndex[InitialCapacity]; - TargetBasedAnimation[] unmanagedDataArray = new TargetBasedAnimation[InitialCapacity]; + MotionData[] unmanagedDataArray = new MotionData[InitialCapacity]; ManagedMotionData[] managedDataArray = new ManagedMotionData[InitialCapacity]; AllocatorHelper allocator; int tail; @@ -61,7 +60,7 @@ public MotionStorage(int id) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span> GetDataSpan() + public Span> GetDataSpan() { return unmanagedDataArray.AsSpan(); } @@ -81,27 +80,88 @@ public void EnsureCapacity(int minimumCapacity) ArrayHelper.EnsureCapacity(ref managedDataArray, minimumCapacity); } - public unsafe MotionHandle Create(ref MotionBuilder builder) - where TweenOptions : unmanaged, ITweenOptions - where TTweenAnimationSpec : unmanaged, IVectorizedAnimationSpec + public unsafe MotionHandle Create(ref MotionBuilder builder) { EnsureCapacity(tail + 1); var buffer = builder.buffer; ref var dataRef = ref unmanagedDataArray[tail]; ref var managedDataRef = ref managedDataArray[tail]; - - // 初始化非托管数据 - var options = Unsafe.As(ref buffer.Options); - dataRef.Initialize(options, buffer.StartValue, buffer.EndValue); - - // 初始化托管数据 - dataRef.GetValueFromNanos(0L,out var startValue); - managedDataRef.Initialize(buffer,startValue); + + ref var state = ref dataRef.Core.State; + ref var parameters = ref dataRef.Core.Parameters; + + state.Status = MotionStatus.Scheduled; + state.Time = 0; + state.PlaybackSpeed = 1f; + state.IsPreserved = false; + + parameters.TimeKind = buffer.TimeKind; + parameters.Duration = buffer.Duration; + parameters.Delay = buffer.Delay; + parameters.DelayType = buffer.DelayType; + parameters.Ease = buffer.Ease; + parameters.Loops = buffer.Loops; + parameters.LoopType = buffer.LoopType; + dataRef.StartValue = buffer.StartValue; + dataRef.EndValue = buffer.EndValue; + dataRef.Options = buffer.Options; + + if (buffer.Ease == Ease.CustomAnimationCurve) + { + if (parameters.AnimationCurve.IsCreated) + { + parameters.AnimationCurve.CopyFrom(buffer.AnimationCurve); + } + else + { +#if LITMOTION_COLLECTIONS_2_0_OR_NEWER + parameters.AnimationCurve = new NativeAnimationCurve(buffer.AnimationCurve, allocator.Allocator.Handle); +#else + parameters.AnimationCurve = new UnsafeAnimationCurve(buffer.AnimationCurve, allocator.Allocator.Handle); +#endif + } + } + + managedDataRef.CancelOnError = buffer.CancelOnError; + managedDataRef.SkipValuesDuringDelay = buffer.SkipValuesDuringDelay; + managedDataRef.UpdateAction = buffer.UpdateAction; + managedDataRef.OnLoopCompleteAction = buffer.OnLoopCompleteAction; + managedDataRef.OnCancelAction = buffer.OnCancelAction; + managedDataRef.OnCompleteAction = buffer.OnCompleteAction; + managedDataRef.StateCount = buffer.StateCount; + managedDataRef.State0 = buffer.State0; + managedDataRef.State1 = buffer.State1; + managedDataRef.State2 = buffer.State2; + +#if LITMOTION_DEBUG + managedDataRef.DebugName = buffer.DebugName; +#endif + + if (buffer.ImmediateBind && buffer.UpdateAction != null) + { + managedDataRef.UpdateUnsafe( + default(TAdapter).Evaluate( + ref dataRef.StartValue, + ref dataRef.EndValue, + ref dataRef.Options, + new() + { + Progress = parameters.Ease switch + { + Ease.CustomAnimationCurve => buffer.AnimationCurve.Evaluate(0f), + _ => EaseUtility.Evaluate(0f, parameters.Ease) + }, + Time = state.Time, + } + )); + } + var sparseIndex = sparseSetCore.Alloc(tail); sparseIndexLookup[tail] = sparseIndex; tail++; + return new MotionHandle() { Index = sparseIndex.Index, @@ -156,26 +216,26 @@ public void RemoveAll(NativeList denseIndexList) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe bool IsActive(MotionHandle handle) + public bool IsActive(MotionHandle handle) { ref var slot = ref sparseSetCore.GetSlotRefUnchecked(handle.Index); if (IsDenseIndexOutOfRange(slot.DenseIndex)) return false; if (IsInvalidVersion(slot.Version, handle)) return false; - var state = unmanagedDataArray[slot.DenseIndex].Core.State; - return state->Status is MotionStatus.Scheduled or MotionStatus.Delayed or MotionStatus.Playing || - (state->Status is MotionStatus.Completed && state->IsPreserved); + ref var state = ref unmanagedDataArray[slot.DenseIndex].Core.State; + return state.Status is MotionStatus.Scheduled or MotionStatus.Delayed or MotionStatus.Playing || + (state.Status is MotionStatus.Completed && state.IsPreserved); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe bool IsPlaying(MotionHandle handle) + public bool IsPlaying(MotionHandle handle) { ref var slot = ref sparseSetCore.GetSlotRefUnchecked(handle.Index); if (IsDenseIndexOutOfRange(slot.DenseIndex)) return false; if (IsInvalidVersion(slot.Version, handle)) return false; - var state = unmanagedDataArray[slot.DenseIndex].Core.State; - return state->Status is MotionStatus.Scheduled or MotionStatus.Delayed or MotionStatus.Playing; + ref var state = ref unmanagedDataArray[slot.DenseIndex].Core.State; + return state.Status is MotionStatus.Scheduled or MotionStatus.Delayed or MotionStatus.Playing; } public bool TryCancel(MotionHandle handle, bool checkIsInSequence = true) @@ -199,7 +259,7 @@ public void Cancel(MotionHandle handle, bool checkIsInSequence = true) } } - unsafe int TryCancelCore(MotionHandle handle, bool checkIsInSequence) + int TryCancelCore(MotionHandle handle, bool checkIsInSequence) { ref var slot = ref sparseSetCore.GetSlotRefUnchecked(handle.Index); var denseIndex = slot.DenseIndex; @@ -209,20 +269,20 @@ unsafe int TryCancelCore(MotionHandle handle, bool checkIsInSequence) } ref var dataRef = ref unmanagedDataArray[denseIndex]; - var state = dataRef.Core.State; + ref var state = ref dataRef.Core.State; - if (state->Status is MotionStatus.None or MotionStatus.Canceled || - (state->Status is MotionStatus.Completed && !state->IsPreserved)) + if (state.Status is MotionStatus.None or MotionStatus.Canceled || + (state.Status is MotionStatus.Completed && !state.IsPreserved)) { return 2; } - if (checkIsInSequence && state->IsInSequence) + if (checkIsInSequence && state.IsInSequence) { return 3; } - state->Status = MotionStatus.Canceled; + state.Status = MotionStatus.Canceled; ref var managedData = ref managedDataArray[denseIndex]; managedData.InvokeOnCancel(); @@ -253,7 +313,7 @@ public void Complete(MotionHandle handle, bool checkIsInSequence = true) } } - unsafe int TryCompleteCore(MotionHandle handle, bool checkIsInSequence) + int TryCompleteCore(MotionHandle handle, bool checkIsInSequence) { ref var slot = ref sparseSetCore.GetSlotRefUnchecked(handle.Index); @@ -263,24 +323,25 @@ unsafe int TryCompleteCore(MotionHandle handle, bool checkIsInSequence) } ref var dataRef = ref unmanagedDataArray[slot.DenseIndex]; - var state = dataRef.Core.State; + ref var state = ref dataRef.Core.State; + ref var parameters = ref dataRef.Core.Parameters; - if (state->Status is MotionStatus.None or MotionStatus.Canceled or MotionStatus.Completed) + if (state.Status is MotionStatus.None or MotionStatus.Canceled or MotionStatus.Completed) { return 2; } - if (checkIsInSequence && state->IsInSequence) + if (checkIsInSequence && state.IsInSequence) { return 3; } - if (dataRef.IsInfinite) + if (parameters.Loops < 0) { return 4; } - dataRef.Complete(out var result); + dataRef.Complete(out var result); ref var managedData = ref managedDataArray[slot.DenseIndex]; try @@ -292,9 +353,9 @@ unsafe int TryCompleteCore(MotionHandle handle, bool checkIsInSequence) MotionDispatcher.GetUnhandledExceptionHandler()?.Invoke(ex); } - if (state->WasLoopCompleted) + if (state.WasLoopCompleted) { - managedData.InvokeOnLoopComplete(state->CompletedLoops); + managedData.InvokeOnLoopComplete(state.CompletedLoops); } managedData.InvokeOnComplete(); @@ -312,16 +373,16 @@ public unsafe void SetTime(MotionHandle handle, double time, bool checkIsInSeque var version = slot.Version; if (version <= 0 || version != handle.Version) Error.MotionNotExists(); - fixed (TargetBasedAnimation* arrayPtr = unmanagedDataArray) + fixed (MotionData* arrayPtr = unmanagedDataArray) { var dataPtr = arrayPtr + denseIndex; - var state = dataPtr->Core.State; + ref var state = ref dataPtr->Core.State; - if (checkIsInSequence && state->IsInSequence) Error.MotionIsInSequence(); + if (checkIsInSequence && state.IsInSequence) Error.MotionIsInSequence(); dataPtr->Update(time, time - state.Time, out var result); - var status = state->Status; + var status = state.Status; ref var managedData = ref managedDataArray[denseIndex]; if (status is MotionStatus.Playing or MotionStatus.Completed || (status == MotionStatus.Delayed && !managedData.SkipValuesDuringDelay)) @@ -335,18 +396,18 @@ public unsafe void SetTime(MotionHandle handle, double time, bool checkIsInSeque MotionDispatcher.GetUnhandledExceptionHandler()?.Invoke(ex); if (managedData.CancelOnError) { - state->Status = MotionStatus.Canceled; + state.Status = MotionStatus.Canceled; managedData.OnCancelAction?.Invoke(); return; } } - if (state->WasLoopCompleted) + if (state.WasLoopCompleted) { - managedData.InvokeOnLoopComplete(state->CompletedLoops); + managedData.InvokeOnLoopComplete(state.CompletedLoops); } - if (status is MotionStatus.Completed && state->WasStatusChanged) + if (status is MotionStatus.Completed && state.WasStatusChanged) { managedData.InvokeOnComplete(); } @@ -354,25 +415,24 @@ public unsafe void SetTime(MotionHandle handle, double time, bool checkIsInSeque } } - public unsafe void AddToSequence(MotionHandle handle, out double motionDuration) + public void AddToSequence(MotionHandle handle, out double motionDuration) { ref var slot = ref GetSlotWithVarify(handle, true); ref var dataRef = ref unmanagedDataArray[slot.DenseIndex]; - if (dataRef.Core.State->Status is not MotionStatus.Scheduled) + if (dataRef.Core.State.Status is not MotionStatus.Scheduled) { throw new ArgumentException("Cannot add a running motion to a sequence."); } motionDuration = handle.TotalDuration; - //if (double.IsInfinity(motionDuration)) - if (handle.IsInfinite) + if (double.IsInfinity(motionDuration)) { throw new ArgumentException("Cannot add an infinitely looping motion to a sequence."); } - dataRef.Core.State->IsPreserved = true; - dataRef.Core.State->IsInSequence = true; + dataRef.Core.State.IsPreserved = true; + dataRef.Core.State.IsInSequence = true; } public ref ManagedMotionData GetManagedDataRef(MotionHandle handle, bool checkIsInSequence = true) @@ -395,7 +455,7 @@ public ref MotionData GetTypeDataRef, MotionData>(ref unmanagedDataArray[slot.DenseIndex]); } - public unsafe MotionDebugInfo GetDebugInfo(MotionHandle handle) + public MotionDebugInfo GetDebugInfo(MotionHandle handle) { ref var slot = ref GetSlotWithVarify(handle, false); ref var dataRef = ref unmanagedDataArray[slot.DenseIndex]; @@ -403,25 +463,25 @@ public unsafe MotionDebugInfo GetDebugInfo(MotionHandle handle) return new() { StartValue = dataRef.StartValue, - EndValue = dataRef.TargetValue, - Options = UnsafeUtility.AsRef(dataRef.Core.Options) + EndValue = dataRef.EndValue, + Options = dataRef.Options, }; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - unsafe ref SparseSetCore.Slot GetSlotWithVarify(MotionHandle handle, bool checkIsInSequence = true) + ref SparseSetCore.Slot GetSlotWithVarify(MotionHandle handle, bool checkIsInSequence = true) { ref var slot = ref sparseSetCore.GetSlotRefUnchecked(handle.Index); if (IsDenseIndexOutOfRange(slot.DenseIndex)) Error.MotionNotExists(); ref var dataRef = ref unmanagedDataArray[slot.DenseIndex]; - if (IsInvalidVersion(slot.Version, handle) || dataRef.Core.State->Status == MotionStatus.None) + if (IsInvalidVersion(slot.Version, handle) || dataRef.Core.State.Status == MotionStatus.None) { Error.MotionNotExists(); } - if (checkIsInSequence && dataRef.Core.State->IsInSequence) + if (checkIsInSequence && dataRef.Core.State.IsInSequence) { Error.MotionIsInSequence(); } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/PlayerLoopMotionScheduler.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/PlayerLoopMotionScheduler.cs index 96a9b83a..16af3dc5 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/PlayerLoopMotionScheduler.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/PlayerLoopMotionScheduler.cs @@ -17,11 +17,10 @@ internal PlayerLoopMotionScheduler(PlayerLoopTiming playerLoopTiming, MotionTime this.timeKind = timeKind; } - public MotionHandle Schedule(ref MotionBuilder builder) + public MotionHandle Schedule(ref MotionBuilder builder) where TValue : unmanaged - where VValue : unmanaged - where TOptions : unmanaged, ITweenOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TOptions : unmanaged, IMotionOptions + where TAdapter : unmanaged, IMotionAdapter { builder.buffer.TimeKind = timeKind; diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/UpdateRunner.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/UpdateRunner.cs index 82d55d70..43542343 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/UpdateRunner.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/UpdateRunner.cs @@ -12,13 +12,12 @@ internal interface IUpdateRunner public void Reset(); } - internal sealed class UpdateRunner : IUpdateRunner + internal sealed class UpdateRunner : IUpdateRunner where TValue : unmanaged - where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { - public UpdateRunner(MotionStorage storage, double time, double unscaledTime, double realtime) + public UpdateRunner(MotionStorage storage, double time, double unscaledTime, double realtime) { this.storage = storage; prevTime = time; @@ -26,13 +25,13 @@ public UpdateRunner(MotionStorage stor prevRealtime = realtime; } - readonly MotionStorage storage; + readonly MotionStorage storage; double prevTime; double prevUnscaledTime; double prevRealtime; - public MotionStorage Storage => storage; + public MotionStorage Storage => storage; IMotionStorage IUpdateRunner.Storage => storage; public unsafe void Update(double time, double unscaledTime, double realtime) @@ -48,10 +47,10 @@ public unsafe void Update(double time, double unscaledTime, double realtime) prevUnscaledTime = unscaledTime; prevRealtime = realtime; - fixed (TargetBasedAnimation* dataPtr = storage.GetDataSpan()) + fixed (MotionData* dataPtr = storage.GetDataSpan()) { // update data - var job = new MotionUpdateJob() + var job = new MotionUpdateJob() { DataPtr = dataPtr, DeltaTime = deltaTime, @@ -68,11 +67,11 @@ public unsafe void Update(double time, double unscaledTime, double realtime) for (int i = 0; i < managedDataSpan.Length; i++) { var currentDataPtr = dataPtr + i; - var state = currentDataPtr->Core.State; + ref var state = ref currentDataPtr->Core.State; - if (state->IsInSequence) continue; + if (state.IsInSequence) continue; - var status = state->Status; + var status = state.Status; ref var managedData = ref managedDataSpan[i]; if (status is MotionStatus.Playing or MotionStatus.Completed || (status == MotionStatus.Delayed && !managedData.SkipValuesDuringDelay)) { @@ -85,17 +84,17 @@ public unsafe void Update(double time, double unscaledTime, double realtime) MotionDispatcher.GetUnhandledExceptionHandler()?.Invoke(ex); if (managedData.CancelOnError) { - state->Status = MotionStatus.Canceled; + state.Status = MotionStatus.Canceled; managedData.OnCancelAction?.Invoke(); } } - if (state->WasLoopCompleted) + if (state.WasLoopCompleted) { - managedData.InvokeOnLoopComplete(state->CompletedLoops); + managedData.InvokeOnLoopComplete(state.CompletedLoops); } - if (status is MotionStatus.Completed && state->WasStatusChanged) + if (status is MotionStatus.Completed && state.WasStatusChanged) { managedData.InvokeOnComplete(); } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.FromSettings.cs b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.FromSettings.cs index 52e71f7c..cc604b91 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.FromSettings.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.FromSettings.cs @@ -10,95 +10,100 @@ public static partial class LMotion /// /// Motion settings /// Created motion builder - public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); + public static MotionBuilder Create(MotionSettings settings) => Create(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); + public static MotionBuilder Create(MotionSettings settings) => Create(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); + public static MotionBuilder Create(MotionSettings settings) => Create(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); + public static MotionBuilder Create(MotionSettings settings) => Create(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); + public static MotionBuilder Create(MotionSettings settings) => Create(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); + public static MotionBuilder Create(MotionSettings settings) => Create(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); + public static MotionBuilder Create(MotionSettings settings) => Create(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); + public static MotionBuilder Create(MotionSettings settings) => Create(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); + public static MotionBuilder Create(MotionSettings settings) => Create(settings); /// /// Create a builder for building motion. /// /// Motion settings /// Created motion builder - public static MotionBuilder> Create(MotionSettings settings) => Create>(settings); + public static MotionBuilder Create(MotionSettings settings) => Create(settings); /// /// Create a builder for building motion. /// /// The type of value to animate - /// The type of vectorized value for internal processing /// The type of special parameters given to the motion entity - /// The type of animation specification + /// The type of adapter that support value animation /// Motion settings /// Created motion builder - public static MotionBuilder Create(MotionSettings settings) + public static MotionBuilder Create(MotionSettings settings) where TValue : unmanaged - where VValue : unmanaged - where TOptions : unmanaged, ITweenOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TOptions : unmanaged, IMotionOptions + where TAdapter : unmanaged, IMotionAdapter { var buffer = MotionBuilderBuffer.Rent(); buffer.StartValue = settings.StartValue; buffer.EndValue = settings.EndValue; + buffer.Duration = settings.Duration; buffer.Options = settings.Options; + buffer.Ease = settings.Ease; + buffer.AnimationCurve = settings.CustomEaseCurve; + buffer.Delay = settings.Delay; + buffer.DelayType = settings.DelayType; + buffer.Loops = settings.Loops; + buffer.LoopType = settings.LoopType; buffer.CancelOnError = settings.CancelOnError; buffer.SkipValuesDuringDelay = settings.SkipValuesDuringDelay; buffer.ImmediateBind = settings.ImmediateBind; buffer.Scheduler = settings.Scheduler; - return new MotionBuilder(buffer); + return new MotionBuilder(buffer); } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.cs b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.cs index 6b52d0c9..385eec8f 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Create.cs @@ -15,19 +15,7 @@ public static partial class LMotion /// End value /// Duration /// Created motion builder - public static MotionBuilder> Create(float from, float to, float duration) - { - var options = new TweenOption - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear - }; - return Create>(from, to, options); - } + public static MotionBuilder Create(float from, float to, float duration) => Create(from, to, duration); /// /// Create a builder for building motion. @@ -36,19 +24,7 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder> Create(double from, double to, float duration) - { - var options = new TweenOption - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear - }; - return Create>(from, to, options); - } + public static MotionBuilder Create(double from, double to, float duration) => Create(from, to, duration); /// /// Create a builder for building motion. @@ -57,19 +33,7 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder> Create(int from, int to, float duration) - { - var options = new IntegerOptions - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear - }; - return Create>(from, to, options); - } + public static MotionBuilder Create(int from, int to, float duration) => Create(from, to, duration); /// /// Create a builder for building motion. @@ -78,19 +42,7 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder> Create(long from, long to, float duration) - { - var options = new IntegerOptions - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear - }; - return Create>(from, to, options); - } + public static MotionBuilder Create(long from, long to, float duration) => Create(from, to, duration); /// /// Create a builder for building motion. @@ -99,19 +51,7 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder> Create(Vector2 from, Vector2 to, float duration) - { - var options = new TweenOption - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear - }; - return Create>(from, to, options); - } + public static MotionBuilder Create(Vector2 from, Vector2 to, float duration) => Create(from, to, duration); /// /// Create a builder for building motion. @@ -120,19 +60,7 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder> Create(Vector3 from, Vector3 to, float duration) - { - var options = new TweenOption - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear - }; - return Create>(from, to, options); - } + public static MotionBuilder Create(Vector3 from, Vector3 to, float duration) => Create(from, to, duration); /// /// Create a builder for building motion. @@ -141,19 +69,7 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder> Create(Vector4 from, Vector4 to, float duration) - { - var options = new TweenOption - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear - }; - return Create>(from, to, options); - } + public static MotionBuilder Create(Vector4 from, Vector4 to, float duration) => Create(from, to, duration); /// /// Create a builder for building motion. @@ -162,19 +78,7 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder> Create(Quaternion from, Quaternion to, float duration) - { - var options = new TweenOption - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear - }; - return Create>(from, to, options); - } + public static MotionBuilder Create(Quaternion from, Quaternion to, float duration) => Create(from, to, duration); /// /// Create a builder for building motion. @@ -183,19 +87,7 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder> Create(Color from, Color to, float duration) - { - var options = new TweenOption - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear - }; - return Create>(from, to, options); - } + public static MotionBuilder Create(Color from, Color to, float duration) => Create(from, to, duration); /// /// Create a builder for building motion. @@ -204,56 +96,28 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder> Create(Rect from, Rect to, float duration) - { - var options = new TweenOption - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear - }; - return Create>(from, to, options); - } - + public static MotionBuilder Create(Rect from, Rect to, float duration) => Create(from, to, duration); /// - /// Create a builder for building motion with explicit animation specification. + /// Create a builder for building motion. /// /// The type of value to animate - /// The type of vectorized value for internal processing /// The type of special parameters given to the motion entity - /// The type of animation specification + /// The type of adapter that support value animation /// Start value /// End value - /// Animation options + /// Duration /// Created motion builder - // public static MotionBuilder Create(in TValue from, in TValue to, TOptions options) - // where TValue : unmanaged - // where VValue : unmanaged - // where TOptions : unmanaged, IMotionOptions - // where TAnimationSpec : unmanaged, IVectorizedAnimationSpec - // { - // var buffer = MotionBuilderBuffer.Rent(); - // buffer.StartValue = from; - // buffer.EndValue = to; - // buffer.Options = options; - // return new MotionBuilder(buffer); - // } - - public static MotionBuilder Create(in TValue from, in TValue to, TOptions options) + public static MotionBuilder Create(in TValue from, in TValue to, float duration) where TValue : unmanaged - where VValue : unmanaged - where TOptions : unmanaged, ITweenOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TOptions : unmanaged, IMotionOptions + where TAdapter : unmanaged, IMotionAdapter { var buffer = MotionBuilderBuffer.Rent(); buffer.StartValue = from; buffer.EndValue = to; - buffer.Options = options; - return new MotionBuilder(buffer); + buffer.Duration = duration; + return new MotionBuilder(buffer); } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.CreateString.cs b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.CreateString.cs index e68ce61b..5d7a0b14 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.CreateString.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.CreateString.cs @@ -17,18 +17,9 @@ public static class String /// End value /// Duration /// Created motion builder - public static MotionBuilder> Create32Bytes(in FixedString32Bytes from, in FixedString32Bytes to, float duration) + public static MotionBuilder Create32Bytes(in FixedString32Bytes from, in FixedString32Bytes to, float duration) { - var options = new StringOptions - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear - }; - return Create>(from, to, options); + return Create(from, to, duration); } /// @@ -38,18 +29,9 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder> Create64Bytes(in FixedString64Bytes from, in FixedString64Bytes to, float duration) + public static MotionBuilder Create64Bytes(in FixedString64Bytes from, in FixedString64Bytes to, float duration) { - var options = new StringOptions - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear - }; - return Create>(from, to, options); + return Create(from, to, duration); } /// @@ -59,18 +41,9 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder> Create128Bytes(in FixedString128Bytes from, in FixedString128Bytes to, float duration) + public static MotionBuilder Create128Bytes(in FixedString128Bytes from, in FixedString128Bytes to, float duration) { - var options = new StringOptions - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear - }; - return Create>(from, to, options); + return Create(from, to, duration); } /// @@ -80,18 +53,9 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder> Create512Bytes(in FixedString512Bytes from, in FixedString512Bytes to, float duration) + public static MotionBuilder Create512Bytes(in FixedString512Bytes from, in FixedString512Bytes to, float duration) { - var options = new StringOptions - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear - }; - return Create>(from, to, options); + return Create(from, to, duration); } /// @@ -101,18 +65,9 @@ public static MotionBuilderEnd value /// Duration /// Created motion builder - public static MotionBuilder> Create4096Bytes(in FixedString4096Bytes from, in FixedString4096Bytes to, float duration) + public static MotionBuilder Create4096Bytes(in FixedString4096Bytes from, in FixedString4096Bytes to, float duration) { - var options = new StringOptions - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear - }; - return Create>(from, to, options); + return Create(from, to, duration); } } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Punch.cs b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Punch.cs index ba0ad73b..105e1126 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Punch.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Punch.cs @@ -17,20 +17,10 @@ public static class Punch /// Vibration strength /// Duration /// Created motion builder - public static MotionBuilder> Create(float startValue, float strength, float duration) + public static MotionBuilder Create(float startValue, float strength, float duration) { - var options = new PunchOptions - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear, - Frequency = 10, - DampingRatio = 1f - }; - return Create>(startValue, startValue, options); + return Create(startValue, strength, duration) + .WithOptions(PunchOptions.Default); } /// @@ -40,20 +30,10 @@ public static MotionBuilderVibration strength /// Duration /// Created motion builder - public static MotionBuilder> Create(Vector2 startValue, Vector2 strength, float duration) + public static MotionBuilder Create(Vector2 startValue, Vector2 strength, float duration) { - var options = new PunchOptions - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear, - Frequency = 10, - DampingRatio = 1f - }; - return Create>(startValue, startValue, options); + return Create(startValue, strength, duration) + .WithOptions(PunchOptions.Default); } /// @@ -63,20 +43,10 @@ public static MotionBuilderVibration strength /// Duration /// Created motion builder - public static MotionBuilder> Create(Vector3 startValue, Vector3 strength, float duration) + public static MotionBuilder Create(Vector3 startValue, Vector3 strength, float duration) { - var options = new PunchOptions - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear, - Frequency = 10, - DampingRatio = 1f - }; - return Create>(startValue, startValue, options); + return Create(startValue, strength, duration) + .WithOptions(PunchOptions.Default); } } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Shake.cs b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Shake.cs index b3aac815..0ce44df3 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Shake.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/LMotion.Shake.cs @@ -17,20 +17,10 @@ public static class Shake /// Vibration strength /// Duration /// Created motion builder - public static MotionBuilder> Create(float startValue, float strength, float duration) + public static MotionBuilder Create(float startValue, float strength, float duration) { - var options = new ShakeOptions - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear, - Frequency = 10, - DampingRatio = 1f - }; - return Create>(startValue, startValue, options); + return Create(startValue, strength, duration) + .WithOptions(ShakeOptions.Default); } /// @@ -40,20 +30,10 @@ public static MotionBuilderVibration strength /// Duration /// Created motion builder - public static MotionBuilder> Create(Vector2 startValue, Vector2 strength, float duration) + public static MotionBuilder Create(Vector2 startValue, Vector2 strength, float duration) { - var options = new ShakeOptions - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear, - Frequency = 10, - DampingRatio = 1f - }; - return Create>(startValue, startValue, options); + return Create(startValue, strength, duration) + .WithOptions(ShakeOptions.Default); } /// @@ -63,20 +43,10 @@ public static MotionBuilderVibration strength /// Duration /// Created motion builder - public static MotionBuilder> Create(Vector3 startValue, Vector3 strength, float duration) + public static MotionBuilder Create(Vector3 startValue, Vector3 strength, float duration) { - var options = new ShakeOptions - { - DurationNanos = (long)(duration * AnimationConstants.SecondsToNanos), - Loops = 1, - DelayNanos = 0, - DelayType = DelayType.FirstLoop, - LoopType = LoopType.Restart, - Ease = Ease.Linear, - Frequency = 10, - DampingRatio = 1f - }; - return Create>(startValue, startValue, options); + return Create(startValue, strength, duration) + .WithOptions(ShakeOptions.Default); } } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/ManualMotionDispatcher.cs b/src/LitMotion/Assets/LitMotion/Runtime/ManualMotionDispatcher.cs index c207ab07..e7708667 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/ManualMotionDispatcher.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/ManualMotionDispatcher.cs @@ -12,13 +12,12 @@ public ManualMotionDispatcherScheduler(ManualMotionDispatcher dispatcher) this.dispatcher = dispatcher; } - public MotionHandle Schedule(ref MotionBuilder builder) + public MotionHandle Schedule(ref MotionBuilder builder) where TValue : unmanaged - where VValue : unmanaged - where TOptions : unmanaged, ITweenOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TOptions : unmanaged, IMotionOptions + where TAdapter : unmanaged, IMotionAdapter { - return dispatcher.GetOrCreateRunner().Storage.Create(ref builder); + return dispatcher.GetOrCreateRunner().Storage.Create(ref builder); } } @@ -63,14 +62,13 @@ public double Time /// Ensures the storage capacity until it reaches at least capacity. /// /// The minimum capacity to ensure - public void EnsureStorageCapacity(int capacity) + public void EnsureStorageCapacity(int capacity) where TValue : unmanaged - where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { - GetOrCreateRunner().Storage.EnsureCapacity(capacity); + GetOrCreateRunner().Storage.EnsureCapacity(capacity); } /// @@ -100,23 +98,22 @@ public void Reset() time = 0; } - internal UpdateRunner GetOrCreateRunner() + internal UpdateRunner GetOrCreateRunner() where TValue : unmanaged - where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { - var key = typeof((TValue, TOptions, TAnimationSpec)); + var key = typeof((TValue, TOptions, TAdapter)); if (!runners.TryGetValue(key, out var runner)) { - var storage = new MotionStorage(MotionManager.MotionTypeCount); + var storage = new MotionStorage(MotionManager.MotionTypeCount); MotionManager.Register(storage); - runner = new UpdateRunner(storage, 0, 0, 0); + runner = new UpdateRunner(storage, 0, 0, 0); runners.Add(key, runner); } - return (UpdateRunner)runner; + return (UpdateRunner)runner; } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilder.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilder.cs index c58f7152..2cc31b7c 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilder.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilder.cs @@ -5,8 +5,6 @@ using System; using System.Runtime.CompilerServices; using UnityEngine; -using Unity.Collections; -using LitMotion.Collections; namespace LitMotion { @@ -41,7 +39,13 @@ public static void Return(MotionBuilderBuffer buffer) buffer.EndValue = default; buffer.Options = default; + buffer.Duration = default; + buffer.Ease = default; + buffer.AnimationCurve = default; buffer.TimeKind = default; + buffer.Delay = default; + buffer.Loops = 1; + buffer.LoopType = default; buffer.State0 = default; buffer.State1 = default; @@ -74,7 +78,13 @@ public static void Return(MotionBuilderBuffer buffer) public TValue StartValue; public TValue EndValue; public TOptions Options; + public float Duration; + public Ease Ease; public MotionTimeKind TimeKind; + public float Delay; + public int Loops = 1; + public DelayType DelayType; + public LoopType LoopType; public bool CancelOnError; public bool SkipValuesDuringDelay; public bool ImmediateBind = true; @@ -87,24 +97,24 @@ public static void Return(MotionBuilderBuffer buffer) public Action OnLoopCompleteAction; public Action OnCompleteAction; public Action OnCancelAction; + public AnimationCurve AnimationCurve; public IMotionScheduler Scheduler; #if LITMOTION_DEBUG public string DebugName; #endif } + /// /// Supports construction, scheduling, and binding of motion entities. /// /// The type of value to animate - /// The type of vectorized value for internal processing /// The type of special parameters given to the motion data - /// The type of animation specification - public struct MotionBuilder : IDisposable + /// The type of adapter that support value animation + public struct MotionBuilder : IDisposable where TValue : unmanaged - where VValue : unmanaged - where TOptions : unmanaged,ITweenOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TOptions : unmanaged, IMotionOptions + where TAdapter : unmanaged, IMotionAdapter { internal MotionBuilder(MotionBuilderBuffer buffer) { @@ -121,11 +131,11 @@ internal MotionBuilder(MotionBuilderBuffer buffer) /// The type of easing /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithEase(Ease ease) + public readonly MotionBuilder WithEase(Ease ease) { CheckEaseType(ease); CheckBuffer(); - buffer.Options.Ease = ease; + buffer.Ease = ease; return this; } @@ -135,15 +145,11 @@ public readonly MotionBuilder WithEase /// Animation curve /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithEase(AnimationCurve animationCurve) + public readonly MotionBuilder WithEase(AnimationCurve animationCurve) { CheckBuffer(); -#if LITMOTION_COLLECTIONS_2_0_OR_NEWER - buffer.Options.AnimationCurve = new NativeAnimationCurve(animationCurve, MotionDispatcher.Allocator.Allocator.Handle); -#else - buffer.Options.AnimationCurve = new UnsafeAnimationCurve(buffer.AnimationCurve, MotionDispatcher.Allocator.Allocator.Handle); -#endif - buffer.Options.Ease = Ease.CustomAnimationCurve; + buffer.AnimationCurve = animationCurve; + buffer.Ease = Ease.CustomAnimationCurve; return this; } @@ -155,11 +161,11 @@ public readonly MotionBuilder WithEase /// Whether to skip updating values during the delay time /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithDelay(float delay, DelayType delayType = DelayType.FirstLoop, bool skipValuesDuringDelay = true) + public readonly MotionBuilder WithDelay(float delay, DelayType delayType = DelayType.FirstLoop, bool skipValuesDuringDelay = true) { CheckBuffer(); - buffer.Options.DelayNanos = (long)(delay * 1_000_000_000); // 转换为纳秒 - buffer.Options.DelayType = delayType; + buffer.Delay = delay; + buffer.DelayType = delayType; buffer.SkipValuesDuringDelay = skipValuesDuringDelay; return this; } @@ -171,11 +177,11 @@ public readonly MotionBuilder WithDela /// Behavior at the end of each loop /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithLoops(int loops, LoopType loopType = LoopType.Restart) + public readonly MotionBuilder WithLoops(int loops, LoopType loopType = LoopType.Restart) { CheckBuffer(); - buffer.Options.Loops = loops; - buffer.Options.LoopType = loopType; + buffer.Loops = loops; + buffer.LoopType = loopType; return this; } @@ -185,7 +191,7 @@ public readonly MotionBuilder WithLoop /// Option value to specify /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithOptions(TOptions options) + public readonly MotionBuilder WithOptions(TOptions options) { CheckBuffer(); buffer.Options = options; @@ -198,7 +204,7 @@ public readonly MotionBuilder WithOpti /// Callback when canceled /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithOnCancel(Action callback) + public readonly MotionBuilder WithOnCancel(Action callback) { CheckBuffer(); buffer.OnCancelAction += callback; @@ -211,7 +217,7 @@ public readonly MotionBuilder WithOnCa /// Callback when playback ends /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithOnComplete(Action callback) + public readonly MotionBuilder WithOnComplete(Action callback) { CheckBuffer(); buffer.OnCompleteAction += callback; @@ -224,7 +230,7 @@ public readonly MotionBuilder WithOnCo /// Callback to be performed when each loop finishes. /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithOnLoopComplete(Action callback) + public readonly MotionBuilder WithOnLoopComplete(Action callback) { CheckBuffer(); buffer.OnLoopCompleteAction += callback; @@ -237,7 +243,7 @@ public readonly MotionBuilder WithOnLo /// Whether to cancel on error /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithCancelOnError(bool cancelOnError = true) + public readonly MotionBuilder WithCancelOnError(bool cancelOnError = true) { CheckBuffer(); buffer.CancelOnError = cancelOnError; @@ -250,7 +256,7 @@ public readonly MotionBuilder WithCanc /// Whether to bind on sheduling /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithImmediateBind(bool immediateBind = true) + public readonly MotionBuilder WithImmediateBind(bool immediateBind = true) { CheckBuffer(); buffer.ImmediateBind = immediateBind; @@ -263,7 +269,7 @@ public readonly MotionBuilder WithImme /// Scheduler /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithScheduler(IMotionScheduler scheduler) + public readonly MotionBuilder WithScheduler(IMotionScheduler scheduler) { CheckBuffer(); buffer.Scheduler = scheduler; @@ -276,7 +282,7 @@ public readonly MotionBuilder WithSche /// Debug name /// This builder to allow chaining multiple method calls. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly MotionBuilder WithDebugName(string debugName) + public readonly MotionBuilder WithDebugName(string debugName) { #if LITMOTION_DEBUG CheckBuffer(); @@ -378,7 +384,14 @@ public readonly MotionSettings ToMotionSettings() { StartValue = buffer.StartValue, EndValue = buffer.EndValue, + Duration = buffer.Duration, Options = buffer.Options, + Ease = buffer.Ease, + CustomEaseCurve = buffer.AnimationCurve, + Delay = buffer.Delay, + DelayType = buffer.DelayType, + Loops = buffer.Loops, + LoopType = buffer.LoopType, CancelOnError = buffer.CancelOnError, SkipValuesDuringDelay = buffer.SkipValuesDuringDelay, ImmediateBind = buffer.ImmediateBind, @@ -396,12 +409,11 @@ internal MotionHandle ScheduleMotion() #if UNITY_EDITOR if (!UnityEditor.EditorApplication.isPlaying) { - // Use default scheduler interface to avoid generic parameter inference issues - handle = MotionScheduler.DefaultScheduler.Schedule(ref this); + handle = EditorMotionDispatcher.Schedule(ref this); } else if (MotionScheduler.DefaultScheduler == MotionScheduler.Update) // avoid virtual method call { - handle = MotionScheduler.Update.Schedule(ref this); + handle = MotionDispatcher.Schedule(ref this, PlayerLoopTiming.Update); } else { @@ -410,7 +422,7 @@ internal MotionHandle ScheduleMotion() #else if (MotionScheduler.DefaultScheduler == MotionScheduler.Update) // avoid virtual method call { - handle = MotionScheduler.Update.Schedule(ref this); + handle = MotionDispatcher.Schedule(ref this, PlayerLoopTiming.Update); } else { diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilderExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilderExtensions.cs index 8b91d00e..e93a0d60 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilderExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilderExtensions.cs @@ -15,11 +15,10 @@ public static class MotionBuilderExtensions /// Motion state /// Action that handles binding /// Handle of the created motion data. - public unsafe static MotionHandle Bind(this MotionBuilder builder, TState state, Action action) + public unsafe static MotionHandle Bind(this MotionBuilder builder, TState state, Action action) where TValue : unmanaged - where VValue : unmanaged - where TOptions : unmanaged, ITweenOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TOptions : unmanaged, IMotionOptions + where TAdapter : unmanaged, IMotionAdapter where TState : struct { return builder.Bind(Box.Create(state), action, (value, state, action) => action(value, state.Value)); @@ -29,15 +28,13 @@ public unsafe static MotionHandle Bind /// The type of value to animate - /// The type of vectorized value for internal processing - /// The type of animation specification + /// The type of adapter that support value animation /// This builder /// Rounding mode /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithRoundingMode(this MotionBuilder builder, RoundingMode roundingMode) + public static MotionBuilder WithRoundingMode(this MotionBuilder builder, RoundingMode roundingMode) where TValue : unmanaged - where VValue : unmanaged - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { var options = builder.buffer.Options; options.RoundingMode = roundingMode; @@ -49,15 +46,13 @@ public static MotionBuilder With /// Specify the frequency of vibration. /// /// The type of value to animate - /// The type of vectorized value for internal processing - /// The type of animation specification + /// The type of adapter that support value animation /// This builder /// Frequency /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithFrequency(this MotionBuilder builder, int frequency) + public static MotionBuilder WithFrequency(this MotionBuilder builder, int frequency) where TValue : unmanaged - where VValue : unmanaged - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { var options = builder.buffer.Options; options.Frequency = frequency; @@ -69,15 +64,13 @@ public static MotionBuilder WithFr /// Specify the vibration damping ratio. /// /// The type of value to animate - /// The type of vectorized value for internal processing - /// The type of animation specification + /// The type of adapter that support value animation /// This builder /// Damping ratio /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithDampingRatio(this MotionBuilder builder, float dampingRatio) + public static MotionBuilder WithDampingRatio(this MotionBuilder builder, float dampingRatio) where TValue : unmanaged - where VValue : unmanaged - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { var options = builder.buffer.Options; options.DampingRatio = dampingRatio; @@ -89,15 +82,13 @@ public static MotionBuilder WithDa /// Specify the frequency of vibration. /// /// The type of value to animate - /// The type of vectorized value for internal processing - /// The type of animation specification + /// The type of adapter that support value animation /// This builder /// Frequency /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithFrequency(this MotionBuilder builder, int frequency) + public static MotionBuilder WithFrequency(this MotionBuilder builder, int frequency) where TValue : unmanaged - where VValue : unmanaged - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { var options = builder.buffer.Options; options.Frequency = frequency; @@ -109,15 +100,13 @@ public static MotionBuilder WithFr /// Specify the vibration damping ratio. /// /// The type of value to animate - /// The type of vectorized value for internal processing - /// The type of animation specification + /// The type of adapter that support value animation /// This builder /// Damping ratio /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithDampingRatio(this MotionBuilder builder, float dampingRatio) + public static MotionBuilder WithDampingRatio(this MotionBuilder builder, float dampingRatio) where TValue : unmanaged - where VValue : unmanaged - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { var options = builder.buffer.Options; options.DampingRatio = dampingRatio; @@ -129,15 +118,13 @@ public static MotionBuilder WithDa /// Specify the random number seed that determines the shake motion value. /// /// The type of value to animate - /// The type of vectorized value for internal processing - /// The type of animation specification + /// The type of adapter that support value animation /// This builder /// Random number seed /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithRandomSeed(this MotionBuilder builder, uint seed) + public static MotionBuilder WithRandomSeed(this MotionBuilder builder, uint seed) where TValue : unmanaged - where VValue : unmanaged - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { var options = builder.buffer.Options; options.RandomSeed = seed; @@ -149,15 +136,13 @@ public static MotionBuilder WithRa /// Enable support for Rich Text tags. /// /// The type of value to animate - /// The type of vectorized value for internal processing - /// The type of animation specification + /// The type of adapter that support value animation /// This builder /// Whether to support Rich Text tags /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithRichText(this MotionBuilder builder, bool richTextEnabled = true) + public static MotionBuilder WithRichText(this MotionBuilder builder, bool richTextEnabled = true) where TValue : unmanaged - where VValue : unmanaged - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { var options = builder.buffer.Options; options.RichTextEnabled = richTextEnabled; @@ -169,15 +154,13 @@ public static MotionBuilder WithR /// Specify the random number seed used to display scramble characters. /// /// The type of value to animate - /// The type of vectorized value for internal processing - /// The type of animation specification + /// The type of adapter that support value animation /// This builder /// Rrandom number seed /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithRandomSeed(this MotionBuilder builder, uint seed) + public static MotionBuilder WithRandomSeed(this MotionBuilder builder, uint seed) where TValue : unmanaged - where VValue : unmanaged - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { var options = builder.buffer.Options; options.RandomSeed = seed; @@ -189,15 +172,13 @@ public static MotionBuilder WithR /// Fill in the parts that are not yet displayed with random strings. /// /// The type of value to animate - /// The type of vectorized value for internal processing - /// The type of animation specification + /// The type of adapter that support value animation /// This builder /// Type of characters used for blank padding /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithScrambleChars(this MotionBuilder builder, ScrambleMode scrambleMode) + public static MotionBuilder WithScrambleChars(this MotionBuilder builder, ScrambleMode scrambleMode) where TValue : unmanaged - where VValue : unmanaged - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { if (scrambleMode == ScrambleMode.Custom) throw new ArgumentException("ScrambleMode.Custom cannot be specified explicitly. Use WithScrambleMode(FixedString64Bytes) instead."); @@ -212,15 +193,13 @@ public static MotionBuilder WithS /// Fill in the parts that are not yet displayed with random strings. /// /// The type of value to animate - /// The type of vectorized value for internal processing - /// The type of animation specification + /// The type of adapter that support value animation /// This builder /// Characters used for blank padding /// This builder to allow chaining multiple method calls. - public static MotionBuilder WithScrambleChars(this MotionBuilder builder, FixedString64Bytes customScrambleChars) + public static MotionBuilder WithScrambleChars(this MotionBuilder builder, FixedString64Bytes customScrambleChars) where TValue : unmanaged - where VValue : unmanaged - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { var options = builder.buffer.Options; options.ScrambleMode = ScrambleMode.Custom; diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionDebugger.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionDebugger.cs index 19ecdf7c..75717d4d 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionDebugger.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionDebugger.cs @@ -84,7 +84,7 @@ void OnComplete() MotionDispatcher.GetUnhandledExceptionHandler()?.Invoke(ex); } - if (Handle.IsActive() && !MotionManager.GetStateRef(Handle, false).IsPreserved) + if (Handle.IsActive() && !MotionManager.GetDataRef(Handle, false).State.IsPreserved) { Release(); } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionDispatcher.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionDispatcher.cs index 88cfd17b..0fb2723d 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionDispatcher.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionDispatcher.cs @@ -14,22 +14,21 @@ namespace LitMotion /// public static class MotionDispatcher { - static class StorageCache + static class StorageCache where TValue : unmanaged - where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { - public static MotionStorage initialization; - public static MotionStorage earlyUpdate; - public static MotionStorage fixedUpdate; - public static MotionStorage preUpdate; - public static MotionStorage update; - public static MotionStorage preLateUpdate; - public static MotionStorage postLateUpdate; - public static MotionStorage timeUpdate; + public static MotionStorage initialization; + public static MotionStorage earlyUpdate; + public static MotionStorage fixedUpdate; + public static MotionStorage preUpdate; + public static MotionStorage update; + public static MotionStorage preLateUpdate; + public static MotionStorage postLateUpdate; + public static MotionStorage timeUpdate; - public static MotionStorage GetOrCreate(PlayerLoopTiming playerLoopTiming) + public static MotionStorage GetOrCreate(PlayerLoopTiming playerLoopTiming) { return playerLoopTiming switch { @@ -46,33 +45,32 @@ public static MotionStorage GetOrCreat } [MethodImpl(MethodImplOptions.AggressiveInlining)] - static MotionStorage CreateIfNull(ref MotionStorage storage) + static MotionStorage CreateIfNull(ref MotionStorage storage) { if (storage == null) { - storage = new MotionStorage(MotionManager.MotionTypeCount); + storage = new MotionStorage(MotionManager.MotionTypeCount); MotionManager.Register(storage); } return storage; } } - static class RunnerCache + static class RunnerCache where TValue : unmanaged - where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { - public static UpdateRunner initialization; - public static UpdateRunner earlyUpdate; - public static UpdateRunner fixedUpdate; - public static UpdateRunner preUpdate; - public static UpdateRunner update; - public static UpdateRunner preLateUpdate; - public static UpdateRunner postLateUpdate; - public static UpdateRunner timeUpdate; + public static UpdateRunner initialization; + public static UpdateRunner earlyUpdate; + public static UpdateRunner fixedUpdate; + public static UpdateRunner preUpdate; + public static UpdateRunner update; + public static UpdateRunner preLateUpdate; + public static UpdateRunner postLateUpdate; + public static UpdateRunner timeUpdate; - public static (UpdateRunner runner, bool isCreated) GetOrCreate(PlayerLoopTiming playerLoopTiming, MotionStorage storage) + public static (UpdateRunner runner, bool isCreated) GetOrCreate(PlayerLoopTiming playerLoopTiming, MotionStorage storage) { return playerLoopTiming switch { @@ -89,17 +87,17 @@ public static (UpdateRunner runner, bo } [MethodImpl(MethodImplOptions.AggressiveInlining)] - static (UpdateRunner, bool) CreateIfNull(PlayerLoopTiming playerLoopTiming, ref UpdateRunner runner, MotionStorage storage) + static (UpdateRunner, bool) CreateIfNull(PlayerLoopTiming playerLoopTiming, ref UpdateRunner runner, MotionStorage storage) { if (runner == null) { if (playerLoopTiming == PlayerLoopTiming.FixedUpdate) { - runner = new UpdateRunner(storage, Time.fixedTimeAsDouble, Time.fixedUnscaledTimeAsDouble, Time.realtimeSinceStartupAsDouble); + runner = new UpdateRunner(storage, Time.fixedTimeAsDouble, Time.fixedUnscaledTimeAsDouble, Time.realtimeSinceStartupAsDouble); } else { - runner = new UpdateRunner(storage, Time.timeAsDouble, Time.unscaledTimeAsDouble, Time.realtimeSinceStartupAsDouble); + runner = new UpdateRunner(storage, Time.timeAsDouble, Time.unscaledTimeAsDouble, Time.realtimeSinceStartupAsDouble); } GetRunnerList(playerLoopTiming).Add(runner); return (runner, true); @@ -149,23 +147,6 @@ static ref FastListCore GetRunnerList(PlayerLoopTiming playerLoop static Action unhandledException = DefaultUnhandledExceptionHandler; static readonly PlayerLoopTiming[] playerLoopTimings = (PlayerLoopTiming[])Enum.GetValues(typeof(PlayerLoopTiming)); - static Unity.Collections.AllocatorHelper allocator; - - static bool isCreatedAllocator = false; - - public static Unity.Collections.AllocatorHelper Allocator - { - get - { - if (!isCreatedAllocator) - { - allocator = RewindableAllocatorFactory.CreateAllocator(); - isCreatedAllocator = true; - } - return allocator; - } - } - [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void Init() { @@ -206,40 +187,33 @@ public static void Clear() span[i].Reset(); } } - if (isCreatedAllocator) - { - allocator.Allocator.Rewind(); - isCreatedAllocator = false; - } } /// /// Ensures the storage capacity until it reaches at least `capacity`. /// /// The minimum capacity to ensure. - public static void EnsureStorageCapacity(int capacity) + public static void EnsureStorageCapacity(int capacity) where TValue : unmanaged - where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { foreach (var playerLoopTiming in playerLoopTimings) { - StorageCache.GetOrCreate(playerLoopTiming).EnsureCapacity(capacity); + StorageCache.GetOrCreate(playerLoopTiming).EnsureCapacity(capacity); } #if UNITY_EDITOR - EditorMotionDispatcher.EnsureStorageCapacity(capacity); + EditorMotionDispatcher.EnsureStorageCapacity(capacity); #endif } - internal static MotionHandle Schedule(ref MotionBuilder builder, PlayerLoopTiming playerLoopTiming) + internal static MotionHandle Schedule(ref MotionBuilder builder, PlayerLoopTiming playerLoopTiming) where TValue : unmanaged - where VValue : unmanaged - where TOptions : unmanaged, ITweenOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TOptions : unmanaged, IMotionOptions + where TAdapter : unmanaged, IMotionAdapter { - var storage = StorageCache.GetOrCreate(playerLoopTiming); - RunnerCache.GetOrCreate(playerLoopTiming, storage); + var storage = StorageCache.GetOrCreate(playerLoopTiming); + RunnerCache.GetOrCreate(playerLoopTiming, storage); return storage.Create(ref builder); } @@ -263,20 +237,19 @@ internal static void Update(PlayerLoopTiming playerLoopTiming) #if UNITY_EDITOR internal static class EditorMotionDispatcher { - static class Cache + static class Cache where TValue : unmanaged - where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { - static MotionStorage storage; - static UpdateRunner updateRunner; + static MotionStorage storage; + static UpdateRunner updateRunner; - public static MotionStorage GetOrCreateStorage() + public static MotionStorage GetOrCreateStorage() { if (storage == null) { - storage = new MotionStorage(MotionManager.MotionTypeCount); + storage = new MotionStorage(MotionManager.MotionTypeCount); MotionManager.Register(storage); } return storage; @@ -287,7 +260,7 @@ public static void InitUpdateRunner() if (updateRunner == null) { var time = EditorApplication.timeSinceStartup; - updateRunner = new UpdateRunner(storage, time, time, time); + updateRunner = new UpdateRunner(storage, time, time, time); updateRunners.Add(updateRunner); } } @@ -295,24 +268,22 @@ public static void InitUpdateRunner() static FastListCore updateRunners; - public static MotionHandle Schedule(ref MotionBuilder builder) + public static MotionHandle Schedule(ref MotionBuilder builder) where TValue : unmanaged - where VValue : unmanaged - where TOptions : unmanaged, ITweenOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TOptions : unmanaged, IMotionOptions + where TAdapter : unmanaged, IMotionAdapter { - var storage = Cache.GetOrCreateStorage(); - Cache.InitUpdateRunner(); + var storage = Cache.GetOrCreateStorage(); + Cache.InitUpdateRunner(); return storage.Create(ref builder); } - public static void EnsureStorageCapacity(int capacity) + public static void EnsureStorageCapacity(int capacity) where TValue : unmanaged - where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { - Cache.GetOrCreateStorage().EnsureCapacity(capacity); + Cache.GetOrCreateStorage().EnsureCapacity(capacity); } [InitializeOnLoadMethod] diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs index 10d07030..04592721 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionHandle.cs @@ -34,45 +34,36 @@ public readonly double Time { get { - return MotionManager.GetStateRef(this, false).Time; + return MotionManager.GetDataRef(this, false).State.Time; } set { MotionManager.SetTime(this, value); } } - //todo - public readonly bool IsInfinite + + /// + /// The delay of the motion + /// + public readonly float Delay + { + get + { + return MotionManager.GetDataRef(this, false).Parameters.Delay; + } + } + + /// + /// The duration of the motion + /// + public readonly float Duration { get { - //return MotionManager.GetDataRef(this, false).IsInfinite; - return false; + return MotionManager.GetDataRef(this, false).Parameters.Duration; } } - //todo - // /// - // /// The delay of the motion - // /// - // public readonly float Delay - // { - // get - // { - // return MotionManager.GetDataRef(this, false).Parameters.Delay; - // } - // } - //todo - // /// - // /// The duration of the motion - // /// - // public readonly float Duration - // { - // get - // { - // return MotionManager.GetDataRef(this, false).Parameters.Duration; - // } - // } - //todo + /// /// The total duration of the motion /// @@ -80,21 +71,20 @@ public readonly double TotalDuration { get { - //return MotionManager.GetDataRef(this, false).GetDuration(); - return 1; + return MotionManager.GetDataRef(this, false).Parameters.TotalDuration; + } + } + + /// + /// The number of loops + /// + public readonly int Loops + { + get + { + return MotionManager.GetDataRef(this, false).Parameters.Loops; } } - //todo - // /// - // /// The number of loops - // /// - // public readonly int Loops - // { - // get - // { - // return MotionManager.GetDataRef(this, false).Parameters.Loops; - // } - // } /// /// The number of loops completed @@ -103,7 +93,7 @@ public readonly int CompletedLoops { get { - return MotionManager.GetStateRef(this).CompletedLoops; + return MotionManager.GetDataRef(this).State.CompletedLoops; } } @@ -114,11 +104,11 @@ public readonly float PlaybackSpeed { get { - return MotionManager.GetStateRef(this).PlaybackSpeed; + return MotionManager.GetDataRef(this).State.PlaybackSpeed; } set { - MotionManager.GetStateRef(this).PlaybackSpeed = value; + MotionManager.GetDataRef(this).State.PlaybackSpeed = value; } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionHandleExtensions.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionHandleExtensions.cs index 57c45102..6fd8d632 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionHandleExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionHandleExtensions.cs @@ -62,7 +62,7 @@ public static string GetDebugName(this MotionHandle handle) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static MotionHandle Preserve(this MotionHandle handle) { - MotionManager.GetStateRef(handle).IsPreserved = true; + MotionManager.GetDataRef(handle).State.IsPreserved = true; return handle; } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceBuilder.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceBuilder.cs index 69cfc32b..e4afd2ee 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceBuilder.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceBuilder.cs @@ -76,7 +76,7 @@ public void WithEase(Ease ease) this.ease = ease; } - public MotionHandle Schedule(Action>> configuration) + public MotionHandle Schedule(Action> configuration) { var source = MotionSequenceSource.Rent(); var builder = LMotion.Create(0.0, duration, (float)duration) @@ -170,7 +170,7 @@ public MotionHandle Run() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public MotionHandle Run(Action>> configuration) + public MotionHandle Run(Action> configuration) { CheckIsDisposed(); var handle = source.Schedule(configuration); diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceSource.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceSource.cs index 0cad4e6f..022d0bfd 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceSource.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionSequenceSource.cs @@ -109,7 +109,7 @@ public double Time void OnComplete() { if (!handle.IsActive()) return; - if (MotionManager.GetStateRef(handle, false).IsPreserved) return; + if (MotionManager.GetDataRef(handle, false).State.IsPreserved) return; Return(this); } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs index 81ab0d1e..4cbb0725 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs @@ -9,18 +9,16 @@ namespace LitMotion /// /// A job that updates the status of the motion data and outputs the current value. /// - /// The type of value to animate (user-facing) - /// The type of vectorized value for internal processing + /// The type of value to animate /// The type of special parameters given to the motion data - /// The type of vectorized animation specification + /// The type of adapter that support value animation [BurstCompile] - public unsafe struct MotionUpdateJob : IJobParallelFor + public unsafe struct MotionUpdateJob : IJobParallelFor where TValue : unmanaged - where VValue : unmanaged where TOptions : unmanaged, IMotionOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TAdapter : unmanaged, IMotionAdapter { - [NativeDisableUnsafePtrRestriction] internal TargetBasedAnimation* DataPtr; + [NativeDisableUnsafePtrRestriction] internal MotionData* DataPtr; [ReadOnly] public double DeltaTime; [ReadOnly] public double UnscaledDeltaTime; [ReadOnly] public double RealDeltaTime; @@ -28,19 +26,18 @@ public unsafe struct MotionUpdateJob : [WriteOnly] public NativeList.ParallelWriter CompletedIndexList; [WriteOnly] public NativeArray Output; - [WriteOnly] public NativeArray OutputVelocity; - public void Execute([AssumeRange(0, int.MaxValue)] int index) { var ptr = DataPtr + index; - var state = ptr->Core.State; + ref var state = ref ptr->Core.State; + ref var parameters = ref ptr->Core.Parameters; - if (Hint.Likely(state->Status is MotionStatus.Scheduled or MotionStatus.Delayed or MotionStatus.Playing) || - Hint.Unlikely(state->IsPreserved && state->Status is MotionStatus.Completed)) + if (Hint.Likely(state.Status is MotionStatus.Scheduled or MotionStatus.Delayed or MotionStatus.Playing) || + Hint.Unlikely(state.IsPreserved && state.Status is MotionStatus.Completed)) { - if (Hint.Unlikely(state->IsInSequence)) return; + if (Hint.Unlikely(state.IsInSequence)) return; - var deltaTime = ptr->Core.TimeKind switch + var deltaTime = parameters.TimeKind switch { MotionTimeKind.Time => DeltaTime, MotionTimeKind.UnscaledTime => UnscaledDeltaTime, @@ -51,13 +48,11 @@ public void Execute([AssumeRange(0, int.MaxValue)] int index) var time = state.Time + deltaTime; ptr->Update(time, deltaTime, out var result); Output[index] = result; - ptr->GetVelocityVectorFromNanos(time,out var velocity); - OutputVelocity[index] = velocity; } - else if ((!state->IsPreserved && state->Status is MotionStatus.Completed) || state->Status is MotionStatus.Canceled) + else if ((!state.IsPreserved && state.Status is MotionStatus.Completed) || state.Status is MotionStatus.Canceled) { CompletedIndexList.AddNoResize(index); - state->Status = MotionStatus.Disposed; + state.Status = MotionStatus.Disposed; } } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/ITweenOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/ITweenOptions.cs deleted file mode 100644 index dd642e2f..00000000 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/ITweenOptions.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using LitMotion.Collections; - -namespace LitMotion -{ - /// - /// Interface for tween animation options that provides common properties for all tween-based animations. - /// - public interface ITweenOptions : IMotionOptions - { - /// - /// Duration of the animation in nanoseconds. - /// - long DurationNanos { get; set; } - - /// - /// Number of loops. Use -1 for infinite loops. - /// - int Loops { get; set; } - - /// - /// Delay before the animation starts in nanoseconds. - /// - long DelayNanos { get; set; } - - /// - /// Type of delay behavior. - /// - DelayType DelayType { get; set; } - - /// - /// Type of loop behavior. - /// - LoopType LoopType { get; set; } - - /// - /// Easing function for the animation. - /// - Ease Ease { get; set; } - - /// - /// Custom animation curve for the easing. - /// - #if LITMOTION_COLLECTIONS_2_0_OR_NEWER - NativeAnimationCurve AnimationCurve { get; set; } - #else - UnsafeAnimationCurve AnimationCurve { get; set; } - #endif - } -} \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/IntegerOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/IntegerOptions.cs index c575aecb..12b79b87 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/IntegerOptions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/IntegerOptions.cs @@ -1,5 +1,4 @@ using System; -using LitMotion.Collections; namespace LitMotion { @@ -7,67 +6,13 @@ namespace LitMotion /// Options for integer type motion. /// [Serializable] - public struct IntegerOptions : ITweenOptions, IEquatable + public struct IntegerOptions : IMotionOptions, IEquatable { - private TweenOption tweenOptions; - - // IntegerOptions特有的属性 - public RoundingMode RoundingMode { get; set; } - - // ITweenOptions接口实现 - 委托给tweenOptions - public long DurationNanos - { - get => tweenOptions.DurationNanos; - set => tweenOptions.DurationNanos = value; - } - - public int Loops - { - get => tweenOptions.Loops; - set => tweenOptions.Loops = value; - } - - public long DelayNanos - { - get => tweenOptions.DelayNanos; - set => tweenOptions.DelayNanos = value; - } - - public DelayType DelayType - { - get => tweenOptions.DelayType; - set => tweenOptions.DelayType = value; - } - - public LoopType LoopType - { - get => tweenOptions.LoopType; - set => tweenOptions.LoopType = value; - } - - public Ease Ease - { - get => tweenOptions.Ease; - set => tweenOptions.Ease = value; - } - - #if LITMOTION_COLLECTIONS_2_0_OR_NEWER - public NativeAnimationCurve AnimationCurve - { - get => tweenOptions.AnimationCurve; - set => tweenOptions.AnimationCurve = value; - } - #else - public UnsafeAnimationCurve AnimationCurve - { - get => tweenOptions.AnimationCurve; - set => tweenOptions.AnimationCurve = value; - } - #endif + public RoundingMode RoundingMode; public readonly bool Equals(IntegerOptions other) { - return tweenOptions.Equals(other.tweenOptions) && RoundingMode == other.RoundingMode; + return other.RoundingMode == RoundingMode; } public override readonly bool Equals(object obj) @@ -78,7 +23,7 @@ public override readonly bool Equals(object obj) public override readonly int GetHashCode() { - return HashCode.Combine(tweenOptions, RoundingMode); + return (int)RoundingMode; } } diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/NoOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/NoOptions.cs new file mode 100644 index 00000000..4c39e400 --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/NoOptions.cs @@ -0,0 +1,26 @@ +using System; + +namespace LitMotion +{ + /// + /// A type indicating that motion has no special options. Specify in the type argument of MotionAdapter when the option is not required. + /// + [Serializable] + public readonly struct NoOptions : IMotionOptions, IEquatable + { + public bool Equals(NoOptions other) + { + return true; + } + + public override bool Equals(object obj) + { + return obj is NoOptions; + } + + public override int GetHashCode() + { + return 0; + } + } +} \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/NoOptions.cs.meta b/src/LitMotion/Assets/LitMotion/Runtime/Options/NoOptions.cs.meta new file mode 100644 index 00000000..303f2a82 --- /dev/null +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/NoOptions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3368898326e974eef8d562e993b21645 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/PunchOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/PunchOptions.cs index 4d1af2e8..ba73d67c 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/PunchOptions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/PunchOptions.cs @@ -1,5 +1,4 @@ using System; -using LitMotion.Collections; namespace LitMotion { @@ -7,64 +6,10 @@ namespace LitMotion /// Options for punch motion. /// [Serializable] - public struct PunchOptions : ITweenOptions, IEquatable + public struct PunchOptions : IEquatable, IMotionOptions { - private TweenOption tweenOptions; - - // PunchOptions特有的属性 - public int Frequency { get; set; } - public float DampingRatio { get; set; } - - // ITweenOptions接口实现 - 委托给tweenOptions - public long DurationNanos - { - get => tweenOptions.DurationNanos; - set => tweenOptions.DurationNanos = value; - } - - public int Loops - { - get => tweenOptions.Loops; - set => tweenOptions.Loops = value; - } - - public long DelayNanos - { - get => tweenOptions.DelayNanos; - set => tweenOptions.DelayNanos = value; - } - - public DelayType DelayType - { - get => tweenOptions.DelayType; - set => tweenOptions.DelayType = value; - } - - public LoopType LoopType - { - get => tweenOptions.LoopType; - set => tweenOptions.LoopType = value; - } - - public Ease Ease - { - get => tweenOptions.Ease; - set => tweenOptions.Ease = value; - } - - #if LITMOTION_COLLECTIONS_2_0_OR_NEWER - public NativeAnimationCurve AnimationCurve - { - get => tweenOptions.AnimationCurve; - set => tweenOptions.AnimationCurve = value; - } - #else - public UnsafeAnimationCurve AnimationCurve - { - get => tweenOptions.AnimationCurve; - set => tweenOptions.AnimationCurve = value; - } - #endif + public int Frequency; + public float DampingRatio; public static PunchOptions Default { @@ -80,9 +25,7 @@ public static PunchOptions Default public readonly bool Equals(PunchOptions other) { - return tweenOptions.Equals(other.tweenOptions) - && Frequency == other.Frequency - && DampingRatio == other.DampingRatio; + return other.Frequency == Frequency && other.DampingRatio == DampingRatio; } public override readonly bool Equals(object obj) @@ -93,7 +36,7 @@ public override readonly bool Equals(object obj) public override readonly int GetHashCode() { - return HashCode.Combine(tweenOptions, Frequency, DampingRatio); + return HashCode.Combine(Frequency, DampingRatio); } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/ShakeOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/ShakeOptions.cs index 5d7a45f5..7aa98fa3 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/ShakeOptions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/ShakeOptions.cs @@ -1,5 +1,4 @@ using System; -using LitMotion.Collections; namespace LitMotion { @@ -7,65 +6,11 @@ namespace LitMotion /// Options for shake motion. /// [Serializable] - public struct ShakeOptions : ITweenOptions, IEquatable + public struct ShakeOptions : IEquatable, IMotionOptions { - private TweenOption tweenOptions; - - // ShakeOptions特有的属性 - public int Frequency { get; set; } - public float DampingRatio { get; set; } - public uint RandomSeed { get; set; } - - // ITweenOptions接口实现 - 委托给tweenOptions - public long DurationNanos - { - get => tweenOptions.DurationNanos; - set => tweenOptions.DurationNanos = value; - } - - public int Loops - { - get => tweenOptions.Loops; - set => tweenOptions.Loops = value; - } - - public long DelayNanos - { - get => tweenOptions.DelayNanos; - set => tweenOptions.DelayNanos = value; - } - - public DelayType DelayType - { - get => tweenOptions.DelayType; - set => tweenOptions.DelayType = value; - } - - public LoopType LoopType - { - get => tweenOptions.LoopType; - set => tweenOptions.LoopType = value; - } - - public Ease Ease - { - get => tweenOptions.Ease; - set => tweenOptions.Ease = value; - } - - #if LITMOTION_COLLECTIONS_2_0_OR_NEWER - public NativeAnimationCurve AnimationCurve - { - get => tweenOptions.AnimationCurve; - set => tweenOptions.AnimationCurve = value; - } - #else - public UnsafeAnimationCurve AnimationCurve - { - get => tweenOptions.AnimationCurve; - set => tweenOptions.AnimationCurve = value; - } - #endif + public int Frequency; + public float DampingRatio; + public uint RandomSeed; public static ShakeOptions Default { @@ -81,10 +26,9 @@ public static ShakeOptions Default public readonly bool Equals(ShakeOptions other) { - return tweenOptions.Equals(other.tweenOptions) - && Frequency == other.Frequency - && DampingRatio == other.DampingRatio - && RandomSeed == other.RandomSeed; + return other.Frequency == Frequency && + other.DampingRatio == DampingRatio && + other.RandomSeed == RandomSeed; } public override readonly bool Equals(object obj) @@ -95,7 +39,7 @@ public override readonly bool Equals(object obj) public override readonly int GetHashCode() { - return HashCode.Combine(tweenOptions, Frequency, DampingRatio, RandomSeed); + return HashCode.Combine(Frequency, DampingRatio, RandomSeed); } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/StringOptions.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/StringOptions.cs index a722e178..d197c1d4 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/StringOptions.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/Options/StringOptions.cs @@ -1,6 +1,5 @@ using System; using Unity.Collections; -using LitMotion.Collections; namespace LitMotion { @@ -39,74 +38,19 @@ public enum ScrambleMode : byte /// Options for string type motion. /// [Serializable] - public struct StringOptions : ITweenOptions, IEquatable + public struct StringOptions : IMotionOptions, IEquatable { - private TweenOption tweenOptions; - - // StringOptions特有的属性 - public ScrambleMode ScrambleMode { get; set; } - public bool RichTextEnabled { get; set; } - public FixedString64Bytes CustomScrambleChars { get; set; } - public uint RandomSeed { get; set; } - - // ITweenOptions接口实现 - 委托给tweenOptions - public long DurationNanos - { - get => tweenOptions.DurationNanos; - set => tweenOptions.DurationNanos = value; - } - - public int Loops - { - get => tweenOptions.Loops; - set => tweenOptions.Loops = value; - } - - public long DelayNanos - { - get => tweenOptions.DelayNanos; - set => tweenOptions.DelayNanos = value; - } - - public DelayType DelayType - { - get => tweenOptions.DelayType; - set => tweenOptions.DelayType = value; - } - - public LoopType LoopType - { - get => tweenOptions.LoopType; - set => tweenOptions.LoopType = value; - } - - public Ease Ease - { - get => tweenOptions.Ease; - set => tweenOptions.Ease = value; - } - - #if LITMOTION_COLLECTIONS_2_0_OR_NEWER - public NativeAnimationCurve AnimationCurve - { - get => tweenOptions.AnimationCurve; - set => tweenOptions.AnimationCurve = value; - } - #else - public UnsafeAnimationCurve AnimationCurve - { - get => tweenOptions.AnimationCurve; - set => tweenOptions.AnimationCurve = value; - } - #endif + public ScrambleMode ScrambleMode; + public bool RichTextEnabled; + public FixedString64Bytes CustomScrambleChars; + public uint RandomSeed; public readonly bool Equals(StringOptions other) { - return tweenOptions.Equals(other.tweenOptions) - && ScrambleMode == other.ScrambleMode - && RichTextEnabled == other.RichTextEnabled - && CustomScrambleChars == other.CustomScrambleChars - && RandomSeed == other.RandomSeed; + return other.ScrambleMode == ScrambleMode && + other.RichTextEnabled == RichTextEnabled && + other.CustomScrambleChars == CustomScrambleChars && + other.RandomSeed == RandomSeed; } public override readonly bool Equals(object obj) @@ -117,7 +61,7 @@ public override readonly bool Equals(object obj) public override readonly int GetHashCode() { - return HashCode.Combine(tweenOptions, ScrambleMode, RichTextEnabled, CustomScrambleChars, RandomSeed); + return HashCode.Combine(ScrambleMode, RichTextEnabled, CustomScrambleChars, RandomSeed); } } } \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Options/TweenOption.cs b/src/LitMotion/Assets/LitMotion/Runtime/Options/TweenOption.cs deleted file mode 100644 index b2b54b0f..00000000 --- a/src/LitMotion/Assets/LitMotion/Runtime/Options/TweenOption.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using LitMotion.Collections; - -namespace LitMotion -{ - /// - /// A type indicating that motion has no special options. Specify in the type argument of MotionAdapter when the option is not required. - /// - [Serializable] - public struct TweenOption : ITweenOptions, IEquatable - { - public long DurationNanos { get; set; } - public int Loops { get; set; } - public long DelayNanos { get; set; } - public DelayType DelayType { get; set; } - public LoopType LoopType { get; set; } - public Ease Ease { get; set; } - - #if LITMOTION_COLLECTIONS_2_0_OR_NEWER - public NativeAnimationCurve AnimationCurve { get; set; } - #else - public UnsafeAnimationCurve AnimationCurve { get; set; } - #endif - - public bool Equals(TweenOption other) - { - return DurationNanos.Equals(other.DurationNanos) - && DelayNanos.Equals(other.DelayNanos) - && DelayType == other.DelayType - && Ease == other.Ease - && Loops == other.Loops - && LoopType == other.LoopType - && AnimationCurve.Equals(other.AnimationCurve); - } - - public override bool Equals(object obj) - { - return obj is TweenOption other && Equals(other); - } - - public override int GetHashCode() - { - return HashCode.Combine(DurationNanos, DelayNanos, DelayType, Ease, Loops, LoopType); - } - } -} \ No newline at end of file diff --git a/src/LitMotion/Assets/LitMotion/Tests/Benchmark/BindBenchmark.cs b/src/LitMotion/Assets/LitMotion/Tests/Benchmark/BindBenchmark.cs index 11b98f89..2c5c9090 100644 --- a/src/LitMotion/Assets/LitMotion/Tests/Benchmark/BindBenchmark.cs +++ b/src/LitMotion/Assets/LitMotion/Tests/Benchmark/BindBenchmark.cs @@ -15,7 +15,7 @@ public class BindBenchmark [OneTimeSetUp] public void OneTimeSetUp() { - MotionDispatcher.EnsureStorageCapacity>(64000); + MotionDispatcher.EnsureStorageCapacity(64000); } [TearDown] diff --git a/src/LitMotion/Assets/LitMotion/Tests/Runtime/ExternalExtensions.cs b/src/LitMotion/Assets/LitMotion/Tests/Runtime/ExternalExtensions.cs index 1591f23f..70b1131f 100644 --- a/src/LitMotion/Assets/LitMotion/Tests/Runtime/ExternalExtensions.cs +++ b/src/LitMotion/Assets/LitMotion/Tests/Runtime/ExternalExtensions.cs @@ -3,11 +3,10 @@ static class ExternalExtensions { #if LITMOTION_TEST_R3 - public static R3.Observable ToR3Observable(this MotionBuilder builder) + public static R3.Observable ToR3Observable(this MotionBuilder builder) where TValue : unmanaged - where VValue : unmanaged - where TOptions : unmanaged, ITweenOptions - where TAnimationSpec : unmanaged, IVectorizedAnimationSpec + where TOptions : unmanaged, IMotionOptions + where TAdapter : unmanaged, IMotionAdapter { return LitMotionR3Extensions.ToObservable(builder); } diff --git a/src/LitMotion/Assets/LitMotion/Tests/Runtime/MotionSettingsTest.cs b/src/LitMotion/Assets/LitMotion/Tests/Runtime/MotionSettingsTest.cs index fe5151b8..94c3789e 100644 --- a/src/LitMotion/Assets/LitMotion/Tests/Runtime/MotionSettingsTest.cs +++ b/src/LitMotion/Assets/LitMotion/Tests/Runtime/MotionSettingsTest.cs @@ -11,7 +11,7 @@ public class MotionSettingsTest public IEnumerator Test_Create() { - var settings = new MotionSettings + var settings = new MotionSettings { StartValue = 0f, EndValue = 1f, From 8aab11539c87c00161c9d8198ab8a6e09bb057b2 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Sun, 28 Sep 2025 07:50:05 +0800 Subject: [PATCH 37/55] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E9=A1=BA=E5=BA=8F=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs b/samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs index c91a1b93..7056bd96 100644 --- a/samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs +++ b/samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs @@ -95,8 +95,8 @@ private void Start() { DetectSystemLanguage(); InitializeLocalizedStrings(); - SetupUI(); AutoAssignUIReferences(); + SetupUI(); } private void SetupUI() From 5dafd586c30ef7de9418b9fba5b8b6b5878d9c84 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Sun, 28 Sep 2025 08:18:23 +0800 Subject: [PATCH 38/55] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E7=9A=84=E4=B8=80=E4=BA=9B=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Tests/LitMotionSpringTestUI.cs | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs b/samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs index 7056bd96..801b5fa4 100644 --- a/samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs +++ b/samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs @@ -16,17 +16,17 @@ public class LitMotionSpringTestUI : MonoBehaviour { [Header("UI Controls")] [SerializeField] private Slider timeScaleSlider; - [SerializeField] private TextMeshProUGUI timeScaleText; + [SerializeField] private Text timeScaleText; [SerializeField] private Slider dampingRatioSlider; - [SerializeField] private TextMeshProUGUI dampingRatioText; + [SerializeField] private Text dampingRatioText; [SerializeField] private Slider stiffnessSlider; - [SerializeField] private TextMeshProUGUI stiffnessText; + [SerializeField] private Text stiffnessText; [SerializeField] private Slider targetValueSlider; - [SerializeField] private TextMeshProUGUI targetValueText; + [SerializeField] private Text targetValueText; [SerializeField] private Slider delaySlider; - [SerializeField] private TextMeshProUGUI delayText; + [SerializeField] private Text delayText; [SerializeField] private Slider loopCountSlider; - [SerializeField] private TextMeshProUGUI loopCountText; + [SerializeField] private Text loopCountText; [SerializeField] private Dropdown loopTypeDropdown; [SerializeField] private Dropdown delayTypeDropdown; @@ -1047,22 +1047,22 @@ private void OnDelayTypeChanged(int value) private void UpdateUI() { if (timeScaleText != null) - timeScaleText.text = $"时间缩放: {timeScale:F2}x"; + timeScaleText.text = $"{timeScale:F2}x"; if (dampingRatioText != null) - dampingRatioText.text = $"阻尼比: {dampingRatio:F2}"; + dampingRatioText.text = $"{dampingRatio:F2}"; if (stiffnessText != null) - stiffnessText.text = $"刚度: {stiffness:F2}"; + stiffnessText.text = $"{stiffness:F2}"; if (targetValueText != null) - targetValueText.text = $"目标值: {targetValue:F3}"; + targetValueText.text = $"{targetValue:F3}"; if (delayText != null) - delayText.text = $"延迟: {delay:F1}s"; + delayText.text = $"{delay:F1}s"; if (loopCountText != null) - loopCountText.text = $"循环次数: {loopCount:F0}"; + loopCountText.text = $"{loopCount:F0}"; } // 自动分配UI引用 @@ -1125,7 +1125,7 @@ private void AutoAssignUIReferences() Debug.LogWarning($"未找到Button: {field.Name}"); } } - else if (field.FieldType == typeof(Text) && field.Name.Contains("performanceResult")) + else if (field.FieldType == typeof(Text)) { Text foundText = FindUnityTextByName(field.Name); if (foundText != null) @@ -1216,9 +1216,13 @@ private Text FindUnityTextByName(string fieldName) foreach (var text in allTexts) { string textName = text.name.ToLower(); - if (textName.Replace("label", "").Replace("value", "").Replace("text", "") == searchName) + if(textName.Contains(searchName)) { - return text; + string endName = textName.Replace(searchName, ""); + if (endName == "value" || endName == "text") + { + return text; + } } } return null; From 79b1319e33d213ab19897851fffacd16204358a8 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Sun, 28 Sep 2025 08:26:31 +0800 Subject: [PATCH 39/55] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs b/samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs index 801b5fa4..6ffeaa31 100644 --- a/samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs +++ b/samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs @@ -1135,7 +1135,7 @@ private void AutoAssignUIReferences() } else { - Debug.LogWarning($"未找到PerformanceResultText: {field.Name}"); + Debug.LogWarning($"未找到: {field.Name}"); } } } @@ -1219,7 +1219,7 @@ private Text FindUnityTextByName(string fieldName) if(textName.Contains(searchName)) { string endName = textName.Replace(searchName, ""); - if (endName == "value" || endName == "text") + if (endName == "value" || endName == "text" || endName == "result" || endName == "") { return text; } From 2611b61d7c781229f1961d91b326d5126c7b4a07 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Tue, 30 Sep 2025 04:54:34 +0800 Subject: [PATCH 40/55] Update SpringUtility.cs --- src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs index d6534dd3..da776443 100644 --- a/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs +++ b/src/LitMotion/Assets/LitMotion/Runtime/SpringUtility.cs @@ -62,7 +62,8 @@ public static void SpringElastic( in float dampingRatio = 0.5f, in float stiffness = 10.0f) { - if (Hint.Unlikely(Approximately(currentValue, targetValue))) + float eps = dampingRatio < 1.0f ? 1e-5f : 1e-2f; + if (Hint.Unlikely(Approximately(currentValue, targetValue, eps))) { currentValue = targetValue; currentVelocity = 0.0f; From fa2c3cf42b23fc4fb7abec7873b45de23534f3a0 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Mon, 29 Dec 2025 01:32:57 +0800 Subject: [PATCH 41/55] revert gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3c3fe90e..3faa1a0a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,3 @@ # Project for Asset Store src/LitMotion.AssetStore/* -*.meta From 563529fc3210c7b65e9216b4900e58fba05210f5 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Mon, 29 Dec 2025 01:34:38 +0800 Subject: [PATCH 42/55] delete api md --- API-Reference-Spring.md | 347 ---------------------------------------- 1 file changed, 347 deletions(-) delete mode 100644 API-Reference-Spring.md diff --git a/API-Reference-Spring.md b/API-Reference-Spring.md deleted file mode 100644 index 85fea645..00000000 --- a/API-Reference-Spring.md +++ /dev/null @@ -1,347 +0,0 @@ -# LitMotion Spring Animation API Reference - -## Namespace -```csharp -using LitMotion; -using LitMotion.Adapters; -``` - -## Core Classes - -### SpringOptions - -```csharp -public struct SpringOptions : IMotionOptions -``` - -#### Properties - -| Property | Type | Description | -|----------|------|-------------| -| `CurrentValue` | `float4` | Current position of the spring | -| `CurrentVelocity` | `float4` | Current velocity of the spring | -| `TargetValue` | `float4` | Target position to converge to | -| `TargetVelocity` | `float4` | Target velocity (usually zero) | -| `Stiffness` | `float` | Spring stiffness (higher = faster) | -| `DampingRatio` | `float` | Damping ratio (1.0 = critical damping) | - -#### Constructors - -```csharp -// Default constructor -public SpringOptions(float stiffness = 10.0f, float dampingRatio = 1.0f, - float4 startVelocity = default, float4 targetVelocity = default) - -// Initialize with values -public void Init(float4 startValue, float4 targetValue, - float4 startVelocity = default, float4 targetVelocity = default) -``` - -#### Static Properties - -```csharp -// Critical damping - fastest convergence without oscillation -public static SpringOptions Critical { get; } - -// Overdamped - smooth, slow convergence -public static SpringOptions Overdamped { get; } - -// Underdamped - bouncy, oscillating motion -public static SpringOptions Underdamped { get; } -``` - -#### Methods - -```csharp -// Restart animation from initial values -public void Restart() - -// Check equality -public bool Equals(SpringOptions other) -``` - -### LMotion.Spring - -```csharp -public static class Spring -``` - -#### Methods - -##### Create Float Spring -```csharp -public static MotionBuilder Create( - float startValue, - float endValue, - SpringOptions options = default) -``` - -**Parameters:** -- `startValue`: Starting value -- `endValue`: Target value -- `options`: Spring configuration - -**Returns:** MotionBuilder for chaining - -**Example:** -```csharp -var motion = LMotion.Spring.Create(0f, 100f, SpringOptions.Critical) - .Bind(value => transform.position.x = value); -``` - -##### Create Vector2 Spring -```csharp -public static MotionBuilder Create( - Vector2 startValue, - Vector2 endValue, - SpringOptions options = default, - Vector2 targetVelocity = default) -``` - -**Parameters:** -- `startValue`: Starting Vector2 -- `endValue`: Target Vector2 -- `options`: Spring configuration -- `targetVelocity`: Target velocity (optional) - -**Example:** -```csharp -var motion = LMotion.Spring.Create(Vector2.zero, new Vector2(100f, 50f), SpringOptions.Critical) - .Bind(value => transform.position = value); -``` - -##### Create Vector3 Spring -```csharp -public static MotionBuilder Create( - Vector3 startValue, - Vector3 endValue, - SpringOptions options = default, - Vector3 targetVelocity = default) -``` - -**Example:** -```csharp -var motion = LMotion.Spring.Create(Vector3.zero, new Vector3(10f, 5f, 0f), SpringOptions.Critical) - .Bind(value => transform.position = value); -``` - -##### Create Vector4 Spring -```csharp -public static MotionBuilder Create( - Vector4 startValue, - Vector4 endValue, - SpringOptions options = default, - Vector4 targetVelocity = default) -``` - -**Example:** -```csharp -var motion = LMotion.Spring.Create(Vector4.zero, new Vector4(1f, 0.5f, 0.2f, 1f), SpringOptions.Critical) - .Bind(value => material.color = value); -``` - -## Motion Adapters - -### FloatSpringMotionAdapter -```csharp -public readonly struct FloatSpringMotionAdapter : IMotionAdapter -``` - -### Vector2SpringMotionAdapter -```csharp -public readonly struct Vector2SpringMotionAdapter : IMotionAdapter -``` - -### Vector3SpringMotionAdapter -```csharp -public readonly struct Vector3SpringMotionAdapter : IMotionAdapter -``` - -### Vector4SpringMotionAdapter -```csharp -public readonly struct Vector4SpringMotionAdapter : IMotionAdapter -``` - -## MotionBuilder Extensions - -All standard LitMotion MotionBuilder methods are supported: - -### Animation Control -```csharp -// Pause animation -motion.Pause(); - -// Resume animation -motion.Resume(); - -// Cancel animation -motion.Cancel(); - -// Complete immediately -motion.Complete(); -``` - -### Continuous Tracking (Manual Stop Required) -```csharp -// For continuous tracking that requires manual stopping -var continuousMotion = LMotion.Spring.Create(0f, 10f, SpringOptions.Critical) - .WithLoops(-1, LoopType.Incremental) // Infinite loops with incremental - .Bind(value => transform.position.x = value); - -// Manually stop when needed -continuousMotion.Cancel(); -``` - -**Important Notes:** -- Use `LoopType.Incremental` with `loops = -1` for continuous tracking -- Spring animations require manual stopping - they don't auto-complete -- `MotionHandle.TotalDuration` is meaningless for spring animations (physics-based, not time-based) - -### Loops -```csharp -// Loop with specific type -motion.WithLoops(3, LoopType.Yoyo); - -// Available loop types: -// - LoopType.Restart -// - LoopType.Flip -// - LoopType.Incremental -// - LoopType.Yoyo -``` - -### Delays -```csharp -// Add delay -motion.WithDelay(1.0f, DelayType.FirstLoop); - -// Available delay types: -// - DelayType.FirstLoop -// - DelayType.EveryLoop -``` - -### Callbacks -```csharp -// Animation callbacks -motion.WithOnComplete(() => Debug.Log("Completed")) - .WithOnUpdate(value => Debug.Log($"Value: {value}")) - .WithOnCancel(() => Debug.Log("Cancelled")); -``` - -### Time Scale -```csharp -// Respect time scale -motion.WithTimeScale(TimeScale.Unscaled); -``` - - -## Performance Considerations - -### Burst Compilation -Spring animations automatically use Burst compilation in build versions for maximum performance. - -### SIMD Operations -Vector operations use Unity.Mathematics float4 for SIMD acceleration when possible. - -### Memory Management -- **Zero GC Design**: LitMotion uses structs and value types throughout -- **SpringOptions are structs**: No GC allocation for spring configurations -- **MotionHandles are lightweight**: Lightweight references, not heavy objects -- **No Object Pooling Needed**: 0GC design eliminates the need for object pooling -- **High Performance**: Spring animations are actually faster than traditional tweens -- **No Concurrency Limits**: Performance tested to handle large numbers of concurrent animations - -## Parameter Guidelines - -### Stiffness Values -- **1-5**: Very slow, gentle motion -- **5-10**: Slow, smooth motion -- **10-15**: Balanced motion (recommended) -- **15-20**: Fast, snappy motion -- **20+**: Very fast, potentially unstable - -### Damping Ratio Values -- **0.1-0.5**: Very bouncy, many oscillations -- **0.5-0.8**: Bouncy, few oscillations -- **0.8-1.0**: Slightly bouncy -- **1.0**: Critical damping (fastest convergence) -- **1.0-1.5**: Smooth, no oscillation -- **1.5+**: Very smooth, slow convergence - -## Common Patterns - -### UI Button Animation -```csharp -// Button press effect -var pressAnimation = LMotion.Spring.Create(1f, 0.9f, SpringOptions.Overdamped) - .WithLoops(1, LoopType.Yoyo) - .Bind(scale => button.transform.localScale = Vector3.one * scale); -``` - -### Smooth Camera Following -```csharp -// Camera follow with spring physics -var followAnimation = LMotion.Spring.Create( - camera.transform.position, - targetPosition, - SpringOptions.Critical) - .Bind(position => camera.transform.position = position); -``` - -### Color Transitions -```csharp -// Smooth color changes -var colorAnimation = LMotion.Spring.Create( - currentColor, - targetColor, - SpringOptions.Underdamped) - .Bind(color => material.color = color); -``` - -### Multi-property Animation -```csharp -// Animate multiple properties simultaneously -var positionSpring = LMotion.Spring.Create(Vector3.zero, targetPos, SpringOptions.Critical) - .Bind(pos => transform.position = pos); - -var scaleSpring = LMotion.Spring.Create(Vector3.one, targetScale, SpringOptions.Overdamped) - .Bind(scale => transform.localScale = scale); -``` - -## Error Handling - -### Common Issues - -1. **Animation Not Completing** - - Check if target value is reachable - - Verify stiffness and damping ratio are reasonable - - Ensure delta time is not zero - - For continuous tracking, use `LoopType.Incremental` with `loops = -1` - -2. **Performance Issues** - - Use Burst compilation in build versions - - Reuse SpringOptions instances - - No object pooling needed (0GC design) - - Spring animations are actually faster than traditional tweens - - No concurrency limits - performance tested for large numbers of animations - -3. **Unexpected Behavior** - - Verify spring parameters are within recommended ranges - - Check for conflicting animations - - Ensure proper initialization - - Remember that `MotionHandle.TotalDuration` is meaningless for spring animations - -4. **Continuous Tracking Issues** - - Use `LoopType.Incremental` with `loops = -1` for continuous tracking - - Always manually stop continuous animations with `Cancel()` - - Don't rely on auto-completion for continuous spring animations - -## Integration with LitMotion - -Spring animations integrate seamlessly with LitMotion's existing API: - -- Same MotionBuilder interface -- Compatible with all LitMotion features (loops, delays, callbacks) -- Uses existing MotionHandle system -- Supports all LitMotion control methods - -This ensures that existing LitMotion knowledge and patterns can be applied to spring animations with minimal learning curve. From 83e9424840162f2dfca4d180a8f4ce2983a8c131 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Mon, 29 Dec 2025 01:35:42 +0800 Subject: [PATCH 43/55] delete readme md --- README-Spring.md | 163 ----------------------------------------------- 1 file changed, 163 deletions(-) delete mode 100644 README-Spring.md diff --git a/README-Spring.md b/README-Spring.md deleted file mode 100644 index c8d98220..00000000 --- a/README-Spring.md +++ /dev/null @@ -1,163 +0,0 @@ -# LitMotion Spring Animation Extension - -## 🎯 Purpose - -This extension adds physics-based spring animations to LitMotion, providing natural and responsive motion that simulates real-world spring physics. Perfect for modern UI interactions and smooth camera movements. - -## ✨ Key Features - -- **🌊 Physics-based Motion**: Natural spring physics simulation -- **📐 Multi-dimensional**: Support for float, Vector2, Vector3, and Vector4 -- **⚡ High Performance**: Burst-compiled with SIMD optimizations -- **🔄 Velocity Preservation**: Smooth animation interruptions -- **🎛️ Configurable**: Adjustable stiffness and damping parameters - -## 🚀 Quick Start - -### Basic Usage - -```csharp -// Simple spring animation -var motion = LMotion.Spring.Create(0f, 100f, SpringOptions.Critical) - .Bind(value => transform.position.x = value); -``` - -### Predefined Configurations - -```csharp -SpringOptions.Critical // Fastest convergence, no oscillation -SpringOptions.Overdamped // Smooth, slow convergence -SpringOptions.Underdamped // Bouncy, oscillating motion -``` - -### Custom Parameters - -```csharp -var options = new SpringOptions( - stiffness: 15f, // Higher = faster convergence - dampingRatio: 0.8f // < 1.0 = bouncy, = 1.0 = critical, > 1.0 = smooth -); -``` - -### Continuous Tracking - -```csharp -// For continuous tracking that requires manual stopping -var continuousMotion = LMotion.Spring.Create(0f, 10f, SpringOptions.Critical) - .WithLoops(-1, LoopType.Incremental) // Infinite loops - .Bind(value => transform.position.x = value); - -// Manually stop when needed -continuousMotion.Cancel(); -``` - -**Important:** -- Use `LoopType.Incremental` with `loops = -1` for continuous tracking -- `MotionHandle.TotalDuration` is meaningless for spring animations -- Spring animations require manual stopping - -## 📋 Supported Features - -| Feature | Status | Notes | -|---------|--------|-------| -| **Multi-dimensional** | ✅ | float, Vector2, Vector3, Vector4 | -| **Loops** | ✅ | All loop types supported | -| **Delays** | ✅ | First loop and every loop delays | -| **Callbacks** | ✅ | OnComplete, OnUpdate, OnCancel | -| **Time Scale** | ✅ | Respects Unity's time scale | -| **Pause/Resume** | ✅ | Full control support | -| **Cancel** | ✅ | Immediate cancellation | - -## ❌ Unsupported Features - -| Feature | Reason | -|---------|--------| -| **Fixed Duration** | Spring animations converge based on physics, not time | -| **Easing Curves** | Physics replace traditional easing | -| **Linear Interpolation** | Spring motion is inherently non-linear | -| **TotalDuration** | `MotionHandle.TotalDuration` is meaningless for physics-based animations | -| **Auto-completion** | Requires manual stopping for continuous tracking | - -## 🎮 Use Cases - -### UI Animations -```csharp -// Button press effect -var press = LMotion.Spring.Create(1f, 0.9f, SpringOptions.Overdamped) - .Bind(scale => button.transform.localScale = Vector3.one * scale); -``` - -### Camera Movement -```csharp -// Smooth camera following -var follow = LMotion.Spring.Create(cameraPos, targetPos, SpringOptions.Critical) - .Bind(pos => camera.transform.position = pos); -``` - -### Color Transitions -```csharp -// Natural color changes -var color = LMotion.Spring.Create(currentColor, targetColor, SpringOptions.Underdamped) - .Bind(c => material.color = c); -``` - -## ⚙️ Parameter Guide - -### Stiffness (5-20 recommended) -- **Low (5-10)**: Slow, gentle motion -- **Medium (10-15)**: Balanced motion -- **High (15-20)**: Fast, snappy motion - -### Damping Ratio -- **< 1.0**: Underdamped (bouncy, oscillates) -- **= 1.0**: Critical damping (fastest, no oscillation) -- **> 1.0**: Overdamped (smooth, slow) - -## 🔄 Migration from Traditional Tweens - -### Before -```csharp -var tween = LMotion.Create(0f, 10f, 2f) - .WithEase(Ease.OutQuad) - .Bind(value => transform.position.x = value); -``` - -### After -```csharp -var spring = LMotion.Spring.Create(0f, 10f, SpringOptions.Critical) - .Bind(value => transform.position.x = value); -``` - -## 🎯 When to Use Spring vs Traditional Tweens - -### Use Spring When: -- You want natural, physics-based motion -- Animation timing is flexible -- You need smooth interruption handling -- Creating modern UI interactions - -### Use Traditional Tweens When: -- You need precise timing control -- You require specific easing curves -- You need linear interpolation -- Working with legacy systems - -## 🛠️ Performance Tips - -1. **Use Burst Compilation**: Build versions automatically use Burst for maximum performance -2. **Reuse SpringOptions**: Create once, use multiple times -3. **High Performance**: Spring animations are actually faster than traditional tweens -4. **Zero GC Design**: LitMotion uses structs and value types - no object pooling needed -5. **No Concurrency Limits**: Performance tested to handle large numbers of concurrent animations - -## 📚 Documentation - -For complete API reference and advanced usage, see [Spring Animation Documentation](./Spring-Animation-Documentation.md). - -## 🤝 Contributing - -This extension follows LitMotion's design principles and integrates seamlessly with the existing API. Contributions that maintain compatibility and performance are welcome. - -## 📄 License - -Same as LitMotion - see the main LitMotion repository for license information. From d2e8860ff131a815bb8264b7ea6f6454c9dfbbdd Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Mon, 29 Dec 2025 01:37:24 +0800 Subject: [PATCH 44/55] revert readme --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 3ef4f02b..bea3f6ee 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,3 @@ -# Main modifications -Vectorize the animation target values to support different animation algorithms such as Tween and Spring. - # LitMotion Lightning-fast and Zero Allocation Tween Library for Unity. From b764cc88ee4e1419e3437c10e40cf3bb2ecd4e94 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Mon, 29 Dec 2025 01:37:49 +0800 Subject: [PATCH 45/55] delete document --- Spring-Animation-Documentation.md | 307 ------------------------------ 1 file changed, 307 deletions(-) delete mode 100644 Spring-Animation-Documentation.md diff --git a/Spring-Animation-Documentation.md b/Spring-Animation-Documentation.md deleted file mode 100644 index 227f35da..00000000 --- a/Spring-Animation-Documentation.md +++ /dev/null @@ -1,307 +0,0 @@ -# LitMotion Spring Animation Documentation - -## Overview - -LitMotion Spring Animation is an extension to the LitMotion library that provides physics-based spring animations. Unlike traditional tween animations that use easing curves, spring animations simulate real-world spring physics to create more natural and responsive motion. - -## Key Features - -- **Physics-based Animation**: Uses spring physics simulation for natural motion -- **Multi-dimensional Support**: Works with float, Vector2, Vector3, and Vector4 types -- **High Performance**: Optimized with Burst compilation and SIMD operations -- **Velocity Preservation**: Maintains velocity information for smooth animation interruptions -- **Configurable Parameters**: Adjustable stiffness and damping ratio for different spring behaviors - -## Spring Animation vs Traditional Tween - -### Supported Features ✅ - -| Feature | Traditional Tween | Spring Animation | -|---------|-------------------|------------------| -| Duration | ✅ Fixed duration | ❌ Physics-based convergence | -| Easing | ✅ Ease curves (In, Out, InOut) | ❌ Physics-based motion | -| Loops | ✅ Loop support | ✅ Loop support | -| Delay | ✅ Delay support | ✅ Delay support | -| Callbacks | ✅ OnComplete, OnUpdate | ✅ OnComplete, OnUpdate | -| Time Scale | ✅ Time scale support | ✅ Time scale support | -| Pause/Resume | ✅ Pause/Resume | ✅ Pause/Resume | -| Cancel | ✅ Cancel support | ✅ Cancel support | - -### Unsupported Features ❌ - -| Feature | Reason | -|---------|--------| -| **Fixed Duration** | Spring animations converge based on physics, not time | -| **Easing Curves** | Spring physics replace easing with natural motion | -| **Duration-based Completion** | Completion is based on convergence to target value | -| **Linear Interpolation** | Spring motion is inherently non-linear | -| **TotalDuration Property** | `MotionHandle.TotalDuration` is meaningless for physics-based animations | -| **Auto-completion** | Spring animations require manual stopping for continuous tracking | - -## API Reference - -### SpringOptions - -```csharp -public struct SpringOptions : IMotionOptions -{ - public float4 CurrentValue; // Current position - public float4 CurrentVelocity; // Current velocity - public float4 TargetValue; // Target position - public float4 TargetVelocity; // Target velocity - public float Stiffness; // Spring stiffness (higher = faster) - public float DampingRatio; // Damping ratio (1.0 = critical damping) -} -``` - -#### Predefined Spring Configurations - -```csharp -// Critical damping - no oscillation, fastest convergence -SpringOptions.Critical - -// Overdamped - slow convergence, no oscillation -SpringOptions.Overdamped - -// Underdamped - oscillates before settling -SpringOptions.Underdamped -``` - -### Creating Spring Animations - -#### Float Spring Animation - -```csharp -// Basic spring animation -var motion = LMotion.Spring.Create(0f, 10f, SpringOptions.Critical) - .Bind(value => transform.position.x = value); - -// Custom spring parameters -var options = new SpringOptions(stiffness: 15f, dampingRatio: 0.8f); -var motion = LMotion.Spring.Create(0f, 10f, options) - .Bind(value => transform.position.x = value); -``` - -#### Vector2 Spring Animation - -```csharp -var motion = LMotion.Spring.Create(Vector2.zero, new Vector2(100f, 50f), SpringOptions.Critical) - .Bind(value => transform.position = value); -``` - -#### Vector3 Spring Animation - -```csharp -var motion = LMotion.Spring.Create(Vector3.zero, new Vector3(10f, 5f, 0f), SpringOptions.Critical) - .Bind(value => transform.position = value); -``` - -#### Vector4 Spring Animation - -```csharp -var motion = LMotion.Spring.Create(Vector4.zero, new Vector4(1f, 0.5f, 0.2f, 1f), SpringOptions.Critical) - .Bind(value => material.color = value); -``` - -### Spring Parameters - -#### Stiffness -- **Range**: 1.0f - 50.0f (recommended: 5.0f - 20.0f) -- **Effect**: Higher values make the spring "stiffer" and converge faster -- **Default**: 10.0f - -#### Damping Ratio -- **< 1.0**: Underdamped (oscillates before settling) -- **= 1.0**: Critical damping (fastest convergence without oscillation) -- **> 1.0**: Overdamped (slow convergence, no oscillation) -- **Default**: 1.0f (critical damping) - -### Animation Control - -```csharp -// Start animation -var motion = LMotion.Spring.Create(0f, 10f, SpringOptions.Critical) - .Bind(value => transform.position.x = value); - -// Pause animation -motion.Pause(); - -// Resume animation -motion.Resume(); - -// Cancel animation -motion.Cancel(); - -// Complete animation immediately -motion.Complete(); -``` - -### Continuous Tracking (Manual Stop Required) - -For animations that need continuous tracking and manual stopping: - -```csharp -// Continuous spring animation that requires manual stop -var continuousMotion = LMotion.Spring.Create(0f, 10f, SpringOptions.Critical) - .WithLoops(-1, LoopType.Incremental) // Infinite loops with incremental - .Bind(value => transform.position.x = value); - -// Manually stop when needed -continuousMotion.Cancel(); -``` - -**Important Notes:** -- Use `LoopType.Incremental` with `loops = -1` for continuous tracking -- Spring animations require manual stopping - they don't auto-complete -- `MotionHandle.TotalDuration` is meaningless for spring animations (physics-based, not time-based) - -### Callbacks - -```csharp -var motion = LMotion.Spring.Create(0f, 10f, SpringOptions.Critical) - .WithOnComplete(() => Debug.Log("Spring animation completed")) - .WithOnUpdate(value => Debug.Log($"Current value: {value}")) - .Bind(value => transform.position.x = value); -``` - -### Loops and Delays - -```csharp -var motion = LMotion.Spring.Create(0f, 10f, SpringOptions.Critical) - .WithLoops(3, LoopType.Yoyo) // Loop 3 times with yoyo effect - .WithDelay(1.0f, DelayType.FirstLoop) // 1 second delay before first loop - .Bind(value => transform.position.x = value); -``` - -## Important Spring Animation Characteristics - -### Duration and Completion -- **No Fixed Duration**: Spring animations are physics-based, not time-based -- **Convergence-based Completion**: Animations complete when they converge to the target value -- **Manual Stop Required**: For continuous tracking, use `LoopType.Incremental` with `loops = -1` -- **TotalDuration is Meaningless**: `MotionHandle.TotalDuration` has no meaning for spring animations - -### Continuous Tracking Pattern -```csharp -// Correct pattern for continuous tracking -var continuousMotion = LMotion.Spring.Create(0f, 10f, SpringOptions.Critical) - .WithLoops(-1, LoopType.Incremental) // Infinite loops with incremental - .Bind(value => transform.position.x = value); - -// Must manually stop when done -continuousMotion.Cancel(); -``` - -### Why These Limitations Exist -- **Physics-based**: Spring animations simulate real physics, not predetermined timing -- **Convergence-dependent**: Completion depends on reaching the target, not elapsed time -- **Continuous nature**: Some use cases require ongoing tracking that never "completes" - -## Performance Considerations - -### Burst Compilation -Spring animations are optimized with Burst compilation for maximum performance in build versions. - -### SIMD Operations -Vector operations use Unity.Mathematics float4 for SIMD acceleration when possible. - -### Zero GC Design -- **No Object Pooling Needed**: LitMotion uses 0GC design with structs and value types -- **Memory Efficient**: SpringOptions are structs, no garbage collection -- **Reusable**: MotionHandles are lightweight references, not heavy objects -- **High Performance**: Spring animations are actually faster than traditional tweens -- **No Concurrency Concerns**: Performance tested to handle large numbers of concurrent animations - -### Performance Advantages -- **Faster than Tweens**: Performance testing shows Spring animations outperform traditional tweens -- **Scalable**: Can handle thousands of concurrent animations without performance degradation -- **Burst Optimized**: Automatic Burst compilation in build versions for maximum speed -- **SIMD Accelerated**: Vector operations use Unity.Mathematics for SIMD acceleration - -## Migration from Traditional Tweens - -### Before (Traditional Tween) -```csharp -// Traditional tween with easing -var tween = LMotion.Create(0f, 10f, 2f) - .WithEase(Ease.OutQuad) - .Bind(value => transform.position.x = value); -``` - -### After (Spring Animation) -```csharp -// Spring animation with physics -var spring = LMotion.Spring.Create(0f, 10f, SpringOptions.Critical) - .Bind(value => transform.position.x = value); -``` - -### Key Differences -1. **No Duration**: Spring animations don't have fixed durations -2. **No Easing**: Physics replace easing curves -3. **Natural Motion**: More realistic animation behavior -4. **Velocity Preservation**: Smooth interruption handling - -## Best Practices - -### When to Use Spring Animations -- UI element positioning and scaling -- Camera movement and following -- Physics-based interactions -- Natural feeling transitions - -### When to Use Traditional Tweens -- Precise timing requirements -- Linear or specific easing needs -- Simple value interpolation -- Legacy compatibility - -### Parameter Tuning -- Start with `SpringOptions.Critical` for most use cases -- Use `SpringOptions.Underdamped` for bouncy effects -- Use `SpringOptions.Overdamped` for smooth, slow transitions -- Adjust stiffness for speed (higher = faster) -- Adjust damping ratio for oscillation behavior - -## Examples - -### UI Button Animation -```csharp -// Button press animation -var pressAnimation = LMotion.Spring.Create(1f, 0.9f, SpringOptions.Overdamped) - .Bind(scale => button.transform.localScale = Vector3.one * scale); -``` - -### Camera Follow -```csharp -// Smooth camera following -var followAnimation = LMotion.Spring.Create(cameraPosition, targetPosition, SpringOptions.Critical) - .Bind(position => camera.transform.position = position); -``` - -### Color Transition -```csharp -// Smooth color changes -var colorAnimation = LMotion.Spring.Create(currentColor, targetColor, SpringOptions.Underdamped) - .Bind(color => material.color = color); -``` - -## Troubleshooting - -### Animation Not Completing -- Check if target value is reachable -- Verify stiffness and damping ratio settings -- Ensure delta time is not zero - -### Performance Issues -- Use Burst compilation in build versions -- Avoid creating too many simultaneous spring animations -- Consider using object pooling for frequent animations - -### Unexpected Behavior -- Verify spring parameters are within reasonable ranges -- Check for conflicting animations on the same property -- Ensure proper initialization of spring options - -## Conclusion - -LitMotion Spring Animation provides a powerful alternative to traditional tween animations, offering more natural and physics-based motion. While it doesn't support all traditional tween features like fixed durations and easing curves, it provides unique benefits in terms of natural motion and velocity preservation that make it ideal for modern UI and game interactions. From 3ea6db19353103de65c274dbf69994f5df9701c1 Mon Sep 17 00:00:00 2001 From: Dashe <1410722798@qq.com> Date: Mon, 29 Dec 2025 01:40:20 +0800 Subject: [PATCH 46/55] delete spring.test --- .../Tests/BurstPerformanceUICreator.cs | 309 ---- .../Tests/BurstPerformanceUITest.cs | 858 --------- .../Tests/BurstTestUsageGuide.cs | 79 - .../LitMotion.Spring/Tests/DamperTest.asmdef | 20 - .../Tests/DamperUtilityTestUI.cs | 913 ---------- .../Tests/DamperUtilityTestUISetup.cs | 423 ----- .../Tests/DamperUtilityTestUI_README.md | 226 --- .../Editor/DamperUtilityPerformanceTest.cs | 546 ------ .../DamperUtilityPerformanceTest_README.md | 219 --- .../DamperUtilitySimplePerformanceTest.cs | 301 ---- .../Editor/EaseUtilityPerformanceTest.cs | 329 ---- .../Tests/LitMotionSpringTestLauncher.cs | 129 -- .../Tests/LitMotionSpringTestUI.cs | 1528 ----------------- .../Tests/LitMotionSpringTestUISetup.cs | 540 ------ .../Tests/LitMotionSpringTest_ButtonLabels.md | 83 - .../Tests/LitMotionSpringTest_README.md | 156 -- .../Tests/LitMotionSpringTest_Summary.md | 159 -- .../LitMotionSpringTest_Troubleshooting.md | 198 --- .../Tests/README_BurstPerformanceTest.md | 148 -- 19 files changed, 7164 deletions(-) delete mode 100644 samples/LitMotion.Spring/Tests/BurstPerformanceUICreator.cs delete mode 100644 samples/LitMotion.Spring/Tests/BurstPerformanceUITest.cs delete mode 100644 samples/LitMotion.Spring/Tests/BurstTestUsageGuide.cs delete mode 100644 samples/LitMotion.Spring/Tests/DamperTest.asmdef delete mode 100644 samples/LitMotion.Spring/Tests/DamperUtilityTestUI.cs delete mode 100644 samples/LitMotion.Spring/Tests/DamperUtilityTestUISetup.cs delete mode 100644 samples/LitMotion.Spring/Tests/DamperUtilityTestUI_README.md delete mode 100644 samples/LitMotion.Spring/Tests/Editor/DamperUtilityPerformanceTest.cs delete mode 100644 samples/LitMotion.Spring/Tests/Editor/DamperUtilityPerformanceTest_README.md delete mode 100644 samples/LitMotion.Spring/Tests/Editor/DamperUtilitySimplePerformanceTest.cs delete mode 100644 samples/LitMotion.Spring/Tests/Editor/EaseUtilityPerformanceTest.cs delete mode 100644 samples/LitMotion.Spring/Tests/LitMotionSpringTestLauncher.cs delete mode 100644 samples/LitMotion.Spring/Tests/LitMotionSpringTestUI.cs delete mode 100644 samples/LitMotion.Spring/Tests/LitMotionSpringTestUISetup.cs delete mode 100644 samples/LitMotion.Spring/Tests/LitMotionSpringTest_ButtonLabels.md delete mode 100644 samples/LitMotion.Spring/Tests/LitMotionSpringTest_README.md delete mode 100644 samples/LitMotion.Spring/Tests/LitMotionSpringTest_Summary.md delete mode 100644 samples/LitMotion.Spring/Tests/LitMotionSpringTest_Troubleshooting.md delete mode 100644 samples/LitMotion.Spring/Tests/README_BurstPerformanceTest.md diff --git a/samples/LitMotion.Spring/Tests/BurstPerformanceUICreator.cs b/samples/LitMotion.Spring/Tests/BurstPerformanceUICreator.cs deleted file mode 100644 index 01676680..00000000 --- a/samples/LitMotion.Spring/Tests/BurstPerformanceUICreator.cs +++ /dev/null @@ -1,309 +0,0 @@ -using UnityEngine; -using UnityEngine.UI; - -namespace ASUI.Test -{ - /// - /// 自动创建Burst性能测试UI的脚本 - /// 在编辑器中运行此脚本来创建测试界面 - /// - public class BurstPerformanceUICreator : MonoBehaviour - { - [ContextMenu("创建Burst性能测试UI")] - public void CreateBurstPerformanceUI() - { - // 创建Canvas - GameObject canvasGO = new GameObject("BurstPerformanceTestCanvas"); - Canvas canvas = canvasGO.AddComponent(); - canvas.renderMode = RenderMode.ScreenSpaceOverlay; - canvas.sortingOrder = 100; - - CanvasScaler scaler = canvasGO.AddComponent(); - scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; - scaler.referenceResolution = new Vector2(1920, 1080); - scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; - scaler.matchWidthOrHeight = 0.5f; - - canvasGO.AddComponent(); - - // 创建背景面板 - GameObject backgroundGO = new GameObject("Background"); - backgroundGO.transform.SetParent(canvasGO.transform, false); - - RectTransform backgroundRect = backgroundGO.AddComponent(); - backgroundRect.anchorMin = Vector2.zero; - backgroundRect.anchorMax = Vector2.one; - backgroundRect.offsetMin = Vector2.zero; - backgroundRect.offsetMax = Vector2.zero; - - Image backgroundImage = backgroundGO.AddComponent(); - backgroundImage.color = new Color(0, 0, 0, 0.8f); - - // 创建主面板 - GameObject mainPanelGO = new GameObject("MainPanel"); - mainPanelGO.transform.SetParent(backgroundGO.transform, false); - - RectTransform mainPanelRect = mainPanelGO.AddComponent(); - mainPanelRect.anchorMin = new Vector2(0.1f, 0.1f); - mainPanelRect.anchorMax = new Vector2(0.9f, 0.9f); - mainPanelRect.offsetMin = Vector2.zero; - mainPanelRect.offsetMax = Vector2.zero; - - Image mainPanelImage = mainPanelGO.AddComponent(); - mainPanelImage.color = new Color(0.2f, 0.2f, 0.2f, 0.9f); - - // 添加圆角效果 - mainPanelGO.AddComponent(); - - // 创建标题 - GameObject titleGO = new GameObject("Title"); - titleGO.transform.SetParent(mainPanelGO.transform, false); - - RectTransform titleRect = titleGO.AddComponent(); - titleRect.anchorMin = new Vector2(0, 0.85f); - titleRect.anchorMax = new Vector2(1, 1); - titleRect.offsetMin = new Vector2(20, 0); - titleRect.offsetMax = new Vector2(-20, -10); - - Text titleText = titleGO.AddComponent(); - titleText.text = "Burst性能测试工具"; - titleText.fontSize = 32; - titleText.color = Color.white; - titleText.alignment = TextAnchor.MiddleCenter; - titleText.fontStyle = FontStyle.Bold; - - // 创建控制面板 - GameObject controlPanelGO = new GameObject("ControlPanel"); - controlPanelGO.transform.SetParent(mainPanelGO.transform, false); - - RectTransform controlPanelRect = controlPanelGO.AddComponent(); - controlPanelRect.anchorMin = new Vector2(0, 0.7f); - controlPanelRect.anchorMax = new Vector2(1, 0.85f); - controlPanelRect.offsetMin = new Vector2(20, 0); - controlPanelRect.offsetMax = new Vector2(-20, -10); - - // 创建迭代次数滑块 - GameObject sliderGO = new GameObject("IterationSlider"); - sliderGO.transform.SetParent(controlPanelGO.transform, false); - - RectTransform sliderRect = sliderGO.AddComponent(); - sliderRect.anchorMin = new Vector2(0, 0.5f); - sliderRect.anchorMax = new Vector2(0.7f, 1); - sliderRect.offsetMin = Vector2.zero; - sliderRect.offsetMax = new Vector2(-10, 0); - - Slider slider = sliderGO.AddComponent(); - slider.minValue = 0f; - slider.maxValue = 1f; - slider.value = 0.5f; - - // 滑块背景 - GameObject sliderBackgroundGO = new GameObject("Background"); - sliderBackgroundGO.transform.SetParent(sliderGO.transform, false); - - RectTransform sliderBackgroundRect = sliderBackgroundGO.AddComponent(); - sliderBackgroundRect.anchorMin = Vector2.zero; - sliderBackgroundRect.anchorMax = Vector2.one; - sliderBackgroundRect.offsetMin = Vector2.zero; - sliderBackgroundRect.offsetMax = Vector2.zero; - - Image sliderBackgroundImage = sliderBackgroundGO.AddComponent(); - sliderBackgroundImage.color = new Color(0.3f, 0.3f, 0.3f, 1f); - - // 滑块填充 - GameObject sliderFillGO = new GameObject("Fill Area"); - sliderFillGO.transform.SetParent(sliderGO.transform, false); - - RectTransform sliderFillAreaRect = sliderFillGO.AddComponent(); - sliderFillAreaRect.anchorMin = Vector2.zero; - sliderFillAreaRect.anchorMax = Vector2.one; - sliderFillAreaRect.offsetMin = Vector2.zero; - sliderFillAreaRect.offsetMax = Vector2.zero; - - GameObject sliderFillGO2 = new GameObject("Fill"); - sliderFillGO2.transform.SetParent(sliderFillGO.transform, false); - - RectTransform sliderFillRect = sliderFillGO2.AddComponent(); - sliderFillRect.anchorMin = Vector2.zero; - sliderFillRect.anchorMax = Vector2.one; - sliderFillRect.offsetMin = Vector2.zero; - sliderFillRect.offsetMax = Vector2.zero; - - Image sliderFillImage = sliderFillGO2.AddComponent(); - sliderFillImage.color = new Color(0.2f, 0.6f, 1f, 1f); - - // 滑块手柄 - GameObject sliderHandleGO = new GameObject("Handle Slide Area"); - sliderHandleGO.transform.SetParent(sliderGO.transform, false); - - RectTransform sliderHandleAreaRect = sliderHandleGO.AddComponent(); - sliderHandleAreaRect.anchorMin = Vector2.zero; - sliderHandleAreaRect.anchorMax = Vector2.one; - sliderHandleAreaRect.offsetMin = Vector2.zero; - sliderHandleAreaRect.offsetMax = Vector2.zero; - - GameObject sliderHandleGO2 = new GameObject("Handle"); - sliderHandleGO2.transform.SetParent(sliderHandleGO.transform, false); - - RectTransform sliderHandleRect = sliderHandleGO2.AddComponent(); - sliderHandleRect.sizeDelta = new Vector2(20, 20); - - Image sliderHandleImage = sliderHandleGO2.AddComponent(); - sliderHandleImage.color = Color.white; - - // 设置滑块的引用 - slider.fillRect = sliderFillRect; - slider.handleRect = sliderHandleRect; - - // 创建迭代次数标签 - GameObject iterationLabelGO = new GameObject("IterationLabel"); - iterationLabelGO.transform.SetParent(controlPanelGO.transform, false); - - RectTransform iterationLabelRect = iterationLabelGO.AddComponent(); - iterationLabelRect.anchorMin = new Vector2(0.7f, 0.5f); - iterationLabelRect.anchorMax = new Vector2(1, 1); - iterationLabelRect.offsetMin = new Vector2(10, 0); - iterationLabelRect.offsetMax = Vector2.zero; - - Text iterationLabelText = iterationLabelGO.AddComponent(); - iterationLabelText.text = "迭代次数: 500,000"; - iterationLabelText.fontSize = 16; - iterationLabelText.color = Color.white; - iterationLabelText.alignment = TextAnchor.MiddleLeft; - - // 创建按钮面板 - GameObject buttonPanelGO = new GameObject("ButtonPanel"); - buttonPanelGO.transform.SetParent(controlPanelGO.transform, false); - - RectTransform buttonPanelRect = buttonPanelGO.AddComponent(); - buttonPanelRect.anchorMin = new Vector2(0, 0); - buttonPanelRect.anchorMax = new Vector2(1, 0.5f); - buttonPanelRect.offsetMin = new Vector2(0, 0); - buttonPanelRect.offsetMax = new Vector2(0, -5); - - // 创建运行测试按钮 - GameObject runButtonGO = new GameObject("RunTestButton"); - runButtonGO.transform.SetParent(buttonPanelGO.transform, false); - - RectTransform runButtonRect = runButtonGO.AddComponent(); - runButtonRect.anchorMin = new Vector2(0, 0); - runButtonRect.anchorMax = new Vector2(0.5f, 1); - runButtonRect.offsetMin = Vector2.zero; - runButtonRect.offsetMax = new Vector2(-5, 0); - - Image runButtonImage = runButtonGO.AddComponent(); - runButtonImage.color = new Color(0.2f, 0.8f, 0.2f, 1f); - - Button runButton = runButtonGO.AddComponent