diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 857929ff9e..04b4374fc4 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.UI.Scrolling private void computeLifetimeStartRecursive(DrawableHitObject hitObject) { - hitObject.LifetimeStart = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, timeRange.Value); + hitObject.LifetimeStart = computeOriginAdjustedLifetimeStart(hitObject); foreach (var obj in hitObject.NestedHitObjects) computeLifetimeStartRecursive(obj); @@ -108,6 +108,35 @@ namespace osu.Game.Rulesets.UI.Scrolling private readonly Dictionary hitObjectInitialStateCache = new Dictionary(); + private double computeOriginAdjustedLifetimeStart(DrawableHitObject hitObject) + { + float originAdjustment = 0.0f; + + // calculate the dimension of the part of the hitobject that should already be visible + // when the hitobject origin first appears inside the scrolling container + switch (direction.Value) + { + case ScrollingDirection.Up: + originAdjustment = hitObject.OriginPosition.Y; + break; + + case ScrollingDirection.Down: + originAdjustment = hitObject.DrawHeight - hitObject.OriginPosition.Y; + break; + + case ScrollingDirection.Left: + originAdjustment = hitObject.OriginPosition.X; + break; + + case ScrollingDirection.Right: + originAdjustment = hitObject.DrawWidth - hitObject.OriginPosition.X; + break; + } + + var adjustedStartTime = scrollingInfo.Algorithm.TimeAt(-originAdjustment, hitObject.HitObject.StartTime, timeRange.Value, scrollLength); + return scrollingInfo.Algorithm.GetDisplayStartTime(adjustedStartTime, timeRange.Value); + } + // Cant use AddOnce() since the delegate is re-constructed every invocation private void computeInitialStateRecursive(DrawableHitObject hitObject) => hitObject.Schedule(() => {