Merge pull request #3851 from ekrctb/use-lifetime-optimization

Do less work for dead drawables in gameplay
This commit is contained in:
Dan Balasescu 2019-02-27 16:46:47 +09:00 committed by GitHub
commit e5eab11a2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 47 additions and 9 deletions

View File

@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
/// <summary>
/// Connects hit objects visually, for example with follow points.
/// </summary>
public abstract class ConnectionRenderer<T> : Container
public abstract class ConnectionRenderer<T> : LifetimeManagementContainer
where T : HitObject
{
/// <summary>

View File

@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
private void update()
{
Clear();
ClearInternal();
if (hitObjects == null)
return;
@ -86,7 +86,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
FollowPoint fp;
Add(fp = new FollowPoint
AddInternal(fp = new FollowPoint
{
Position = pointStartPosition,
Rotation = rotation,

View File

@ -139,6 +139,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt));
ApproachCircle.ScaleTo(1.1f, HitObject.TimePreempt);
ApproachCircle.Expire(true);
}
protected override void UpdateCurrentState(ArmedState state)

View File

@ -12,6 +12,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public class ApproachCircle : Container
{
public override bool RemoveWhenNotAlive => false;
public ApproachCircle()
{
Anchor = Anchor.Centre;

View File

@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.UI
{
public class OsuPlayfield : Playfield
{
private readonly Container approachCircles;
private readonly ApproachCircleProxyContainer approachCircles;
private readonly JudgementContainer<DrawableOsuJudgement> judgementLayer;
private readonly ConnectionRenderer<OsuHitObject> connectionLayer;
@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.UI
Depth = 1,
},
HitObjectContainer,
approachCircles = new Container
approachCircles = new ApproachCircleProxyContainer
{
RelativeSizeAxes = Axes.Both,
Depth = -1,
@ -60,11 +60,25 @@ namespace osu.Game.Rulesets.Osu.UI
var c = h as IDrawableHitObjectWithProxiedApproach;
if (c != null)
approachCircles.Add(c.ProxiedLayer.CreateProxy());
{
var original = c.ProxiedLayer;
// Hitobjects only have lifetimes set on LoadComplete. For nested hitobjects (e.g. SliderHeads), this only happens when the parenting slider becomes visible.
// This delegation is required to make sure that the approach circles for those not-yet-loaded objects aren't added prematurely.
original.OnLoadComplete += addApproachCircleProxy;
}
base.Add(h);
}
private void addApproachCircleProxy(Drawable d)
{
var proxy = d.CreateProxy();
proxy.LifetimeStart = d.LifetimeStart;
proxy.LifetimeEnd = d.LifetimeEnd;
approachCircles.Add(proxy);
}
public override void PostProcess()
{
connectionLayer.HitObjects = HitObjectContainer.Objects.Select(d => d.HitObject).OfType<OsuHitObject>();
@ -86,5 +100,10 @@ namespace osu.Game.Rulesets.Osu.UI
}
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => HitObjectContainer.ReceivePositionalInputAt(screenSpacePos);
private class ApproachCircleProxyContainer : LifetimeManagementContainer
{
public void Add(Drawable approachCircleProxy) => AddInternal(approachCircleProxy);
}
}
}

View File

@ -220,6 +220,16 @@ namespace osu.Game.Rulesets.Objects.Drawables
OnNewResult?.Invoke(this, Result);
}
/// <summary>
/// Will called at least once after the <see cref="LifetimeEnd"/> of this <see cref="DrawableHitObject"/> has been passed.
/// </summary>
internal void OnLifetimeEnd()
{
foreach (var nested in NestedHitObjects)
nested.OnLifetimeEnd();
UpdateResult(false);
}
/// <summary>
/// Processes this <see cref="DrawableHitObject"/>, checking if a scoring result has occurred.
/// </summary>

View File

@ -9,7 +9,7 @@ using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.UI
{
public class HitObjectContainer : CompositeDrawable
public class HitObjectContainer : LifetimeManagementContainer
{
public IEnumerable<DrawableHitObject> Objects => InternalChildren.Cast<DrawableHitObject>().OrderBy(h => h.HitObject.StartTime);
public IEnumerable<DrawableHitObject> AliveObjects => AliveInternalChildren.Cast<DrawableHitObject>().OrderBy(h => h.HitObject.StartTime);
@ -31,5 +31,11 @@ namespace osu.Game.Rulesets.UI
int i = yObj.HitObject.StartTime.CompareTo(xObj.HitObject.StartTime);
return i == 0 ? CompareReverseChildID(x, y) : i;
}
protected override void OnChildLifetimeBoundaryCrossed(LifetimeBoundaryCrossedEvent e)
{
if (e.Kind == LifetimeBoundaryKind.End && e.Direction == LifetimeBoundaryCrossingDirection.Forward && e.Child is DrawableHitObject hitObject)
hitObject.OnLifetimeEnd();
}
}
}

View File

@ -7,7 +7,7 @@ using osu.Framework.Graphics.Containers;
namespace osu.Game.Storyboards.Drawables
{
public class DrawableStoryboardLayer : Container
public class DrawableStoryboardLayer : LifetimeManagementContainer
{
public StoryboardLayer Layer { get; private set; }
public bool Enabled;
@ -29,7 +29,7 @@ namespace osu.Game.Storyboards.Drawables
foreach (var element in Layer.Elements)
{
if (element.IsDrawable)
Add(element.CreateDrawable());
AddInternal(element.CreateDrawable());
}
}
}