Use entry to calculate lifetime in ScrollingHOC

DHOs cannot be used to calculate lifetime, it is not created before the entry became alive.
This commit is contained in:
ekrctb
2021-04-29 15:04:32 +09:00
parent c83c804057
commit 632bb70e0f

View File

@ -5,7 +5,9 @@ using System.Collections.Generic;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Layout; using osu.Framework.Layout;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osuTK; using osuTK;
@ -17,16 +19,18 @@ namespace osu.Game.Rulesets.UI.Scrolling
private readonly IBindable<double> timeRange = new BindableDouble(); private readonly IBindable<double> timeRange = new BindableDouble();
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>(); private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
/// <summary>
/// Hit objects which require lifetime computation in the next update call.
/// </summary>
private readonly HashSet<DrawableHitObject> toComputeLifetime = new HashSet<DrawableHitObject>();
/// <summary> /// <summary>
/// A set containing all <see cref="HitObjectContainer.AliveObjects"/> which have an up-to-date layout. /// A set containing all <see cref="HitObjectContainer.AliveObjects"/> which have an up-to-date layout.
/// </summary> /// </summary>
private readonly HashSet<DrawableHitObject> layoutComputed = new HashSet<DrawableHitObject>(); private readonly HashSet<DrawableHitObject> layoutComputed = new HashSet<DrawableHitObject>();
/// <summary>
/// A conservative estimate of maximum bounding box of a <see cref="DrawableHitObject"/>
/// with respect to the start time position of the hit object.
/// It is used to calculate when the object appears inbound.
/// </summary>
protected virtual RectangleF GetDrawRectangle(HitObjectLifetimeEntry entry) => new RectangleF().Inflate(100);
[Resolved] [Resolved]
private IScrollingInfo scrollingInfo { get; set; } private IScrollingInfo scrollingInfo { get; set; }
@ -54,7 +58,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
{ {
base.Clear(); base.Clear();
toComputeLifetime.Clear();
layoutComputed.Clear(); layoutComputed.Clear();
} }
@ -166,7 +169,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
private void onRemoveRecursive(DrawableHitObject hitObject) private void onRemoveRecursive(DrawableHitObject hitObject)
{ {
toComputeLifetime.Remove(hitObject);
layoutComputed.Remove(hitObject); layoutComputed.Remove(hitObject);
hitObject.DefaultsApplied -= invalidateHitObject; hitObject.DefaultsApplied -= invalidateHitObject;
@ -175,14 +177,11 @@ namespace osu.Game.Rulesets.UI.Scrolling
onRemoveRecursive(nested); onRemoveRecursive(nested);
} }
/// <summary>
/// Make this <see cref="DrawableHitObject"/> lifetime and layout computed in next update.
/// </summary>
private void invalidateHitObject(DrawableHitObject hitObject) private void invalidateHitObject(DrawableHitObject hitObject)
{ {
// Lifetime computation is delayed until next update because if (hitObject.ParentHitObject == null)
// when the hit object is not pooled this container is not loaded here and `scrollLength` cannot be computed. updateLifetime(hitObject.Entry);
toComputeLifetime.Add(hitObject);
layoutComputed.Remove(hitObject); layoutComputed.Remove(hitObject);
} }
@ -194,13 +193,8 @@ namespace osu.Game.Rulesets.UI.Scrolling
if (!layoutCache.IsValid) if (!layoutCache.IsValid)
{ {
toComputeLifetime.Clear(); foreach (var entry in Entries)
updateLifetime(entry);
foreach (var hitObject in Objects)
{
if (hitObject.HitObject != null)
toComputeLifetime.Add(hitObject);
}
layoutComputed.Clear(); layoutComputed.Clear();
@ -220,11 +214,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
layoutCache.Validate(); layoutCache.Validate();
} }
foreach (var hitObject in toComputeLifetime)
hitObject.LifetimeStart = computeOriginAdjustedLifetimeStart(hitObject);
toComputeLifetime.Clear();
} }
protected override void UpdateAfterChildrenLife() protected override void UpdateAfterChildrenLife()
@ -247,32 +236,31 @@ namespace osu.Game.Rulesets.UI.Scrolling
} }
} }
private double computeOriginAdjustedLifetimeStart(DrawableHitObject hitObject) private void updateLifetime(HitObjectLifetimeEntry entry)
{ {
float originAdjustment = 0.0f; var rectangle = GetDrawRectangle(entry);
float startOffset = 0;
// 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) switch (direction.Value)
{ {
case ScrollingDirection.Up: case ScrollingDirection.Right:
originAdjustment = hitObject.OriginPosition.Y; startOffset = rectangle.Right;
break; break;
case ScrollingDirection.Down: case ScrollingDirection.Down:
originAdjustment = hitObject.DrawHeight - hitObject.OriginPosition.Y; startOffset = rectangle.Bottom;
break; break;
case ScrollingDirection.Left: case ScrollingDirection.Left:
originAdjustment = hitObject.OriginPosition.X; startOffset = -rectangle.Left;
break; break;
case ScrollingDirection.Right: case ScrollingDirection.Up:
originAdjustment = hitObject.DrawWidth - hitObject.OriginPosition.X; startOffset = -rectangle.Top;
break; break;
} }
return scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, originAdjustment, timeRange.Value, scrollLength); entry.LifetimeStart = scrollingInfo.Algorithm.GetDisplayStartTime(entry.HitObject.StartTime, startOffset, timeRange.Value, scrollLength);
} }
private void updateLayoutRecursive(DrawableHitObject hitObject) private void updateLayoutRecursive(DrawableHitObject hitObject)