diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/ConnectionRenderer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/ConnectionRenderer.cs
index f15be94b8a..dfbb503cbf 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/ConnectionRenderer.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/ConnectionRenderer.cs
@@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
///
/// Connects hit objects visually, for example with follow points.
///
- public abstract class ConnectionRenderer : Container
+ public abstract class ConnectionRenderer : LifetimeManagementContainer
where T : HitObject
{
///
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs
index 61219d9bb9..ebcf6b33ba 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs
@@ -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,
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
index 9b562745fa..c5d5717618 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
@@ -118,6 +118,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)
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs
index 07d99bda42..59d7b24ca9 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs
@@ -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;
diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
index 3399fdb9a0..732ba5d7e8 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
@@ -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 judgementLayer;
private readonly ConnectionRenderer 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,23 @@ namespace osu.Game.Rulesets.Osu.UI
var c = h as IDrawableHitObjectWithProxiedApproach;
if (c != null)
- approachCircles.Add(c.ProxiedLayer.CreateProxy());
+ {
+ var original = c.ProxiedLayer;
+ // lifetime is set on LoadComplete so wait until it.
+ 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();
@@ -86,5 +98,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);
+ }
}
}
diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs
index 261132c56b..73d44cca13 100644
--- a/osu.Game/Rulesets/UI/HitObjectContainer.cs
+++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs
@@ -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 Objects => InternalChildren.Cast().OrderBy(h => h.HitObject.StartTime);
public IEnumerable AliveObjects => AliveInternalChildren.Cast().OrderBy(h => h.HitObject.StartTime);
diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs
index 74eaab33ca..e06d226adf 100644
--- a/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs
+++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs
@@ -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());
}
}
}