Compute lifetime from entry in scrolling container

This commit is contained in:
ekrctb
2022-10-04 14:01:36 +09:00
parent f7f0aa1548
commit 5d80950eaf

View File

@ -5,10 +5,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Layout;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
@ -127,6 +127,16 @@ namespace osu.Game.Rulesets.UI.Scrolling
private float scrollLength => scrollingAxis == Direction.Horizontal ? DrawWidth : DrawHeight;
public override void Add(HitObjectLifetimeEntry entry)
{
// Scroll info is not available until loaded.
// The lifetime of all entries will be updated in the first Update.
if (IsLoaded)
setComputedLifetimeStart(entry);
base.Add(entry);
}
protected override void AddDrawable(HitObjectLifetimeEntry entry, DrawableHitObject drawable)
{
base.AddDrawable(entry, drawable);
@ -145,7 +155,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
private void invalidateHitObject(DrawableHitObject hitObject)
{
hitObject.LifetimeStart = computeOriginAdjustedLifetimeStart(hitObject);
layoutComputed.Remove(hitObject);
}
@ -157,10 +166,8 @@ namespace osu.Game.Rulesets.UI.Scrolling
layoutComputed.Clear();
// Reset lifetime to the conservative estimation.
// If a drawable becomes alive by this lifetime, its lifetime will be updated to a more precise lifetime in the next update.
foreach (var entry in Entries)
entry.SetInitialLifetime();
setComputedLifetimeStart(entry);
scrollingInfo.Algorithm.Reset();
@ -187,38 +194,46 @@ namespace osu.Game.Rulesets.UI.Scrolling
}
}
private double computeOriginAdjustedLifetimeStart(DrawableHitObject hitObject)
/// <summary>
/// Get a conservative maximum bounding box of a <see cref="DrawableHitObject"/> corresponding to <paramref name="entry"/>.
/// It is used to calculate when the hit object appears.
/// </summary>
protected virtual RectangleF GetConservativeBoundingBox(HitObjectLifetimeEntry entry) => new RectangleF().Inflate(100);
private double computeDisplayStartTime(HitObjectLifetimeEntry entry)
{
// Origin position may be relative to the parent size
Debug.Assert(hitObject.Parent != null);
RectangleF boundingBox = GetConservativeBoundingBox(entry);
float startOffset = 0;
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;
case ScrollingDirection.Right:
startOffset = boundingBox.Right;
break;
case ScrollingDirection.Down:
originAdjustment = hitObject.DrawHeight - hitObject.OriginPosition.Y;
startOffset = boundingBox.Bottom;
break;
case ScrollingDirection.Left:
originAdjustment = hitObject.OriginPosition.X;
startOffset = -boundingBox.Left;
break;
case ScrollingDirection.Right:
originAdjustment = hitObject.DrawWidth - hitObject.OriginPosition.X;
case ScrollingDirection.Up:
startOffset = -boundingBox.Top;
break;
}
double computedStartTime = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, originAdjustment, timeRange.Value, scrollLength);
return scrollingInfo.Algorithm.GetDisplayStartTime(entry.HitObject.StartTime, startOffset, timeRange.Value, scrollLength);
}
private void setComputedLifetimeStart(HitObjectLifetimeEntry entry)
{
double computedStartTime = computeDisplayStartTime(entry);
// always load the hitobject before its first judgement offset
return Math.Min(hitObject.HitObject.StartTime - hitObject.MaximumJudgementOffset, computedStartTime);
double judgementOffset = entry.HitObject.HitWindows?.WindowFor(Scoring.HitResult.Miss) ?? 0;
entry.LifetimeStart = Math.Min(entry.HitObject.StartTime - judgementOffset, computedStartTime);
}
private void updateLayoutRecursive(DrawableHitObject hitObject)