mirror of
https://github.com/osukey/osukey.git
synced 2025-05-29 17:37:23 +09:00
Rewrite hit object management, take three
This commit is contained in:
parent
7f6e4d5b21
commit
e34a205104
@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// If this <see cref="HitObjectContainer"/> uses pooled objects, this represents the time when the <see cref="HitObject"/>s become alive.
|
/// If this <see cref="HitObjectContainer"/> uses pooled objects, this represents the time when the <see cref="HitObject"/>s become alive.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
internal event Action<HitObject> HitObjectUsageBegan;
|
internal event Action<DrawableHitObject> HitObjectUsageBegan;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked when a <see cref="HitObject"/> becomes unused by a <see cref="DrawableHitObject"/>.
|
/// Invoked when a <see cref="HitObject"/> becomes unused by a <see cref="DrawableHitObject"/>.
|
||||||
@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// If this <see cref="HitObjectContainer"/> uses pooled objects, this represents the time when the <see cref="HitObject"/>s become dead.
|
/// If this <see cref="HitObjectContainer"/> uses pooled objects, this represents the time when the <see cref="HitObject"/>s become dead.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
internal event Action<HitObject> HitObjectUsageFinished;
|
internal event Action<DrawableHitObject> HitObjectUsageFinished;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of time prior to the current time within which <see cref="HitObject"/>s should be considered alive.
|
/// The amount of time prior to the current time within which <see cref="HitObject"/>s should be considered alive.
|
||||||
@ -115,7 +115,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
bindStartTime(drawable);
|
bindStartTime(drawable);
|
||||||
AddInternal(drawableMap[entry] = drawable, false);
|
AddInternal(drawableMap[entry] = drawable, false);
|
||||||
|
|
||||||
HitObjectUsageBegan?.Invoke(entry.HitObject);
|
HitObjectUsageBegan?.Invoke(drawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeDrawable(HitObjectLifetimeEntry entry)
|
private void removeDrawable(HitObjectLifetimeEntry entry)
|
||||||
@ -132,7 +132,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
unbindStartTime(drawable);
|
unbindStartTime(drawable);
|
||||||
RemoveInternal(drawable);
|
RemoveInternal(drawable);
|
||||||
|
|
||||||
HitObjectUsageFinished?.Invoke(entry.HitObject);
|
HitObjectUsageFinished?.Invoke(drawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -91,8 +91,8 @@ namespace osu.Game.Rulesets.UI
|
|||||||
{
|
{
|
||||||
h.NewResult += (d, r) => NewResult?.Invoke(d, r);
|
h.NewResult += (d, r) => NewResult?.Invoke(d, r);
|
||||||
h.RevertResult += (d, r) => RevertResult?.Invoke(d, r);
|
h.RevertResult += (d, r) => RevertResult?.Invoke(d, r);
|
||||||
h.HitObjectUsageBegan += o => HitObjectUsageBegan?.Invoke(o);
|
h.HitObjectUsageBegan += o => HitObjectUsageBegan?.Invoke(o.HitObject);
|
||||||
h.HitObjectUsageFinished += o => HitObjectUsageFinished?.Invoke(o);
|
h.HitObjectUsageFinished += o => HitObjectUsageFinished?.Invoke(o.HitObject);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,11 +17,16 @@ 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>();
|
||||||
|
|
||||||
// If a hit object is not in this set, the position and the size should be updated when the hit object becomes alive.
|
// Tracks all `DrawableHitObject` (nested or not) applied a `HitObject`.
|
||||||
private readonly HashSet<DrawableHitObject> layoutComputedHitObjects = new HashSet<DrawableHitObject>();
|
// It dynamically changes based on approximate lifetime when a pooling is used.
|
||||||
|
private readonly HashSet<DrawableHitObject> hitObjectApplied = new HashSet<DrawableHitObject>();
|
||||||
|
|
||||||
// Used to recompute all lifetime when `layoutCache` becomes invalid
|
// The lifetime of a hit object in this will be computed in next update.
|
||||||
private readonly HashSet<DrawableHitObject> allHitObjects = new HashSet<DrawableHitObject>();
|
private readonly HashSet<DrawableHitObject> toComputeLifetime = new HashSet<DrawableHitObject>();
|
||||||
|
|
||||||
|
// The layout (length if IHasDuration, and nested object positions) of a hit object *not* in this set will be computed in next updated.
|
||||||
|
// Only objects in `AliveObjects` are considered, to prevent a massive recomputation when scrolling speed or something changes.
|
||||||
|
private readonly HashSet<DrawableHitObject> layoutComputed = new HashSet<DrawableHitObject>();
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IScrollingInfo scrollingInfo { get; set; }
|
private IScrollingInfo scrollingInfo { get; set; }
|
||||||
@ -34,6 +39,9 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
AddLayout(layoutCache);
|
AddLayout(layoutCache);
|
||||||
|
|
||||||
|
HitObjectUsageBegan += onHitObjectUsageBegin;
|
||||||
|
HitObjectUsageFinished += onHitObjectUsageFinished;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -50,7 +58,9 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
{
|
{
|
||||||
base.Clear(disposeChildren);
|
base.Clear(disposeChildren);
|
||||||
|
|
||||||
layoutComputedHitObjects.Clear();
|
hitObjectApplied.Clear();
|
||||||
|
toComputeLifetime.Clear();
|
||||||
|
layoutComputed.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -145,21 +155,20 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private void onHitObjectUsageBegin(DrawableHitObject hitObject)
|
||||||
/// Invalidate the cache of the layout of this hit object.
|
|
||||||
/// </summary>
|
|
||||||
public void InvalidateDrawableHitObject(DrawableHitObject hitObject)
|
|
||||||
{
|
{
|
||||||
// Lifetime computation is delayed to the next update because `scrollLength` may not be valid here.
|
// Lifetime computation is delayed until next update because
|
||||||
// Layout computation will be delayed to when the object becomes alive.
|
// when the hit object is not pooled this container is not loaded here and `scrollLength` cannot be computed.
|
||||||
// An assumption is that a hit object layout update (setting `Height` or `Width`) won't affect its lifetime but
|
hitObjectApplied.Add(hitObject);
|
||||||
// this is satisfied in practice because otherwise the hit object won't be aligned to its `StartTime`.
|
toComputeLifetime.Add(hitObject);
|
||||||
|
layoutComputed.Remove(hitObject);
|
||||||
|
}
|
||||||
|
|
||||||
layoutCache.Invalidate();
|
private void onHitObjectUsageFinished(DrawableHitObject hitObject)
|
||||||
|
{
|
||||||
allHitObjects.Add(hitObject);
|
hitObjectApplied.Remove(hitObject);
|
||||||
|
toComputeLifetime.Remove(hitObject);
|
||||||
layoutComputedHitObjects.Remove(hitObject);
|
layoutComputed.Remove(hitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float scrollLength;
|
private float scrollLength;
|
||||||
@ -170,11 +179,10 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
|
|
||||||
if (!layoutCache.IsValid)
|
if (!layoutCache.IsValid)
|
||||||
{
|
{
|
||||||
// this.Objects cannot be used as it doesn't contain nested objects
|
foreach (var hitObject in hitObjectApplied)
|
||||||
foreach (var hitObject in allHitObjects)
|
toComputeLifetime.Add(hitObject);
|
||||||
hitObject.LifetimeStart = computeOriginAdjustedLifetimeStart(hitObject);
|
|
||||||
|
|
||||||
layoutComputedHitObjects.Clear();
|
layoutComputed.Clear();
|
||||||
|
|
||||||
scrollingInfo.Algorithm.Reset();
|
scrollingInfo.Algorithm.Reset();
|
||||||
|
|
||||||
@ -193,14 +201,21 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
layoutCache.Validate();
|
layoutCache.Validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var hitObject in toComputeLifetime)
|
||||||
|
hitObject.LifetimeStart = computeOriginAdjustedLifetimeStart(hitObject);
|
||||||
|
|
||||||
|
toComputeLifetime.Clear();
|
||||||
|
|
||||||
|
// An assumption is that this update won't affect lifetime,
|
||||||
|
// but this is satisfied in practice because otherwise the hit object won't be aligned to its `StartTime`.
|
||||||
foreach (var obj in AliveObjects)
|
foreach (var obj in AliveObjects)
|
||||||
{
|
{
|
||||||
if (layoutComputedHitObjects.Contains(obj))
|
if (layoutComputed.Contains(obj))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
updateLayoutRecursive(obj);
|
updateLayoutRecursive(obj);
|
||||||
|
|
||||||
layoutComputedHitObjects.Add(obj);
|
layoutComputed.Add(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,12 +24,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
Direction.BindTo(ScrollingInfo.Direction);
|
Direction.BindTo(ScrollingInfo.Direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnNewDrawableHitObject(DrawableHitObject drawableHitObject)
|
|
||||||
{
|
|
||||||
drawableHitObject.HitObjectApplied +=
|
|
||||||
((ScrollingHitObjectContainer)HitObjectContainer).InvalidateDrawableHitObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Given a position in screen space, return the time within this column.
|
/// Given a position in screen space, return the time within this column.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user