diff --git a/src/LitMotion/Assets/LitMotion/Runtime/DelayType.cs b/src/LitMotion/Assets/LitMotion/Runtime/DelayType.cs
new file mode 100644
index 00000000..1e97dfd8
--- /dev/null
+++ b/src/LitMotion/Assets/LitMotion/Runtime/DelayType.cs
@@ -0,0 +1,17 @@
+namespace LitMotion
+{
+ ///
+ /// Specifies the behavior of WithDelay.
+ ///
+ public enum DelayType : byte
+ {
+ ///
+ /// Delay when starting playback
+ ///
+ FirstLoop = 0,
+ ///
+ /// Delay every loop
+ ///
+ EveryLoop = 1,
+ }
+}
\ No newline at end of file
diff --git a/src/LitMotion/Assets/LitMotion/Runtime/DelayType.cs.meta b/src/LitMotion/Assets/LitMotion/Runtime/DelayType.cs.meta
new file mode 100644
index 00000000..67791698
--- /dev/null
+++ b/src/LitMotion/Assets/LitMotion/Runtime/DelayType.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ede4abfbaa71b475ab0e832d38c4495a
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs
index c13d71ce..d07a41b4 100644
--- a/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs
+++ b/src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionData.cs
@@ -21,6 +21,7 @@ public struct MotionData
public MotionTimeKind TimeKind;
public float Delay;
public int Loops;
+ public DelayType DelayType;
public LoopType LoopType;
public TValue StartValue;
diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilder.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilder.cs
index 32118ab6..870f2b18 100644
--- a/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilder.cs
+++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionBuilder.cs
@@ -28,6 +28,7 @@ public static void Return(MotionBuilderBuffer buffer)
buffer.Duration = default;
buffer.Ease = default;
buffer.Delay = default;
+ buffer.DelayType = default;
buffer.Loops = 1;
buffer.LoopType = default;
buffer.StartValue = default;
@@ -50,6 +51,7 @@ public static void Return(MotionBuilderBuffer buffer)
public float Duration;
public Ease Ease;
public float Delay;
+ public DelayType DelayType;
public int Loops = 1;
public LoopType LoopType;
@@ -111,6 +113,21 @@ public readonly MotionBuilder WithDelay(float delay)
return this;
}
+ ///
+ /// Specify the delay time when the motion starts.
+ ///
+ /// Delay time (seconds)
+ /// Delay type
+ /// This builder to allow chaining multiple method calls.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public readonly MotionBuilder WithDelay(float delay, DelayType delayType)
+ {
+ CheckBuffer();
+ buffer.Delay = delay;
+ buffer.DelayType = delayType;
+ return this;
+ }
+
///
/// Specify the number of times the motion is repeated. If specified as less than 0, the motion will continue to play until manually completed or canceled.
///
@@ -344,6 +361,7 @@ internal MotionData BuildMotionData()
Duration = buffer.Duration,
Ease = buffer.Ease,
Delay = buffer.Delay,
+ DelayType = buffer.DelayType,
Loops = buffer.Loops,
LoopType = buffer.LoopType,
Status = MotionStatus.Scheduled,
diff --git a/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs b/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs
index 8cb1276e..df7d0a23 100644
--- a/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs
+++ b/src/LitMotion/Assets/LitMotion/Runtime/MotionUpdateJob.cs
@@ -42,42 +42,77 @@ public void Execute([AssumeRange(0, int.MaxValue)] int index)
};
var motionTime = currentTime - ptr->StartTime;
- var time = motionTime - ptr->Delay;
double t;
bool isCompleted;
+ bool isDelayed;
int completedLoops;
int clampedCompletedLoops;
if (Hint.Unlikely(ptr->Duration <= 0f))
{
- isCompleted = time > 0f;
- if (isCompleted)
+ if (ptr->DelayType == DelayType.FirstLoop || ptr->Delay == 0f)
{
- t = 1f;
- completedLoops = ptr->Loops;
+ var time = motionTime - ptr->Delay;
+ isCompleted = ptr->Loops >= 0 && time > 0f;
+ if (isCompleted)
+ {
+ t = 1f;
+ completedLoops = ptr->Loops;
+ }
+ else
+ {
+ t = 0f;
+ completedLoops = time < 0f ? -1 : 0;
+ }
+ clampedCompletedLoops = ptr->Loops < 0 ? math.max(0, completedLoops) : math.clamp(completedLoops, 0, ptr->Loops);
+ isDelayed = time < 0;
}
else
{
- t = 0f;
- completedLoops = time < 0f ? -1 : 0;
+ completedLoops = (int)math.floor(motionTime / ptr->Delay);
+ clampedCompletedLoops = ptr->Loops < 0 ? math.max(0, completedLoops) : math.clamp(completedLoops, 0, ptr->Loops);
+ isCompleted = ptr->Loops >= 0 && clampedCompletedLoops > ptr->Loops - 1;
+ isDelayed = !isCompleted;
+ t = isCompleted ? 1f : 0f;
}
- clampedCompletedLoops = ptr->Loops < 0 ? math.max(0, completedLoops) : math.clamp(completedLoops, 0, ptr->Loops);
}
else
{
- completedLoops = (int)math.floor(time / ptr->Duration);
- clampedCompletedLoops = ptr->Loops < 0 ? math.max(0, completedLoops) : math.clamp(completedLoops, 0, ptr->Loops);
- isCompleted = ptr->Loops >= 0 && clampedCompletedLoops > ptr->Loops - 1;
-
- if (isCompleted)
+ if (ptr->DelayType == DelayType.FirstLoop)
{
- t = 1f;
+ var time = motionTime - ptr->Delay;
+ completedLoops = (int)math.floor(time / ptr->Duration);
+ clampedCompletedLoops = ptr->Loops < 0 ? math.max(0, completedLoops) : math.clamp(completedLoops, 0, ptr->Loops);
+ isCompleted = ptr->Loops >= 0 && clampedCompletedLoops > ptr->Loops - 1;
+ isDelayed = time < 0f;
+
+ if (isCompleted)
+ {
+ t = 1f;
+ }
+ else
+ {
+ var currentLoopTime = time - ptr->Duration * clampedCompletedLoops;
+ t = math.clamp(currentLoopTime / ptr->Duration, 0f, 1f);
+ }
}
else
{
- var currentLoopTime = time - ptr->Duration * clampedCompletedLoops;
- t = math.clamp(currentLoopTime / ptr->Duration, 0f, 1f);
+ var currentLoopTime = math.fmod(motionTime, ptr->Duration + ptr->Delay) - ptr->Delay;
+ completedLoops = (int)math.floor(motionTime / (ptr->Duration + ptr->Delay));
+ clampedCompletedLoops = ptr->Loops < 0 ? math.max(0, completedLoops) : math.clamp(completedLoops, 0, ptr->Loops);
+ isCompleted = ptr->Loops >= 0 && clampedCompletedLoops > ptr->Loops - 1;
+ isDelayed = currentLoopTime < 0;
+
+ if (isCompleted)
+ {
+ t = 1f;
+ }
+ else
+ {
+ t = math.clamp(currentLoopTime / ptr->Duration, 0f, 1f);
+ }
}
}
@@ -97,11 +132,15 @@ public void Execute([AssumeRange(0, int.MaxValue)] int index)
break;
}
- if (ptr->Loops > 0 && time >= ptr->Duration * ptr->Loops)
+ var totalDuration = ptr->DelayType == DelayType.FirstLoop
+ ? ptr->Delay + ptr->Duration * ptr->Loops
+ : (ptr->Delay + ptr->Duration) * ptr->Loops;
+
+ if (ptr->Loops > 0 && motionTime >= totalDuration)
{
ptr->Status = MotionStatus.Completed;
}
- else if (motionTime < ptr->Delay)
+ else if (isDelayed)
{
ptr->Status = MotionStatus.Delayed;
}
diff --git a/src/LitMotion/Assets/LitMotion/Tests/Runtime/DelayTest.cs b/src/LitMotion/Assets/LitMotion/Tests/Runtime/DelayTest.cs
index 11e201f1..7fef9f4c 100644
--- a/src/LitMotion/Assets/LitMotion/Tests/Runtime/DelayTest.cs
+++ b/src/LitMotion/Assets/LitMotion/Tests/Runtime/DelayTest.cs
@@ -10,23 +10,47 @@ public class DelayTest
[UnityTest]
public IEnumerator Test_Delay()
{
- var t = Time.time;
+ var t = Time.timeAsDouble;
yield return LMotion.Create(0f, 1f, 0.5f)
.WithDelay(0.5f)
- .RunWithoutBinding()
+ .BindToUnityLogger()
.ToYieldInteraction();
- Assert.IsTrue(Time.time - t >= 1f);
+ Assert.That(Time.timeAsDouble - t, Is.GreaterThan(0.95).And.LessThan(1.1));
}
[UnityTest]
public IEnumerator Test_Delay_WithZeroDuration()
{
- var t = Time.time;
+ var t = Time.timeAsDouble;
yield return LMotion.Create(0f, 1f, 0f)
.WithDelay(1f)
- .RunWithoutBinding()
+ .BindToUnityLogger()
.ToYieldInteraction();
- Assert.IsTrue(Time.time - t >= 1f);
+ Assert.That(Time.timeAsDouble - t, Is.GreaterThan(0.95).And.LessThan(1.1));
+ }
+
+ [UnityTest]
+ public IEnumerator Test_Delay_EveryLoop()
+ {
+ var t = Time.timeAsDouble;
+ yield return LMotion.Create(0f, 1f, 0.5f)
+ .WithLoops(2)
+ .WithDelay(0.5f, DelayType.EveryLoop)
+ .BindToUnityLogger()
+ .ToYieldInteraction();
+ Assert.That(Time.timeAsDouble - t, Is.GreaterThan(1.95).And.LessThan(2.1));
+ }
+
+ [UnityTest]
+ public IEnumerator Test_Delay_EveryLoop_WithZeroDuration()
+ {
+ var t = Time.timeAsDouble;
+ yield return LMotion.Create(0f, 1f, 0f)
+ .WithLoops(3)
+ .WithDelay(0.5f, DelayType.EveryLoop)
+ .BindToUnityLogger()
+ .ToYieldInteraction();
+ Assert.That(Time.timeAsDouble - t, Is.GreaterThan(1.45).And.LessThan(1.6));
}
}
}
\ No newline at end of file