From 576f462f59e9cd6110582a611a01a25ebc71c057 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Nov 2022 00:53:38 +0900 Subject: [PATCH 1/6] Add pooling support to `BarHitErrorMeter` --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index e7b2ce1672..5fca8e2c51 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -11,6 +11,7 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Pooling; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; @@ -23,6 +24,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD.HitErrorMeters { + [Cached] public class BarHitErrorMeter : HitErrorMeter { private const int judgement_line_width = 14; @@ -44,6 +46,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [SettingSource("Label style", "How to show early/late extremities")] public Bindable LabelStyle { get; } = new Bindable(LabelStyles.Icons); + private readonly DrawablePool judgementLinePool = new DrawablePool(50, 100); + private SpriteIcon arrow; private UprightAspectMaintainingContainer labelEarly; private UprightAspectMaintainingContainer labelLate; @@ -88,6 +92,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Margin = new MarginPadding(2), Children = new Drawable[] { + judgementLinePool, colourBars = new Container { Name = "colour axis", @@ -403,11 +408,12 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } - judgementsContainer.Add(new JudgementLine + judgementLinePool.Get(drawableJudgement => { - JudgementLineThickness = { BindTarget = JudgementLineThickness }, - Y = getRelativeJudgementPosition(judgement.TimeOffset), - Colour = GetColourForHitResult(judgement.Type), + drawableJudgement.Y = getRelativeJudgementPosition(judgement.TimeOffset); + drawableJudgement.Colour = GetColourForHitResult(judgement.Type); + + judgementsContainer.Add(drawableJudgement); }); arrow.MoveToY( @@ -417,7 +423,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private float getRelativeJudgementPosition(double value) => Math.Clamp((float)((value / maxHitWindow) + 1) / 2, 0, 1); - internal class JudgementLine : CompositeDrawable + internal class JudgementLine : PoolableDrawable { public readonly BindableNumber JudgementLineThickness = new BindableFloat(); @@ -437,18 +443,27 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters }; } + [Resolved] + private BarHitErrorMeter barHitErrorMeter { get; set; } + protected override void LoadComplete() { + base.LoadComplete(); + + JudgementLineThickness.BindTo(barHitErrorMeter.JudgementLineThickness); + JudgementLineThickness.BindValueChanged(thickness => Height = thickness.NewValue, true); + } + + protected override void PrepareForUse() + { + base.PrepareForUse(); + const int judgement_fade_in_duration = 100; const int judgement_fade_out_duration = 5000; - base.LoadComplete(); - Alpha = 0; Width = 0; - JudgementLineThickness.BindValueChanged(thickness => Height = thickness.NewValue, true); - this .FadeTo(0.6f, judgement_fade_in_duration, Easing.OutQuint) .ResizeWidthTo(1, judgement_fade_in_duration, Easing.OutQuint) From a86b50d62afd9cd279622f39d31505423ecee6fa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Nov 2022 01:07:53 +0900 Subject: [PATCH 2/6] Apply nullability to `BarHitErrorMeter` --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 5fca8e2c51..23e9c86adc 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Linq; using osu.Framework.Allocation; @@ -27,8 +25,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [Cached] public class BarHitErrorMeter : HitErrorMeter { - private const int judgement_line_width = 14; - [SettingSource("Judgement line thickness", "How thick the individual lines should be.")] public BindableNumber JudgementLineThickness { get; } = new BindableNumber(4) { @@ -46,30 +42,33 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [SettingSource("Label style", "How to show early/late extremities")] public Bindable LabelStyle { get; } = new Bindable(LabelStyles.Icons); - private readonly DrawablePool judgementLinePool = new DrawablePool(50, 100); + private const int judgement_line_width = 14; - private SpriteIcon arrow; - private UprightAspectMaintainingContainer labelEarly; - private UprightAspectMaintainingContainer labelLate; + private const int max_concurrent_judgements = 50; - private Container colourBarsEarly; - private Container colourBarsLate; - - private Container judgementsContainer; + private const int centre_marker_size = 8; private double maxHitWindow; private double floatingAverage; - private Container colourBars; - private Container arrowContainer; - private (HitResult result, double length)[] hitWindows; + private readonly DrawablePool judgementLinePool = new DrawablePool(50, 100); - private const int max_concurrent_judgements = 50; + private SpriteIcon arrow = null!; + private UprightAspectMaintainingContainer labelEarly = null!; + private UprightAspectMaintainingContainer labelLate = null!; - private Drawable[] centreMarkerDrawables; + private Container colourBarsEarly = null!; + private Container colourBarsLate = null!; - private const int centre_marker_size = 8; + private Container judgementsContainer = null!; + + private Container colourBars = null!; + private Container arrowContainer = null!; + + private (HitResult result, double length)[] hitWindows = null!; + + private Drawable[]? centreMarkerDrawables; public BarHitErrorMeter() { @@ -427,6 +426,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { public readonly BindableNumber JudgementLineThickness = new BindableFloat(); + [Resolved] + private BarHitErrorMeter barHitErrorMeter { get; set; } = null!; + public JudgementLine() { RelativeSizeAxes = Axes.X; @@ -443,9 +445,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters }; } - [Resolved] - private BarHitErrorMeter barHitErrorMeter { get; set; } - protected override void LoadComplete() { base.LoadComplete(); From aef6ee23eb871d7c7ae1550b4d451527a623d630 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Nov 2022 01:34:22 +0900 Subject: [PATCH 3/6] Apply pooling support to `ColourHitErrorMeter` --- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index dadec7c06b..6bf3ad0b28 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -3,9 +3,11 @@ using System.Collections.Generic; using System.Linq; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Pooling; using osu.Framework.Graphics.Shapes; using osu.Game.Configuration; using osu.Game.Rulesets.Judgements; @@ -15,6 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD.HitErrorMeters { + [Cached] public class ColourHitErrorMeter : HitErrorMeter { private const int animation_duration = 200; @@ -82,7 +85,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { base.LoadComplete(); - JudgementCount.BindValueChanged(count => + JudgementCount.BindValueChanged(_ => { removeExtraJudgements(); updateMetrics(); @@ -91,11 +94,14 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters JudgementSpacing.BindValueChanged(_ => updateMetrics(), true); } + private readonly DrawablePool judgementLinePool = new DrawablePool(50); + public void Push(Color4 colour) { - Add(new HitErrorShape(colour, drawable_judgement_size) + judgementLinePool.Get(shape => { - Shape = { BindTarget = JudgementShape }, + shape.Colour = colour; + Add(shape); }); removeExtraJudgements(); @@ -116,32 +122,32 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } - public class HitErrorShape : Container + public class HitErrorShape : PoolableDrawable { public bool IsRemoved { get; private set; } public readonly Bindable Shape = new Bindable(); - private readonly Color4 colour; + [Resolved] + private ColourHitErrorMeter hitErrorMeter { get; set; } = null!; private Container content = null!; - public HitErrorShape(Color4 colour, int size) + public HitErrorShape() { - this.colour = colour; - Size = new Vector2(size); + Size = new Vector2(drawable_judgement_size); } protected override void LoadComplete() { base.LoadComplete(); - Child = content = new Container + InternalChild = content = new Container { RelativeSizeAxes = Axes.Both, - Colour = colour }; + Shape.BindTo(hitErrorMeter.JudgementShape); Shape.BindValueChanged(shape => { switch (shape.NewValue) @@ -155,17 +161,27 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters break; } }, true); + } - content.FadeInFromZero(animation_duration, Easing.OutQuint); - content.MoveToY(-DrawSize.Y); - content.MoveToY(0, animation_duration, Easing.OutQuint); + protected override void PrepareForUse() + { + base.PrepareForUse(); + + IsRemoved = false; + + this.FadeIn(); + + content.FadeInFromZero(animation_duration, Easing.OutQuint) + .MoveToY(-DrawSize.Y) + .MoveToY(0, animation_duration, Easing.OutQuint); } public void Remove() { IsRemoved = true; - this.FadeOut(animation_duration, Easing.OutQuint).Expire(); + this.FadeOut(animation_duration, Easing.OutQuint) + .Expire(); } } From 59a8603728e280e8cd75e620a89ac7ba4d478bf6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Nov 2022 11:33:19 +0900 Subject: [PATCH 4/6] Ensure flowing animation starts correctly from zero --- .../Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 6bf3ad0b28..b82afe18a6 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -169,7 +169,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters IsRemoved = false; - this.FadeIn(); + this.FadeIn() + // On pool re-use, start flow animation from (0,0). + .MoveTo(Vector2.Zero); content.FadeInFromZero(animation_duration, Easing.OutQuint) .MoveToY(-DrawSize.Y) From 308ed1abd1353631d98f1c868fd010d0c989b807 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Nov 2022 11:55:33 +0900 Subject: [PATCH 5/6] Fix number of judgements shown potentially exceeding upper limit --- .../Visual/Gameplay/TestSceneHitErrorMeter.cs | 5 +---- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 17 ++++++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs index 7c668adba5..b90b9b437d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs @@ -163,10 +163,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for bars to disappear", () => !this.ChildrenOfType().Any()); AddUntilStep("ensure max circles not exceeded", () => - { - return this.ChildrenOfType() - .All(m => m.ChildrenOfType().Count() <= max_displayed_judgements); - }); + this.ChildrenOfType().First().ChildrenOfType().Count(), () => Is.LessThanOrEqualTo(max_displayed_judgements)); AddStep("show displays", () => { diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index b82afe18a6..86ba85168f 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -102,9 +102,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { shape.Colour = colour; Add(shape); - }); - removeExtraJudgements(); + removeExtraJudgements(); + }); } private void removeExtraJudgements() @@ -167,17 +167,20 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { base.PrepareForUse(); - IsRemoved = false; - - this.FadeIn() + this.FadeInFromZero(animation_duration, Easing.OutQuint) // On pool re-use, start flow animation from (0,0). .MoveTo(Vector2.Zero); - content.FadeInFromZero(animation_duration, Easing.OutQuint) - .MoveToY(-DrawSize.Y) + content.MoveToY(-DrawSize.Y) .MoveToY(0, animation_duration, Easing.OutQuint); } + protected override void FreeAfterUse() + { + base.FreeAfterUse(); + IsRemoved = false; + } + public void Remove() { IsRemoved = true; From 489dca79a115060fe76cfa08d5a94b0886eec923 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Nov 2022 12:05:38 +0900 Subject: [PATCH 6/6] Remove upper limit for pooling --- osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 23e9c86adc..c9f1571dfe 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -52,7 +52,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private double floatingAverage; - private readonly DrawablePool judgementLinePool = new DrawablePool(50, 100); + private readonly DrawablePool judgementLinePool = new DrawablePool(50); private SpriteIcon arrow = null!; private UprightAspectMaintainingContainer labelEarly = null!;