diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/ConstantScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/ConstantScrollAlgorithm.cs
index 0bd8aa64c9..c957a84eb1 100644
--- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/ConstantScrollAlgorithm.cs
+++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/ConstantScrollAlgorithm.cs
@@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms
return -PositionAt(startTime, endTime, timeRange, scrollLength);
}
- public float PositionAt(double time, double currentTime, double timeRange, float scrollLength)
+ public float PositionAt(double time, double currentTime, double timeRange, float scrollLength, double? originTime = null)
=> (float)((time - currentTime) / timeRange * scrollLength);
public double TimeAt(float position, double currentTime, double timeRange, float scrollLength)
diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/IScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/IScrollAlgorithm.cs
index d2fb9e3531..f78509f919 100644
--- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/IScrollAlgorithm.cs
+++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/IScrollAlgorithm.cs
@@ -53,8 +53,9 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms
/// The current time.
/// The amount of visible time.
/// The absolute spatial length through .
+ /// The time to be used for control point lookups (ie. the parent's start time for nested hit objects).
/// The absolute spatial position.
- float PositionAt(double time, double currentTime, double timeRange, float scrollLength);
+ float PositionAt(double time, double currentTime, double timeRange, float scrollLength, double? originTime = null);
///
/// Computes the time which brings a point to a provided spatial position given the current time.
@@ -63,7 +64,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms
/// The current time.
/// The amount of visible time.
/// The absolute spatial length through .
- /// The time at which == .
+ /// The time at which == .
double TimeAt(float position, double currentTime, double timeRange, float scrollLength);
///
diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs
index 8fd7677a52..00bc7453d8 100644
--- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs
+++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs
@@ -34,8 +34,8 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms
return -PositionAt(startTime, endTime, timeRange, scrollLength);
}
- public float PositionAt(double time, double currentTime, double timeRange, float scrollLength)
- => (float)((time - currentTime) / timeRange * controlPointAt(time).Multiplier * scrollLength);
+ public float PositionAt(double time, double currentTime, double timeRange, float scrollLength, double? originTime = null)
+ => (float)((time - currentTime) / timeRange * controlPointAt(originTime ?? time).Multiplier * scrollLength);
public double TimeAt(float position, double currentTime, double timeRange, float scrollLength)
{
diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs
index 8d43185eac..774beb20c7 100644
--- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs
+++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs
@@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms
return (float)(objectLength * scrollLength);
}
- public float PositionAt(double time, double currentTime, double timeRange, float scrollLength)
+ public float PositionAt(double time, double currentTime, double timeRange, float scrollLength, double? originTime = null)
{
double timelineLength = relativePositionAt(time, timeRange) - relativePositionAt(currentTime, timeRange);
return (float)(timelineLength * scrollLength);
diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs
index 37da157cc1..443a37ab1c 100644
--- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs
+++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs
@@ -93,9 +93,9 @@ namespace osu.Game.Rulesets.UI.Scrolling
///
/// Given a time, return the position along the scrolling axis within this at time .
///
- public float PositionAtTime(double time, double currentTime)
+ public float PositionAtTime(double time, double currentTime, double? originTime = null)
{
- float scrollPosition = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength);
+ float scrollPosition = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength, originTime);
return axisInverted ? -scrollPosition : scrollPosition;
}
@@ -252,14 +252,14 @@ namespace osu.Game.Rulesets.UI.Scrolling
updateLayoutRecursive(obj);
// Nested hitobjects don't need to scroll, but they do need accurate positions and start lifetime
- updatePosition(obj, hitObject.HitObject.StartTime);
+ updatePosition(obj, hitObject.HitObject.StartTime, hitObject.HitObject.StartTime);
setComputedLifetimeStart(obj.Entry);
}
}
- private void updatePosition(DrawableHitObject hitObject, double currentTime)
+ private void updatePosition(DrawableHitObject hitObject, double currentTime, double? parentHitObjectStartTime = null)
{
- float position = PositionAtTime(hitObject.HitObject.StartTime, currentTime);
+ float position = PositionAtTime(hitObject.HitObject.StartTime, currentTime, parentHitObjectStartTime);
if (scrollingAxis == Direction.Horizontal)
hitObject.X = position;
diff --git a/osu.Game/Tests/Visual/ScrollingTestContainer.cs b/osu.Game/Tests/Visual/ScrollingTestContainer.cs
index cf7fe6e45d..87f4bb3f3b 100644
--- a/osu.Game/Tests/Visual/ScrollingTestContainer.cs
+++ b/osu.Game/Tests/Visual/ScrollingTestContainer.cs
@@ -99,7 +99,7 @@ namespace osu.Game.Tests.Visual
public float GetLength(double startTime, double endTime, double timeRange, float scrollLength)
=> implementation.GetLength(startTime, endTime, timeRange, scrollLength);
- public float PositionAt(double time, double currentTime, double timeRange, float scrollLength)
+ public float PositionAt(double time, double currentTime, double timeRange, float scrollLength, double? originTime = null)
=> implementation.PositionAt(time, currentTime, timeRange, scrollLength);
public double TimeAt(float position, double currentTime, double timeRange, float scrollLength)