From c0234ff254f0a4144abd5a893c1a3581aba9bbad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 29 Sep 2023 12:44:26 +0900 Subject: [PATCH 01/35] Reduce approach circle's final opacity to match stable Closes #24941. --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 2f1cf57ebe..4de9a57acb 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -191,7 +191,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables CirclePiece.FadeInFromZero(HitObject.TimeFadeIn); - ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt)); + ApproachCircle.FadeTo(0.9f, Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt)); ApproachCircle.ScaleTo(1f, HitObject.TimePreempt); ApproachCircle.Expire(true); } From 94f4268ae5de46ab33849e6ba6583f616f1a55b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 29 Sep 2023 18:23:22 +0900 Subject: [PATCH 02/35] Fix object dim being applied to approach circles Fixes half of https://github.com/ppy/osu/issues/24956. The other half is high effort. The number portion is nested deeply and with reason - depending on skin setting it changes the visual order. I'm not sure how to fix that one, but I also think it's weird behaviour and if people don't complain, it's probably fine to just dim the number for consistency. That said, the approach circle is an important one to ensure it matches 1:1, so I've fixed that here. --- .../Objects/Drawables/DrawableHitCircle.cs | 6 ++++++ .../Objects/Drawables/DrawableOsuHitObject.cs | 17 ++++++++--------- .../Objects/Drawables/DrawableSlider.cs | 8 ++++++++ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 4de9a57acb..e87a075a11 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; using osu.Framework.Allocation; @@ -34,6 +35,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public HitReceptor HitArea { get; private set; } public SkinnableDrawable CirclePiece { get; private set; } + protected override IEnumerable DimmablePieces => new[] + { + CirclePiece, + }; + Drawable IHasApproachCircle.ApproachCircle => ApproachCircle; private Container scaleContainer; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index 920dfcab03..ed981d2d5d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -4,6 +4,8 @@ #nullable disable using System; +using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -71,20 +73,17 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables ScaleBindable.UnbindFrom(HitObject.ScaleBindable); } + protected virtual IEnumerable DimmablePieces => Enumerable.Empty(); + protected override void UpdateInitialTransforms() { base.UpdateInitialTransforms(); - // Dim should only be applied at a top level, as it will be implicitly applied to nested objects. - if (ParentHitObject == null) + foreach (var piece in DimmablePieces) { - // Of note, no one noticed this was missing for years, but it definitely feels like it should still exist. - // For now this is applied across all skins, and matches stable. - // For simplicity, dim colour is applied to the DrawableHitObject itself. - // We may need to make a nested container setup if this even causes a usage conflict (ie. with a mod). - this.FadeColour(new Color4(195, 195, 195, 255)); - using (BeginDelayedSequence(InitialLifetimeOffset - OsuHitWindows.MISS_WINDOW)) - this.FadeColour(Color4.White, 100); + piece.FadeColour(new Color4(195, 195, 195, 255)); + using (piece.BeginDelayedSequence(InitialLifetimeOffset - OsuHitWindows.MISS_WINDOW)) + piece.FadeColour(Color4.White, 100); } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 1a6a0a9ecc..07e448937f 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; @@ -35,6 +36,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private ShakeContainer shakeContainer; + protected override IEnumerable DimmablePieces => new Drawable[] + { + HeadCircle, + TailCircle, + Body, + }; + /// /// A target container which can be used to add top level elements to the slider's display. /// Intended to be used for proxy purposes only. From 869f8e5e1b21dfe53bb56a54a8479797956358f8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Oct 2023 00:20:53 +0300 Subject: [PATCH 03/35] Adjust test scene to apply miss judgements as well --- .../Gameplay/TestSceneSkinnableHealthDisplay.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs index b4ebb7c410..e3700a2a8b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Scoring; @@ -28,15 +29,21 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep(@"Reset all", delegate { healthProcessor.Health.Value = 1; + healthProcessor.Failed += () => false; // health won't be updated if the processor gets into a "fail" state. }); } [Test] public void TestHealthDisplayIncrementing() { - AddRepeatStep(@"decrease hp", delegate + AddRepeatStep("apply miss judgement", delegate { - healthProcessor.Health.Value -= 0.08f; + healthProcessor.ApplyResult(new JudgementResult(new HitObject(), new Judgement()) { Type = HitResult.Miss }); + }, 5); + + AddRepeatStep(@"decrease hp slightly", delegate + { + healthProcessor.Health.Value -= 0.01f; }, 10); AddRepeatStep(@"increase hp without flash", delegate From 33b0cb15a88ece545779bad5ac754f1a79275398 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Oct 2023 00:21:12 +0300 Subject: [PATCH 04/35] Add handling for miss judgements in `HealthDisplay` --- osu.Game/Screens/Play/HUD/HealthDisplay.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/HealthDisplay.cs b/osu.Game/Screens/Play/HUD/HealthDisplay.cs index 9fdd735804..5131f93ca2 100644 --- a/osu.Game/Screens/Play/HUD/HealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HealthDisplay.cs @@ -29,10 +29,22 @@ namespace osu.Game.Screens.Play.HUD MaxValue = 1 }; + /// + /// Triggered when a is a successful hit, signaling the health display to perform a flash animation (if designed to do so). + /// + /// The judgement result. protected virtual void Flash(JudgementResult result) { } + /// + /// Triggered when a resulted in the player losing health. + /// + /// The judgement result. + protected virtual void Miss(JudgementResult result) + { + } + [Resolved] private HUDOverlay? hudOverlay { get; set; } @@ -54,6 +66,8 @@ namespace osu.Game.Screens.Play.HUD { if (judgement.IsHit && judgement.Type != HitResult.IgnoreHit) Flash(judgement); + else if (judgement.Judgement.HealthIncreaseFor(judgement) < 0) + Miss(judgement); } protected override void Dispose(bool isDisposing) From 776536e816075e179a595e42c56c275f989e039b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 26 Sep 2023 02:23:29 +0300 Subject: [PATCH 05/35] Add "Argon" health display implementation --- .../TestSceneSkinnableHealthDisplay.cs | 3 +- .../Screens/Play/HUD/ArgonHealthDisplay.cs | 284 ++++++++++++++++++ 2 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs index e3700a2a8b..4d8ddcd581 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs @@ -20,6 +20,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Cached(typeof(HealthProcessor))] private HealthProcessor healthProcessor = new DrainingHealthProcessor(0); + protected override Drawable CreateArgonImplementation() => new ArgonHealthDisplay(); protected override Drawable CreateDefaultImplementation() => new DefaultHealthDisplay(); protected override Drawable CreateLegacyImplementation() => new LegacyHealthDisplay(); @@ -61,4 +62,4 @@ namespace osu.Game.Tests.Visual.Gameplay }, 3); } } -} +} \ No newline at end of file diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs new file mode 100644 index 0000000000..ca7a4a6cf7 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -0,0 +1,284 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Lines; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Threading; +using osu.Framework.Utils; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Skinning; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.Play.HUD +{ + public partial class ArgonHealthDisplay : HealthDisplay, ISerialisableDrawable + { + private const float curve_start = 280; + private const float curve_end = 310; + private const float curve_smoothness = 10; + + private const float bar_length = 350; + private const float bar_height = 32.5f; + + private BarPath healthBar = null!; + private BarPath missBar = null!; + + private SliderPath barPath = null!; + + private static readonly Colour4 health_bar_colour = Colour4.White; + + // the opacity isn't part of the design, it's only here to control glow intensity. + private static readonly Colour4 health_bar_glow_colour = Color4Extensions.FromHex("#7ED7FD").Opacity(0.3f); + private static readonly Colour4 health_bar_flash_colour = Color4Extensions.FromHex("#7ED7FD").Opacity(0.4f); + + private static readonly Colour4 miss_bar_colour = Color4Extensions.FromHex("#FF9393"); + private static readonly Colour4 miss_bar_glow_colour = Color4Extensions.FromHex("#FD0000"); + + // the "flashed" glow colour is just a lightened version of the original one, not part of the design. + private static readonly Colour4 miss_bar_flash_colour = Color4Extensions.FromHex("#FF5D5D"); + + public bool UsesFixedAnchor { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + Anchor = Anchor.TopLeft; + Origin = Anchor.TopLeft; + AutoSizeAxes = Axes.Both; + + Vector2 diagonalDir = (new Vector2(curve_end, bar_height) - new Vector2(curve_start, 0)).Normalized(); + + // todo: SliderPath or parts of it should be moved away to a utility class as they're useful for making curved paths in general, as done here. + barPath = new SliderPath(new[] + { + new PathControlPoint(new Vector2(0, 0), PathType.Linear), + new PathControlPoint(new Vector2(curve_start - curve_smoothness, 0), PathType.Bezier), + new PathControlPoint(new Vector2(curve_start, 0)), + new PathControlPoint(new Vector2(curve_start, 0) + diagonalDir * curve_smoothness, PathType.Linear), + new PathControlPoint(new Vector2(curve_end, bar_height) - diagonalDir * curve_smoothness, PathType.Bezier), + new PathControlPoint(new Vector2(curve_end, bar_height)), + new PathControlPoint(new Vector2(curve_end + curve_smoothness, bar_height), PathType.Linear), + new PathControlPoint(new Vector2(bar_length, bar_height)), + }); + + var vertices = new List(); + barPath.GetPathToProgress(vertices, 0.0, 1.0); + + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(4f, 0f), + Children = new Drawable[] + { + new Circle + { + Margin = new MarginPadding { Top = 10f - 3f / 2f, Left = -2f }, + Size = new Vector2(50f, 3f), + }, + new Container + { + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new BackgroundPath + { + PathRadius = 10f, + Vertices = vertices, + }, + missBar = new BarPath + { + AutoSizeAxes = Axes.None, + RelativeSizeAxes = Axes.Both, + BarColour = miss_bar_colour, + GlowColour = miss_bar_glow_colour, + Alpha = 0f, + PathRadius = 10f, + Vertices = vertices + }, + healthBar = new BarPath + { + AutoSizeAxes = Axes.None, + RelativeSizeAxes = Axes.Both, + BarColour = health_bar_colour, + GlowColour = health_bar_glow_colour, + PathRadius = 10f, + Vertices = vertices + }, + } + } + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Current.BindValueChanged(v => + { + if (v.NewValue > MissBarValue) + { + missBar.FadeOut(300, Easing.OutQuint); + resetMissBarDelegate?.Cancel(); + resetMissBarDelegate = null; + } + + if (v.NewValue == 0) + healthBar.FadeOut(300, Easing.OutQuint); + else if (healthBar.Alpha < 1) + healthBar.FadeIn(300, Easing.OutQuint); + + this.TransformTo(nameof(HealthBarValue), v.NewValue, 300, Easing.OutQuint); + }, true); + } + + private ScheduledDelegate? resetMissBarDelegate; + + protected override void Miss(JudgementResult result) + { + base.Miss(result); + + if (resetMissBarDelegate != null) + resetMissBarDelegate.Cancel(); + else + this.TransformTo(nameof(MissBarValue), HealthBarValue); + + this.Delay(500).Schedule(() => + { + this.TransformTo(nameof(MissBarValue), Current.Value, 300, Easing.OutQuint); + resetMissBarDelegate = null; + }, out resetMissBarDelegate); + + missBar.FadeIn(120, Easing.OutQuint); + missBar.Delay(500).FadeOut(300, Easing.InQuint); + + missBar.TransformTo(nameof(BarPath.BarColour), miss_bar_colour.Lighten(0.1f)) + .TransformTo(nameof(BarPath.BarColour), miss_bar_colour, 300, Easing.OutQuint); + + missBar.TransformTo(nameof(BarPath.GlowColour), miss_bar_flash_colour) + .TransformTo(nameof(BarPath.GlowColour), miss_bar_glow_colour, 300, Easing.OutQuint); + } + + protected override void Flash(JudgementResult result) + { + base.Flash(result); + + healthBar.TransformTo(nameof(BarPath.GlowColour), health_bar_flash_colour) + .TransformTo(nameof(BarPath.GlowColour), health_bar_glow_colour, 300, Easing.OutQuint); + } + + private double missBarValue = 1.0; + private readonly List missBarVertices = new List(); + + public double MissBarValue + { + get => missBarValue; + set + { + if (missBarValue == value) + return; + + missBarValue = value; + updatePathVertices(); + } + } + + private double healthBarValue = 1.0; + private readonly List healthBarVertices = new List(); + + public double HealthBarValue + { + get => healthBarValue; + set + { + if (healthBarValue == value) + return; + + healthBarValue = value; + updatePathVertices(); + } + } + + private void updatePathVertices() + { + barPath.GetPathToProgress(healthBarVertices, 0.0, healthBarValue); + barPath.GetPathToProgress(missBarVertices, healthBarValue, Math.Max(missBarValue, healthBarValue)); + + if (healthBarVertices.Count == 0) + healthBarVertices.Add(Vector2.Zero); + + if (missBarVertices.Count == 0) + missBarVertices.Add(Vector2.Zero); + + missBar.Vertices = missBarVertices.Select(v => v - missBarVertices[0]).ToList(); + missBar.Position = missBarVertices[0]; + + healthBar.Vertices = healthBarVertices.Select(v => v - healthBarVertices[0]).ToList(); + healthBar.Position = healthBarVertices[0]; + } + + private partial class BackgroundPath : SmoothPath + { + protected override Color4 ColourAt(float position) + { + if (position <= 0.128f) + return Color4.White.Opacity(0.3f); + + position -= 0.128f; + return Interpolation.ValueAt(Math.Clamp(position, 0f, 1f), Color4.White.Opacity(0.5f), Color4.Black.Opacity(0.5f), -0.75f, 1f, Easing.OutQuart); + } + } + + private partial class BarPath : SmoothPath + { + private Colour4 barColour; + + public Colour4 BarColour + { + get => barColour; + set + { + if (barColour == value) + return; + + barColour = value; + InvalidateTexture(); + } + } + + private Colour4 glowColour; + + public Colour4 GlowColour + { + get => glowColour; + set + { + if (glowColour == value) + return; + + glowColour = value; + InvalidateTexture(); + } + } + + protected override Color4 ColourAt(float position) + { + if (position >= 0.6f) + return BarColour; + + return Interpolation.ValueAt(position, Colour4.Black.Opacity(0.0f), GlowColour, 0.0, 0.6); + } + } + } +} From 319208ca3d985b1e733adc39c0be321e09f26f67 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Oct 2023 01:18:05 +0300 Subject: [PATCH 06/35] Adjust health bar glow intensity --- osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index ca7a4a6cf7..5035571820 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -38,8 +38,8 @@ namespace osu.Game.Screens.Play.HUD private static readonly Colour4 health_bar_colour = Colour4.White; // the opacity isn't part of the design, it's only here to control glow intensity. - private static readonly Colour4 health_bar_glow_colour = Color4Extensions.FromHex("#7ED7FD").Opacity(0.3f); - private static readonly Colour4 health_bar_flash_colour = Color4Extensions.FromHex("#7ED7FD").Opacity(0.4f); + private static readonly Colour4 health_bar_glow_colour = Color4Extensions.FromHex("#7ED7FD").Opacity(0.5f); + private static readonly Colour4 health_bar_flash_colour = Color4Extensions.FromHex("#7ED7FD").Opacity(0.6f); private static readonly Colour4 miss_bar_colour = Color4Extensions.FromHex("#FF9393"); private static readonly Colour4 miss_bar_glow_colour = Color4Extensions.FromHex("#FD0000"); From a331fb993ae5dbc94b50283ffb7577d7efb08332 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Oct 2023 01:21:37 +0300 Subject: [PATCH 07/35] Adjust health bar outer stroke colour --- osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index 5035571820..ed141a9a26 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -233,7 +233,7 @@ namespace osu.Game.Screens.Play.HUD protected override Color4 ColourAt(float position) { if (position <= 0.128f) - return Color4.White.Opacity(0.3f); + return Color4.White.Opacity(0.5f); position -= 0.128f; return Interpolation.ValueAt(Math.Clamp(position, 0f, 1f), Color4.White.Opacity(0.5f), Color4.Black.Opacity(0.5f), -0.75f, 1f, Easing.OutQuart); From 9e2b8254d9fc95986c1c3a7eebffe91d8b4f4b0b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Oct 2023 13:26:43 +0300 Subject: [PATCH 08/35] Add argon-specific health display test scene --- .../Gameplay/TestSceneArgonHealthDisplay.cs | 78 +++++++++++++++++++ .../Screens/Play/HUD/ArgonHealthDisplay.cs | 2 - 2 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneArgonHealthDisplay.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneArgonHealthDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneArgonHealthDisplay.cs new file mode 100644 index 0000000000..12a2611a76 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneArgonHealthDisplay.cs @@ -0,0 +1,78 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Judgements; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Play.HUD; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public partial class TestSceneArgonHealthDisplay : OsuTestScene + { + [Cached(typeof(HealthProcessor))] + private HealthProcessor healthProcessor = new DrainingHealthProcessor(0); + + [SetUpSteps] + public void SetUpSteps() + { + AddStep(@"Reset all", delegate + { + healthProcessor.Health.Value = 1; + healthProcessor.Failed += () => false; // health won't be updated if the processor gets into a "fail" state. + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + new ArgonHealthDisplay + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(2f), + }, + }; + }); + } + + [Test] + public void TestHealthDisplayIncrementing() + { + AddRepeatStep("apply miss judgement", delegate + { + healthProcessor.ApplyResult(new JudgementResult(new HitObject(), new Judgement()) { Type = HitResult.Miss }); + }, 5); + + AddRepeatStep(@"decrease hp slightly", delegate + { + healthProcessor.Health.Value -= 0.01f; + }, 10); + + AddRepeatStep(@"increase hp without flash", delegate + { + healthProcessor.Health.Value += 0.1f; + }, 3); + + AddRepeatStep(@"increase hp with flash", delegate + { + healthProcessor.Health.Value += 0.1f; + healthProcessor.ApplyResult(new JudgementResult(new HitCircle(), new OsuJudgement()) + { + Type = HitResult.Perfect + }); + }, 3); + } + } +} diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index ed141a9a26..2db8e9d641 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -52,8 +52,6 @@ namespace osu.Game.Screens.Play.HUD [BackgroundDependencyLoader] private void load() { - Anchor = Anchor.TopLeft; - Origin = Anchor.TopLeft; AutoSizeAxes = Axes.Both; Vector2 diagonalDir = (new Vector2(curve_end, bar_height) - new Vector2(curve_start, 0)).Normalized(); From 446c9c2efefa819fc835cc8a2bb266311f40babf Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Oct 2023 13:39:36 +0300 Subject: [PATCH 09/35] Apply adjustments on the "miss" bar display --- osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index 2db8e9d641..aeaaa19f33 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -96,21 +96,20 @@ namespace osu.Game.Screens.Play.HUD }, missBar = new BarPath { - AutoSizeAxes = Axes.None, - RelativeSizeAxes = Axes.Both, BarColour = miss_bar_colour, GlowColour = miss_bar_glow_colour, Alpha = 0f, - PathRadius = 10f, + PathRadius = 20f, + GlowPortion = 0.75f, + Margin = new MarginPadding(-10f), Vertices = vertices }, healthBar = new BarPath { - AutoSizeAxes = Axes.None, - RelativeSizeAxes = Axes.Both, BarColour = health_bar_colour, GlowColour = health_bar_glow_colour, PathRadius = 10f, + GlowPortion = 0.6f, Vertices = vertices }, } @@ -270,9 +269,11 @@ namespace osu.Game.Screens.Play.HUD } } + public float GlowPortion { get; init; } + protected override Color4 ColourAt(float position) { - if (position >= 0.6f) + if (position >= GlowPortion) return BarColour; return Interpolation.ValueAt(position, Colour4.Black.Opacity(0.0f), GlowColour, 0.0, 0.6); From 30d9004ef9bc089f543bdbb68f3ac6ea7dbb99f8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Oct 2023 13:41:11 +0300 Subject: [PATCH 10/35] Fix small mistake --- osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index aeaaa19f33..434736d42a 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -276,7 +276,7 @@ namespace osu.Game.Screens.Play.HUD if (position >= GlowPortion) return BarColour; - return Interpolation.ValueAt(position, Colour4.Black.Opacity(0.0f), GlowColour, 0.0, 0.6); + return Interpolation.ValueAt(position, Colour4.Black.Opacity(0.0f), GlowColour, 0.0, GlowPortion); } } } From 8d389accf81ceb8b77eb6a9287419d1ffd689ab0 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Oct 2023 15:12:24 +0300 Subject: [PATCH 11/35] Cover "Argon" helath display in skin deserialisation tests --- .../Archives/modified-argon-pro-20231001.osk | Bin 0 -> 1834 bytes osu.Game.Tests/Skins/SkinDeserialisationTest.cs | 4 +++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Resources/Archives/modified-argon-pro-20231001.osk diff --git a/osu.Game.Tests/Resources/Archives/modified-argon-pro-20231001.osk b/osu.Game.Tests/Resources/Archives/modified-argon-pro-20231001.osk new file mode 100644 index 0000000000000000000000000000000000000000..081bb73b9ef7bd85d763007117d4f18fe4046fa4 GIT binary patch literal 1834 zcmZ{k3pA8z7{@<%)ey@Fsfdu68N@O+iKb-6WyVab%KbJjGni2(8%CSUG(_(A+me+_ ziILp0V%-gPkc@<|xh7Ji-KlN2V|Mp@&vV}MzTf+Q&htFye|}a-K7L660E7WK$|)PI zcV5S;IHz!)Pd5NS^2QS&cmlqs@4hI{DKWu`ketaohy7y{qUNx0aFS|7mW#`kGjHDp zy!P3BYZ@$Smo^f2!b!H7i0*HOnLKal1odvLdfaWum7i11S|deZ`$cdw-`G`MP+Z^@!Tl z)?(GoIf3eOvd@+~`c6WdzHWe&?~~M%hv&5c$#>p5RV|c#(*NyE7Oot5syTIj$08)d_{*uu*6;b+f*{n`n%xYNrhorUla) zz%tu=EIUwLDD!@7RD@<=^D8p7giNK;MY=&6&PimW8U1~Q%E{CFsB}z@?GE?}{M1w^Vf*V2g478z8ZRn*waaV#7+R)VKERS-<6WktPXW5mv zG7d)b0)QD90Hio&n>*nNrnu84L|;E5!HqyBeXf7e22IR>iG?gz7*Q0u>%5FXW*!V1X|bChMk_R%Vx1*oSP-6C>7=Bjg%s zNekEREs3}@Q@i2k!bTgU3M1q!qliJezj4j&$u_A7?;y=OziC8srup25=RJl zQ2Cdl@!d_@VcG%hOvWO*iO><#x*pZgJXGy>2Q#R45#5{MB#ss>JNJr!3z~)Y-$Eps zs>`+MtO-@7f@M^6RxVOEyO$hmDej2c@T-Vi9f|vDv=WsxWja)x7Pc=%sE;-hQHM|x zzuc3>t}HEQBZg!>BRvgb^FjE;<@DO-CS`+RcKYM10#$a)jvc>MzsL_t849q^`duRT zqRNBFs$kq)wg4PoP~&}RUE1ZS6y^yjQ8OG9?B+93f6zlWtv>TX9{Y?PAKN}bExzUy zeGRTD6(duhCy%rjf#RCj)p92W$p?PT3JS$6ymxgDDQIAfJI&XSMl}7iVcWaVlUHDp zYOC?ie3ZT(79L#k25!8aq~T(EYA#HhhiYL#PsapoOLG=p$+j+y6mGqU$r*1vlSc&x{ zZx7*_%hE9~Yby;D$Mep%Wlzx?u3>6gbB7lmLZ`|;H2tvhDlN9%6JHLPv=wY@I&SaZ zY2K`8w3Q5pB-$JU@8y`+nn>`lcJpy_A%AwQZ@i^<3k=k{ye-)_>v&$5p*82^8Y*p2 zTFQpF38~;DtZ};;Ep}#&TMKb+_+5sn8wu-cah4Ja(*>-PaFd`yjjmw--RewU{Xyxq zN38rQU*Et|d8|^MUBldo;+MT*GHTe)E!wVjgX-|>p~fRZ@lj1F(eHTYL4zO6s#V1C zF^vqEN^t`#H42fH*YSMf;p72krq}7T4|^T%X&dUTp$$TWmYTlcFieh&Yg2zDh zh9mR6^QAZlDF&wN1lLlyhu#qCL^57Cv%?xMSW7?pDMxhdf&Swn;;0uHM&}=o1lM(8 z4Hxu7&fI`U-uCA^A0!11zbyZq-tzSK(;C)3sj==B$m{#}Xg=SpYcUT#%R;3)?3|)p zlJiw%&h(CQLX;C$K28*Oyqk~fS9Ap&HB+}lb)H-AMt0d$Vu}T6Jcu_pk<`pNTltFQ zyHXse@bF3k|Ic|&+P^;Pr|oa*bE~)+`b7f()X^`he~8L0<>uH|X*|au|4lXS9Nc#L mn!|$sU*_T#b5HTBI8lImrdCJ+!B77MI19olZ-(;%0R99!8uHBm literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index 82d204f134..98008a003d 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -52,7 +52,9 @@ namespace osu.Game.Tests.Skins // Covers player avatar and flag. "Archives/modified-argon-20230305.osk", // Covers key counters - "Archives/modified-argon-pro-20230618.osk" + "Archives/modified-argon-pro-20230618.osk", + // Covers "Argon" health display + "Archives/modified-argon-pro-20231001.osk" }; /// From 7825bea959f41e6e1df8f14ed32eacd124ba0a20 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Oct 2023 15:25:23 +0300 Subject: [PATCH 12/35] Use interpolation for health bar opacity instead of transforms --- osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index 434736d42a..c6c64ebcad 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -131,15 +131,18 @@ namespace osu.Game.Screens.Play.HUD resetMissBarDelegate = null; } - if (v.NewValue == 0) - healthBar.FadeOut(300, Easing.OutQuint); - else if (healthBar.Alpha < 1) - healthBar.FadeIn(300, Easing.OutQuint); - this.TransformTo(nameof(HealthBarValue), v.NewValue, 300, Easing.OutQuint); }, true); } + protected override void Update() + { + base.Update(); + + float targetAlpha = Current.Value > 0 ? 1 : 0; + healthBar.Alpha = (float)Interpolation.DampContinuously(healthBar.Alpha, targetAlpha, 50.0, Time.Elapsed); + } + private ScheduledDelegate? resetMissBarDelegate; protected override void Miss(JudgementResult result) From eef099e69d347e9502d63142d8920f3edf74e332 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 1 Oct 2023 15:25:34 +0300 Subject: [PATCH 13/35] Do not display "miss" bar if health is already zero --- osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index c6c64ebcad..50ac100ed2 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -149,6 +149,10 @@ namespace osu.Game.Screens.Play.HUD { base.Miss(result); + if (result.HealthAtJudgement == 0.0) + // health is already empty, nothing should be displayed here. + return; + if (resetMissBarDelegate != null) resetMissBarDelegate.Cancel(); else From 22aa7ffd06af80f021023d5a97162d6f06adc7a0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 1 Oct 2023 13:45:16 +0900 Subject: [PATCH 14/35] Use additive colour --- osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index 50ac100ed2..023c5e47da 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -98,6 +98,7 @@ namespace osu.Game.Screens.Play.HUD { BarColour = miss_bar_colour, GlowColour = miss_bar_glow_colour, + Blending = BlendingParameters.Additive, Alpha = 0f, PathRadius = 20f, GlowPortion = 0.75f, @@ -106,6 +107,9 @@ namespace osu.Game.Screens.Play.HUD }, healthBar = new BarPath { + AutoSizeAxes = Axes.None, + RelativeSizeAxes = Axes.Both, + Blending = BlendingParameters.Additive, BarColour = health_bar_colour, GlowColour = health_bar_glow_colour, PathRadius = 10f, From df51e612342a0aadecc86267df90c9e641a694de Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 1 Oct 2023 21:20:03 +0900 Subject: [PATCH 15/35] Improve animation --- .../Screens/Play/HUD/ArgonHealthDisplay.cs | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index 023c5e47da..1419ab1b43 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -7,11 +7,13 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Lines; using osu.Framework.Graphics.Shapes; using osu.Framework.Threading; using osu.Framework.Utils; +using osu.Game.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; @@ -96,13 +98,13 @@ namespace osu.Game.Screens.Play.HUD }, missBar = new BarPath { - BarColour = miss_bar_colour, - GlowColour = miss_bar_glow_colour, + BarColour = Color4.White, + GlowColour = OsuColour.Gray(0.5f), Blending = BlendingParameters.Additive, - Alpha = 0f, - PathRadius = 20f, - GlowPortion = 0.75f, - Margin = new MarginPadding(-10f), + Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(0.8f), Color4.White), + PathRadius = 40f, + GlowPortion = 0.9f, + Margin = new MarginPadding(-30f), Vertices = vertices }, healthBar = new BarPath @@ -130,7 +132,8 @@ namespace osu.Game.Screens.Play.HUD { if (v.NewValue > MissBarValue) { - missBar.FadeOut(300, Easing.OutQuint); + missBar.TransformTo(nameof(BarPath.BarColour), Colour4.White, 300, Easing.OutQuint); + missBar.TransformTo(nameof(BarPath.GlowColour), Colour4.White, 300, Easing.OutQuint); resetMissBarDelegate?.Cancel(); resetMissBarDelegate = null; } @@ -158,19 +161,23 @@ namespace osu.Game.Screens.Play.HUD return; if (resetMissBarDelegate != null) + { resetMissBarDelegate.Cancel(); + resetMissBarDelegate = null; + } else this.TransformTo(nameof(MissBarValue), HealthBarValue); this.Delay(500).Schedule(() => { this.TransformTo(nameof(MissBarValue), Current.Value, 300, Easing.OutQuint); + + missBar.TransformTo(nameof(BarPath.BarColour), Colour4.White, 300, Easing.OutQuint); + missBar.TransformTo(nameof(BarPath.GlowColour), Colour4.White, 300, Easing.OutQuint); + resetMissBarDelegate = null; }, out resetMissBarDelegate); - missBar.FadeIn(120, Easing.OutQuint); - missBar.Delay(500).FadeOut(300, Easing.InQuint); - missBar.TransformTo(nameof(BarPath.BarColour), miss_bar_colour.Lighten(0.1f)) .TransformTo(nameof(BarPath.BarColour), miss_bar_colour, 300, Easing.OutQuint); @@ -287,7 +294,7 @@ namespace osu.Game.Screens.Play.HUD if (position >= GlowPortion) return BarColour; - return Interpolation.ValueAt(position, Colour4.Black.Opacity(0.0f), GlowColour, 0.0, GlowPortion); + return Interpolation.ValueAt(position, Colour4.Black.Opacity(0.0f), GlowColour, 0.0, GlowPortion, Easing.InQuart); } } } From 88d608e1fab112e12cb31660191df51c93f69fd4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 00:42:47 +0900 Subject: [PATCH 16/35] Tidy up common animation code --- .../Screens/Play/HUD/ArgonHealthDisplay.cs | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index 1419ab1b43..c64d065e50 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -131,14 +131,11 @@ namespace osu.Game.Screens.Play.HUD Current.BindValueChanged(v => { if (v.NewValue > MissBarValue) - { - missBar.TransformTo(nameof(BarPath.BarColour), Colour4.White, 300, Easing.OutQuint); - missBar.TransformTo(nameof(BarPath.GlowColour), Colour4.White, 300, Easing.OutQuint); - resetMissBarDelegate?.Cancel(); - resetMissBarDelegate = null; - } + finishMissBarUsage(); this.TransformTo(nameof(HealthBarValue), v.NewValue, 300, Easing.OutQuint); + if (resetMissBarDelegate == null) + this.TransformTo(nameof(MissBarValue), v.NewValue, 300, Easing.OutQuint); }, true); } @@ -146,8 +143,8 @@ namespace osu.Game.Screens.Play.HUD { base.Update(); - float targetAlpha = Current.Value > 0 ? 1 : 0; - healthBar.Alpha = (float)Interpolation.DampContinuously(healthBar.Alpha, targetAlpha, 50.0, Time.Elapsed); + healthBar.Alpha = (float)Interpolation.DampContinuously(healthBar.Alpha, (float)(Current.Value > 0 ? 1 : 0), 40, Time.Elapsed); + missBar.Alpha = (float)Interpolation.DampContinuously(missBar.Alpha, (float)(MissBarValue > 0 ? 1 : 0), 40, Time.Elapsed); } private ScheduledDelegate? resetMissBarDelegate; @@ -172,10 +169,7 @@ namespace osu.Game.Screens.Play.HUD { this.TransformTo(nameof(MissBarValue), Current.Value, 300, Easing.OutQuint); - missBar.TransformTo(nameof(BarPath.BarColour), Colour4.White, 300, Easing.OutQuint); - missBar.TransformTo(nameof(BarPath.GlowColour), Colour4.White, 300, Easing.OutQuint); - - resetMissBarDelegate = null; + finishMissBarUsage(); }, out resetMissBarDelegate); missBar.TransformTo(nameof(BarPath.BarColour), miss_bar_colour.Lighten(0.1f)) @@ -185,6 +179,18 @@ namespace osu.Game.Screens.Play.HUD .TransformTo(nameof(BarPath.GlowColour), miss_bar_glow_colour, 300, Easing.OutQuint); } + private void finishMissBarUsage() + { + if (Current.Value > 0) + { + missBar.TransformTo(nameof(BarPath.BarColour), Colour4.Gray, 300, Easing.OutQuint); + missBar.TransformTo(nameof(BarPath.GlowColour), Colour4.Gray, 300, Easing.OutQuint); + } + + resetMissBarDelegate?.Cancel(); + resetMissBarDelegate = null; + } + protected override void Flash(JudgementResult result) { base.Flash(result); From c4f47974bc044a63ec393375b4de5c2cea4a4eb8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 00:56:29 +0900 Subject: [PATCH 17/35] Improve glow further --- osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index c64d065e50..97ae2cc7ec 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -184,7 +184,7 @@ namespace osu.Game.Screens.Play.HUD if (Current.Value > 0) { missBar.TransformTo(nameof(BarPath.BarColour), Colour4.Gray, 300, Easing.OutQuint); - missBar.TransformTo(nameof(BarPath.GlowColour), Colour4.Gray, 300, Easing.OutQuint); + missBar.TransformTo(nameof(BarPath.GlowColour), health_bar_glow_colour, 300, Easing.OutQuint); } resetMissBarDelegate?.Cancel(); @@ -300,7 +300,7 @@ namespace osu.Game.Screens.Play.HUD if (position >= GlowPortion) return BarColour; - return Interpolation.ValueAt(position, Colour4.Black.Opacity(0.0f), GlowColour, 0.0, GlowPortion, Easing.InQuart); + return Interpolation.ValueAt(position, Colour4.Black.Opacity(0.0f), GlowColour, 0.0, GlowPortion, Easing.InQuint); } } } From 3a45bcad15857029647b56a462b7de21522e25fd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 02:03:45 +0900 Subject: [PATCH 18/35] Improve flash and glow further --- .../Screens/Play/HUD/ArgonHealthDisplay.cs | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index 97ae2cc7ec..6cf1daa102 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Play.HUD // the opacity isn't part of the design, it's only here to control glow intensity. private static readonly Colour4 health_bar_glow_colour = Color4Extensions.FromHex("#7ED7FD").Opacity(0.5f); - private static readonly Colour4 health_bar_flash_colour = Color4Extensions.FromHex("#7ED7FD").Opacity(0.6f); + private static readonly Colour4 health_bar_flash_colour = Color4Extensions.FromHex("#7ED7FD").Opacity(0.8f); private static readonly Colour4 miss_bar_colour = Color4Extensions.FromHex("#FF9393"); private static readonly Colour4 miss_bar_glow_colour = Color4Extensions.FromHex("#FD0000"); @@ -130,13 +130,15 @@ namespace osu.Game.Screens.Play.HUD Current.BindValueChanged(v => { - if (v.NewValue > MissBarValue) + if (v.NewValue >= MissBarValue) finishMissBarUsage(); this.TransformTo(nameof(HealthBarValue), v.NewValue, 300, Easing.OutQuint); if (resetMissBarDelegate == null) this.TransformTo(nameof(MissBarValue), v.NewValue, 300, Easing.OutQuint); }, true); + + updatePathVertices(); } protected override void Update() @@ -172,19 +174,20 @@ namespace osu.Game.Screens.Play.HUD finishMissBarUsage(); }, out resetMissBarDelegate); - missBar.TransformTo(nameof(BarPath.BarColour), miss_bar_colour.Lighten(0.1f)) - .TransformTo(nameof(BarPath.BarColour), miss_bar_colour, 300, Easing.OutQuint); + missBar.TransformTo(nameof(BarPath.BarColour), miss_bar_colour, 100, Easing.OutQuint) + .Then() + .TransformTo(nameof(BarPath.BarColour), miss_bar_flash_colour, 800, Easing.OutQuint); - missBar.TransformTo(nameof(BarPath.GlowColour), miss_bar_flash_colour) - .TransformTo(nameof(BarPath.GlowColour), miss_bar_glow_colour, 300, Easing.OutQuint); + missBar.TransformTo(nameof(BarPath.GlowColour), miss_bar_glow_colour.Lighten(0.2f)) + .TransformTo(nameof(BarPath.GlowColour), miss_bar_glow_colour, 800, Easing.OutQuint); } private void finishMissBarUsage() { if (Current.Value > 0) { - missBar.TransformTo(nameof(BarPath.BarColour), Colour4.Gray, 300, Easing.OutQuint); - missBar.TransformTo(nameof(BarPath.GlowColour), health_bar_glow_colour, 300, Easing.OutQuint); + missBar.TransformTo(nameof(BarPath.BarColour), health_bar_colour, 300, Easing.In); + missBar.TransformTo(nameof(BarPath.GlowColour), health_bar_glow_colour, 300, Easing.In); } resetMissBarDelegate?.Cancel(); @@ -197,6 +200,16 @@ namespace osu.Game.Screens.Play.HUD healthBar.TransformTo(nameof(BarPath.GlowColour), health_bar_flash_colour) .TransformTo(nameof(BarPath.GlowColour), health_bar_glow_colour, 300, Easing.OutQuint); + + if (resetMissBarDelegate == null) + { + missBar.TransformTo(nameof(BarPath.BarColour), Colour4.White, 100, Easing.OutQuint) + .Then() + .TransformTo(nameof(BarPath.BarColour), health_bar_colour, 800, Easing.OutQuint); + + missBar.TransformTo(nameof(BarPath.GlowColour), Colour4.White) + .TransformTo(nameof(BarPath.GlowColour), health_bar_glow_colour, 800, Easing.OutQuint); + } } private double missBarValue = 1.0; From 7dd9951c448515bb438992ca4aa127a3f770e604 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 17:41:08 +0900 Subject: [PATCH 19/35] Split out reverse arrow implementations to allow better animation --- .../Objects/Drawables/DrawableSliderRepeat.cs | 8 +++- .../Skinning/Argon/ArgonReverseArrow.cs | 48 ++++++++++++++----- ...seArrowPiece.cs => DefaultReverseArrow.cs} | 13 ++--- .../Skinning/Legacy/LegacyReverseArrow.cs | 18 ++++++- 4 files changed, 63 insertions(+), 24 deletions(-) rename osu.Game.Rulesets.Osu/Skinning/Default/{ReverseArrowPiece.cs => DefaultReverseArrow.cs} (78%) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs index 5721328057..ac4d733672 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public SkinnableDrawable CirclePiece { get; private set; } - public ReverseArrowPiece Arrow { get; private set; } + public SkinnableDrawable Arrow { get; private set; } private Drawable scaleContainer; @@ -65,7 +65,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - Arrow = new ReverseArrowPiece(), + Arrow = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.ReverseArrow), _ => new DefaultReverseArrow()) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, } }); diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs index 67fc1b2304..61077e08a4 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs @@ -2,12 +2,16 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osuTK; @@ -15,14 +19,19 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public partial class ArgonReverseArrow : CompositeDrawable + public partial class ArgonReverseArrow : BeatSyncedContainer { + [Resolved] + private DrawableHitObject drawableRepeat { get; set; } = null!; + private Bindable accentColour = null!; private SpriteIcon icon = null!; + private Container main = null!; + [BackgroundDependencyLoader] - private void load(DrawableHitObject hitObject) + private void load(TextureStore textures, DrawableHitObject hitObject) { Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -31,24 +40,39 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon InternalChildren = new Drawable[] { - new Circle + main = new Container { - Size = new Vector2(40, 20), - Colour = Color4.White, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - icon = new SpriteIcon - { - Icon = FontAwesome.Solid.AngleDoubleRight, - Size = new Vector2(16), + RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, + Children = new Drawable[] + { + new Circle + { + Size = new Vector2(40, 20), + Colour = Color4.White, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + icon = new SpriteIcon + { + Icon = FontAwesome.Solid.AngleDoubleRight, + Size = new Vector2(16), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + } }, }; accentColour = hitObject.AccentColour.GetBoundCopy(); accentColour.BindValueChanged(accent => icon.Colour = accent.NewValue.Darken(4), true); } + + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + { + if (!drawableRepeat.Judged) + main.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out); + } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs similarity index 78% rename from osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs index 27868db2f6..251f048fb6 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs @@ -9,17 +9,16 @@ using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Skinning; using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public partial class ReverseArrowPiece : BeatSyncedContainer + public partial class DefaultReverseArrow : BeatSyncedContainer { [Resolved] private DrawableHitObject drawableRepeat { get; set; } = null!; - public ReverseArrowPiece() + public DefaultReverseArrow() { Divisor = 2; MinimumBeatLength = 200; @@ -29,14 +28,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default Size = OsuHitObject.OBJECT_DIMENSIONS; - Child = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.ReverseArrow), _ => new SpriteIcon + Child = new SpriteIcon { RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, Icon = FontAwesome.Solid.ChevronRight, - Size = new Vector2(0.35f) - }) - { + Size = new Vector2(0.35f), Anchor = Anchor.Centre, Origin = Anchor.Centre, }; @@ -44,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { - if (!drawableRepeat.IsHit) + if (!drawableRepeat.Judged) Child.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out); } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index 3a80607522..c63ae35a3f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -3,9 +3,11 @@ using System.Diagnostics; using osu.Framework.Allocation; +using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; @@ -14,8 +16,11 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public partial class LegacyReverseArrow : CompositeDrawable + public partial class LegacyReverseArrow : BeatSyncedContainer { + [Resolved] + private DrawableHitObject drawableRepeat { get; set; } = null!; + [Resolved(canBeNull: true)] private DrawableHitObject? drawableHitObject { get; set; } @@ -30,6 +35,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy [BackgroundDependencyLoader] private void load(ISkinSource skinSource) { + Divisor = 2; + MinimumBeatLength = 200; + AutoSizeAxes = Axes.Both; string lookupName = new OsuSkinComponentLookup(OsuSkinComponents.ReverseArrow).LookupName; @@ -59,6 +67,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy } } + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + { + if (!drawableRepeat.Judged) + Child.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out); + } + private void onHitObjectApplied(DrawableHitObject drawableObject) { Debug.Assert(proxy.Parent == null); From 455fc228ad5c572a772648a7da53084ea034dd5c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 18:26:35 +0900 Subject: [PATCH 20/35] Add edge piece to argon reverse arrow --- .../Skinning/Argon/ArgonReverseArrow.cs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs index 61077e08a4..aed7d1a55f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs @@ -29,10 +29,15 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private SpriteIcon icon = null!; private Container main = null!; + private Sprite side = null!; [BackgroundDependencyLoader] private void load(TextureStore textures, DrawableHitObject hitObject) { + Divisor = 2; + MinimumBeatLength = 120; + EarlyActivationMilliseconds = 30; + Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -63,6 +68,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon }, } }, + side = new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Texture = textures.Get("Gameplay/osu/repeat-edge-piece"), + Size = new Vector2(ArgonMainCirclePiece.OUTER_GRADIENT_SIZE), + } }; accentColour = hitObject.AccentColour.GetBoundCopy(); @@ -72,7 +84,15 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { if (!drawableRepeat.Judged) - main.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out); + { + main.ScaleTo(1.3f, 30, Easing.Out) + .Then() + .ScaleTo(1f, timingPoint.BeatLength / 2, Easing.Out); + side + .MoveToX(-12, 30, Easing.Out) + .Then() + .MoveToX(0, timingPoint.BeatLength / 2, Easing.Out); + } } } } From ad4e988520def03498327625be3c9369be0d0a7d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 18:34:21 +0900 Subject: [PATCH 21/35] Adjust reverse arrows to bounce more --- osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs | 7 +++---- .../Skinning/Default/DefaultReverseArrow.cs | 2 +- .../Skinning/Legacy/LegacyReverseArrow.cs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs index aed7d1a55f..1ce3a32900 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs @@ -35,8 +35,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private void load(TextureStore textures, DrawableHitObject hitObject) { Divisor = 2; - MinimumBeatLength = 120; - EarlyActivationMilliseconds = 30; + MinimumBeatLength = 150; Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -85,11 +84,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { if (!drawableRepeat.Judged) { - main.ScaleTo(1.3f, 30, Easing.Out) + main.ScaleTo(1.3f, timingPoint.BeatLength / 8, Easing.Out) .Then() .ScaleTo(1f, timingPoint.BeatLength / 2, Easing.Out); side - .MoveToX(-12, 30, Easing.Out) + .MoveToX(-12, timingPoint.BeatLength / 8, Easing.Out) .Then() .MoveToX(0, timingPoint.BeatLength / 2, Easing.Out); } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs index 251f048fb6..f1deba7782 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default public DefaultReverseArrow() { Divisor = 2; - MinimumBeatLength = 200; + MinimumBeatLength = 150; Anchor = Anchor.Centre; Origin = Anchor.Centre; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index c63ae35a3f..e1d1b088a2 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private void load(ISkinSource skinSource) { Divisor = 2; - MinimumBeatLength = 200; + MinimumBeatLength = 150; AutoSizeAxes = Axes.Both; From 8010410487c9e43434e4785af10f64156f4d81d7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 19:09:57 +0900 Subject: [PATCH 22/35] Stop beat syncing (and close match stable's implementation of arrow animation) --- .../Skinning/Argon/ArgonReverseArrow.cs | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs index 1ce3a32900..d4084a76f1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -10,8 +9,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osuTK; @@ -19,24 +16,20 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public partial class ArgonReverseArrow : BeatSyncedContainer + public partial class ArgonReverseArrow : CompositeDrawable { [Resolved] - private DrawableHitObject drawableRepeat { get; set; } = null!; + private DrawableHitObject drawableObject { get; set; } = null!; private Bindable accentColour = null!; private SpriteIcon icon = null!; - private Container main = null!; private Sprite side = null!; [BackgroundDependencyLoader] - private void load(TextureStore textures, DrawableHitObject hitObject) + private void load(TextureStore textures) { - Divisor = 2; - MinimumBeatLength = 150; - Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -76,22 +69,39 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon } }; - accentColour = hitObject.AccentColour.GetBoundCopy(); + accentColour = drawableObject.AccentColour.GetBoundCopy(); accentColour.BindValueChanged(accent => icon.Colour = accent.NewValue.Darken(4), true); + + drawableObject.ApplyCustomUpdateState += updateStateTransforms; } - protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + private void updateStateTransforms(DrawableHitObject hitObject, ArmedState state) { - if (!drawableRepeat.Judged) + const float move_distance = -12; + const double move_out_duration = 35; + const double move_in_duration = 250; + const double total = 300; + + switch (state) { - main.ScaleTo(1.3f, timingPoint.BeatLength / 8, Easing.Out) - .Then() - .ScaleTo(1f, timingPoint.BeatLength / 2, Easing.Out); - side - .MoveToX(-12, timingPoint.BeatLength / 8, Easing.Out) - .Then() - .MoveToX(0, timingPoint.BeatLength / 2, Easing.Out); + case ArmedState.Idle: + main.ScaleTo(1.3f, move_out_duration, Easing.Out) + .Then() + .ScaleTo(1f, move_in_duration, Easing.Out) + .Loop(total - (move_in_duration + move_out_duration)); + side + .MoveToX(move_distance, move_out_duration, Easing.Out) + .Then() + .MoveToX(0, move_in_duration, Easing.Out) + .Loop(total - (move_in_duration + move_out_duration)); + break; } } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; + } } } From e4ac8362ecd5329458356013e0c66eff310cf40d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 19:17:45 +0900 Subject: [PATCH 23/35] Update other implementations to use non-beat-sync logic --- .../Skinning/Default/DefaultReverseArrow.cs | 42 +++++++++---- .../Skinning/Legacy/LegacyReverseArrow.cs | 61 ++++++++++--------- 2 files changed, 62 insertions(+), 41 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs index f1deba7782..a019a4767b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs @@ -2,33 +2,28 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public partial class DefaultReverseArrow : BeatSyncedContainer + public partial class DefaultReverseArrow : CompositeDrawable { [Resolved] - private DrawableHitObject drawableRepeat { get; set; } = null!; + private DrawableHitObject drawableObject { get; set; } = null!; public DefaultReverseArrow() { - Divisor = 2; - MinimumBeatLength = 150; - Anchor = Anchor.Centre; Origin = Anchor.Centre; Size = OsuHitObject.OBJECT_DIMENSIONS; - Child = new SpriteIcon + InternalChild = new SpriteIcon { RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, @@ -39,10 +34,33 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default }; } - protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + [BackgroundDependencyLoader] + private void load() { - if (!drawableRepeat.Judged) - Child.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out); + drawableObject.ApplyCustomUpdateState += updateStateTransforms; + } + + private void updateStateTransforms(DrawableHitObject hitObject, ArmedState state) + { + const double move_out_duration = 35; + const double move_in_duration = 250; + const double total = 300; + + switch (state) + { + case ArmedState.Idle: + InternalChild.ScaleTo(1.3f, move_out_duration, Easing.Out) + .Then() + .ScaleTo(1f, move_in_duration, Easing.Out) + .Loop(total - (move_in_duration + move_out_duration)); + break; + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index e1d1b088a2..98ac770dd0 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -3,11 +3,9 @@ using System.Diagnostics; using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Graphics.Containers; +using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; @@ -16,13 +14,10 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public partial class LegacyReverseArrow : BeatSyncedContainer + public partial class LegacyReverseArrow : CompositeDrawable { [Resolved] - private DrawableHitObject drawableRepeat { get; set; } = null!; - - [Resolved(canBeNull: true)] - private DrawableHitObject? drawableHitObject { get; set; } + private DrawableHitObject drawableObject { get; set; } = null!; private Drawable proxy = null!; @@ -35,9 +30,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy [BackgroundDependencyLoader] private void load(ISkinSource skinSource) { - Divisor = 2; - MinimumBeatLength = 150; - AutoSizeAxes = Axes.Both; string lookupName = new OsuSkinComponentLookup(OsuSkinComponents.ReverseArrow).LookupName; @@ -46,6 +38,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy InternalChild = arrow = (skin?.GetAnimation(lookupName, true, true, maxSize: OsuHitObject.OBJECT_DIMENSIONS) ?? Empty()); textureIsDefaultSkin = skin is ISkinTransformer transformer && transformer.Skin is DefaultLegacySkin; + + drawableObject.ApplyCustomUpdateState += updateStateTransforms; } protected override void LoadComplete() @@ -54,23 +48,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy proxy = CreateProxy(); - if (drawableHitObject != null) + drawableObject.HitObjectApplied += onHitObjectApplied; + onHitObjectApplied(drawableObject); + + accentColour = drawableObject.AccentColour.GetBoundCopy(); + accentColour.BindValueChanged(c => { - drawableHitObject.HitObjectApplied += onHitObjectApplied; - onHitObjectApplied(drawableHitObject); - - accentColour = drawableHitObject.AccentColour.GetBoundCopy(); - accentColour.BindValueChanged(c => - { - arrow.Colour = textureIsDefaultSkin && c.NewValue.R + c.NewValue.G + c.NewValue.B > (600 / 255f) ? Color4.Black : Color4.White; - }, true); - } - } - - protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) - { - if (!drawableRepeat.Judged) - Child.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out); + arrow.Colour = textureIsDefaultSkin && c.NewValue.R + c.NewValue.G + c.NewValue.B > (600 / 255f) ? Color4.Black : Color4.White; + }, true); } private void onHitObjectApplied(DrawableHitObject drawableObject) @@ -82,11 +67,29 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy .OverlayElementContainer.Add(proxy); } + private void updateStateTransforms(DrawableHitObject hitObject, ArmedState state) + { + const double move_out_duration = 35; + const double move_in_duration = 250; + const double total = 300; + + switch (state) + { + case ArmedState.Idle: + InternalChild.ScaleTo(1.3f, move_out_duration, Easing.Out) + .Then() + .ScaleTo(1f, move_in_duration, Easing.Out) + .Loop(total - (move_in_duration + move_out_duration)); + break; + } + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - if (drawableHitObject != null) - drawableHitObject.HitObjectApplied -= onHitObjectApplied; + + drawableObject.HitObjectApplied -= onHitObjectApplied; + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; } } } From 1bee7bf353d286978b1b975c1d202c2730ce7b2f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 19:22:24 +0900 Subject: [PATCH 24/35] Add note about rotation --- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index 98ac770dd0..81781bc6b0 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -76,6 +76,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy switch (state) { case ArmedState.Idle: + // TODO: rotate slightly if Version < 1 (aka UseNewLayout) InternalChild.ScaleTo(1.3f, move_out_duration, Easing.Out) .Then() .ScaleTo(1f, move_in_duration, Easing.Out) From f0070eecf10ce1fe7193e973eee20ae1720e9a12 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 20:09:39 +0900 Subject: [PATCH 25/35] Add rotation support for very old skins --- .../Resources/old-skin/reversearrow.png | Bin 0 -> 4853 bytes .../Skinning/Legacy/LegacyReverseArrow.cs | 26 ++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/old-skin/reversearrow.png diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/old-skin/reversearrow.png b/osu.Game.Rulesets.Osu.Tests/Resources/old-skin/reversearrow.png new file mode 100644 index 0000000000000000000000000000000000000000..7ebdec37d356490d018f711ae525abb3250be3fd GIT binary patch literal 4853 zcmbtY_d6S2)K3TvF=AJY#9lQ+X=~T6O-qYfvDz9{dqfawR;=11ZH=O}s)``Awptzb zh+1DWsG^iN?|<+<&wHP9@A=`LAMUyLbI$pkn`myT&qxoW2LJ$!h6Xy86pi`c38tm2 zpVgg*D2h8k*EYb)*F7NE+20MIh4OWALl}BHd$?J;Iio_K4!EfT0IWHNI$G8tGusYy ze%89MU3(B%07OSunwYKw;u4JEO|ne7^3o{OyjsNNlUYlR^p^>T`RpD`i6LrpagI4i z?BFU(8YW&C2kA~?H9lfU~o91h-_28Sn)_H7H3 zH^njMCDtdJH*Vb6j_2`lI$R(1Pz(Qq5^7K1Blti;gpOh~lp|}_G`rK%)6-K^T8fF1MIbOHxpL8J z=j6|0P(SFR=waPVjWGGI4wMDKXp;-%U{*gt2zlVx1m)!X=7#f-%8QZ5^XI(}3*p-d5Ziwu*NI}%r9ohCT zMVdlYRaLgy+S)>f35o@2a1C`SdHH%xR>Q{t=6j&)1*rwmk!OFD&SFf9Zq^TEiapE3 z)Ee@n{5RirYco_Pakj3G$nh_eM-;H&fX875KO#ReY97C{`+5$ znF8HIUCfPVYsBQV^6|7@!2VI{a> z5H&%;Ziy)B;jZJws8IzZvLy(rWAJKJML71O)H3}HLM02qH*K_4G0KO zOioI2QJxQAOHN5aq0wlW)3%YKTYVpW<_9MxCSWGiEF_hs2)B#Hel6M#9q?_luJ#J;l+m^~h3^ukW9ivun(B!5#qEAJ#5-j4xzj5f0gPWOAy(!$j z-ES+#>9TKrj%RdDQ#}CN9J^B)cYpMrwG9iqSzTGVv?%oasWcrtCTF3Fak}THaC9dR z-31W8OPZ_4-+tbp50A`>i;K(C+W<3?*vrey{f}yMu?|<5`Oo``)xv*%9@LUgi2mMi zszm(#-#42HH&};W#KqjR(fZuntKYy2kD9cb4pRi~aq5ngrff$&w6L&Prhxj}zBG)_ z3t?kEI#T;>%ESb~8ll`;6BC>knAOK0o|4M1HsiM6D&?-a9q!^HILZiEIp-**AQMWb z7K`?YrgBS)knO-Y|tgIx_jTw)Rw(gq3ZHdZaOOi?sSWerbEU z@x1s+q&x}wHAEOxN{i-doR@Sb@G>UR`Q>H+tSU^~qh)wJ8Coy?ZiOnz7&y^7m2}NC zJ?2T)Z)j*RGT6}f{0V1?>8peyJB=CUO4uF{t8l~!P-)&mvCL&OIsH}9tza41207}w zs~>#kZ~i&k>qN4KIQaPNj-Q`LSm#+ofHw49LlzPpQKp1)y>SMn#z&Ya?VX{##d=r$ zG%i)nX!WygWY7{3h&Fq8@%FWT+U~1Q9maY4Zt>iX5@=fdBwg1XHYYY1(LNMIxjvy5 zB(+R>41)Ki!98NHFs~(6NCD$~o*Zrdm>akixM|J!_JUgRj5+zfG>xNV zeAR9>V@z|4C0Ry{_{K03Iw{S{gxFeW4=pD9ak`3hp z)KQX=cK*?{;?^CGt{m}h*}LwM@0@#QZ-ktMr^48x|fOo|qJ&Ag}{{-982Uo&mozGBTLPwikumgIb`fz4rx9{6E(;OE%7r zzoZe85g>j^WIOw|>hp9--_|zdBZ0uHts(6$1ZPkDqRpT4z!^(RdE2(pfdPqI z5hs3O4h|0WuXaZzUmI6O+}J8BYHqVi%&i6!A?e3<0(BeN!&{WGav9pcWX(x@}CMHI3i#Sts?1vp_Nc~k#f%9iZwqks$&9gca zo1lcWG`Mz-`V@L6=@sJvak{~6=u;By$0yVNxu8yc@N1*Qw$(~{28IurR9mllI9~#{;Nj2M`B`P@Ym+@4yt{EpeQ|y zvx$Xje36|m-!mGZdDPEgR``#bDu1Z}#$M-ppk=^*p; zjErve(-k(Ei2Tz~?UQvZIT=e{9j=A0>9`+k7uU%WIY1}W@B7c2IO{h5jNICj`w%X0 zX0Ow2_IlAy2IONwI8e|vpHQC+-kAxMLzT(s4dlrtkR4gk`Q}??+GIV_9ofZqchPn# z(S%pjciY~@`F5Pfd+hgHNC|n!7O97Gzu-uGdT-7K=CV&~d8y7`yzqS0v&IC_($cd1 zD^262{KYZ53_m;GE-vID-u%+?q{-;X9{J5X=l5d(f_fVT`tJ@Rroz9RoD4(g>HP8rBHpcI&rB-36`2k=dKx|D5efW#<6#`S5f?!~T=+R@3RbxuiS=L8}m zZB}wOX}*iFlD)ioFH~i76PG8{=4gOYk;Ga*L13!NTT(@D81j5AvaXEEg@WPuh28nK zC;_X37Ba^Q62gGZc(k|%b>gRWHgBalG8>)C%*$)hAyiD@NXTrmgBw+Y8|=rlriU!n z^X$(~BaT;cI&N!MFMF{j>0w*Y4y<+icJ})pkLJxTzOXelHHpNitQxUfxLhZ-4bmC+ zWLsB#D@i?&>MyOSsWAc@XK22(8Bp97+3(?U{E~WAe)-{n(3qgG0m0_pitT-?!71zR zU=AQol>|}ndtca6eMJ=DkB}~1JN|L>M=Et7(%>ZFa5nMy6x=o2a}?9f_&hOR@`V)rEB0Axu4 zu;u3ZwFIU`&y^`taKEihuu^wJW4Xf4O}s8D#nD%f)RqFEl=5owv>OVgxQh*>9RpE~ zGD08_*6z&LA~al<)CR1!j3@;Wdu@QQSO4b)OrhFM4;4sz*wM1OE((QG*3jq#^gL~= z%BzCvW)OSr?Ta2iq5>!>DV30r=YM8>L)S(m_-i^fMi+mztT4|-q>fb4w~-d`N<<~} zCqqL+4IHO|b~&T4A15s%O!yy0W&bige3P)b!PPtoFfY^9)g6+{>-f7_om}N_mvn3Q zQ*5H8jPbjG&Cxz{phKg@8m=Eyq^YgQ?vK}NLqBXvG z`^~=q*h9>P<(lz$5(7*WZxMsU=&@>ATYq<`qop+|B{6}ZFS6b>G#or}b|!^?((Oq_ zawd++(bI^HkB|S0jg5s{8kT;=gnI#qAD^v{P}t0BfyMAX#X-k9>1q*8rM;38QA`_D^AS+kwx4|%KPJaj?FUDnkd!odJkAmF->YqEfp2Jfr5+G%9s`dj zC}+b7c^aCTmH0HzJ|5HX_*QN*S;$6=W)f5gQAZ#U+Bl-)W1zAiriw;fu;1j)or1JI z*C@5Yx>}m4u=qMTaq-IV#g53!!I9&I@drdkB>=P`PQ1k>7^}iRt$ol6= zTCud!!U_yrO!!XDW*#rV5B9N2N<*@DP8mnyu+U$r%I_ugF?D1L1zs0MWY%T9!fplH zZlFaqm1u1Fsz$zkjT4=s?0;2WT;WlFkYt!CT5spu&T*mn#NK|+(wY9eNyATIhH(D_ zG`<$fRQPeE=w@L4ZKnAW@?k}BSQ4aBgoy5%ZuB^`^iA$*kU%1zQ9Z8OLLNz$^g)T5 zF#y9DB9Z8^*S4pg<#EVFO6HV)H2z0{_d9t|s+P?8uB@z#2dSV??6EF|hA9H)Djf)j z=n^BUq}4q>1yuj?($Z3~r(~Sa`~!bIK!!<(tbyi?lbSAU6w>H=7{vPNM=0=XI&pNg z*38&=c=6Ti*Uu5tY;gGK83Xt6zM}|ThcGLV*S5U~kV@3Ao!r z*}a=9D=YKvqA~hKyfZ0=xS7(%G4Q;&DleRaL#Zx!Z-F4qU8wt8tT%dWg9`nY%+elh zUS7WIEX-On+ZwoqbQg*45N~v->7hVTm!X%^>A&xDC@4Srz1;-z)Z?ji$G5w{VraNmlnNJO_;l(~ zf`W!iHUZ)SHxd@#R8*w7n#>c8*<}9aM)%V;F4cNsnFIqESh2XD z3LN)fM~a70uSc(l7?GLAk)`#w6YhV&q}?CRbK#8ONJT_q|F{GwrZCmKMKSE9OFN_b zSdPran$|n}KE$;18e55$fvMMb2E7-KYTlA=W1z2uv0>RFt{I@~KfeoUdMlD#KPi|1 zjzwarHwzu+PH#V=4K=E``8`!wlI}Y-+}^*iU@{j&;r^XJqOOFJH;0ehOwMTkWgB#t zI7FbTi(SkinConfiguration.LegacySetting.Version)?.Value <= 1; } protected override void LoadComplete() @@ -76,11 +80,23 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy switch (state) { case ArmedState.Idle: - // TODO: rotate slightly if Version < 1 (aka UseNewLayout) - InternalChild.ScaleTo(1.3f, move_out_duration, Easing.Out) - .Then() - .ScaleTo(1f, move_in_duration, Easing.Out) - .Loop(total - (move_in_duration + move_out_duration)); + if (shouldRotate) + { + InternalChild.ScaleTo(1.3f, move_out_duration) + .RotateTo(5.625f) + .Then() + .ScaleTo(1f, move_in_duration) + .RotateTo(-5.625f, move_in_duration) + .Loop(total - (move_in_duration + move_out_duration)); + } + else + { + InternalChild.ScaleTo(1.3f) + .Then() + .ScaleTo(1f, move_in_duration) + .Loop(total - (move_in_duration + move_out_duration)); + } + break; } } From 94e49a34fdd1d827a500d0235800e40fff1cab41 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 22:26:57 +0900 Subject: [PATCH 26/35] Adjust legacy reverse arrow implementation to match stable more closely --- .../Skinning/Legacy/LegacyReverseArrow.cs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index 09625c2aed..7e69c7a25b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -73,28 +73,26 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private void updateStateTransforms(DrawableHitObject hitObject, ArmedState state) { - const double move_out_duration = 35; - const double move_in_duration = 250; - const double total = 300; + const double duration = 300; + const float rotation = 5.625f; switch (state) { case ArmedState.Idle: if (shouldRotate) { - InternalChild.ScaleTo(1.3f, move_out_duration) - .RotateTo(5.625f) + InternalChild.ScaleTo(1.3f) + .RotateTo(rotation) .Then() - .ScaleTo(1f, move_in_duration) - .RotateTo(-5.625f, move_in_duration) - .Loop(total - (move_in_duration + move_out_duration)); + .ScaleTo(1f, duration) + .RotateTo(-rotation, duration) + .Loop(); } else { - InternalChild.ScaleTo(1.3f) - .Then() - .ScaleTo(1f, move_in_duration) - .Loop(total - (move_in_duration + move_out_duration)); + InternalChild.ScaleTo(1.3f).Then() + .ScaleTo(1f, duration, Easing.Out) + .Loop(); } break; From 3aa51301e8b9f94c7088b59af796daf7d011e3fd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 22:28:33 +0900 Subject: [PATCH 27/35] Add null checks in disposal flow --- osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs | 5 ++++- .../Skinning/Default/DefaultReverseArrow.cs | 5 ++++- .../Skinning/Legacy/LegacyReverseArrow.cs | 8 ++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs index d4084a76f1..160edb6f67 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -101,7 +102,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - drawableObject.ApplyCustomUpdateState -= updateStateTransforms; + + if (drawableObject.IsNotNull()) + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs index a019a4767b..b44f6571b9 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultReverseArrow.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -60,7 +61,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - drawableObject.ApplyCustomUpdateState -= updateStateTransforms; + + if (drawableObject.IsNotNull()) + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index 7e69c7a25b..34bcf95e1d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; @@ -103,8 +104,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { base.Dispose(isDisposing); - drawableObject.HitObjectApplied -= onHitObjectApplied; - drawableObject.ApplyCustomUpdateState -= updateStateTransforms; + if (drawableObject.IsNotNull()) + { + drawableObject.HitObjectApplied -= onHitObjectApplied; + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; + } } } } From 16fcc4eaaa9818989a1ad39cb6921822ab35abc7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Oct 2023 12:32:52 +0900 Subject: [PATCH 28/35] Fix incorrect anchor/origin causing rotation to look wrong on legacy skin arrows --- .../Skinning/Legacy/LegacyReverseArrow.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index 34bcf95e1d..25de6d2381 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -39,7 +39,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy var skin = skinSource.FindProvider(s => s.GetTexture(lookupName) != null); - InternalChild = arrow = (skin?.GetAnimation(lookupName, true, true, maxSize: OsuHitObject.OBJECT_DIMENSIONS) ?? Empty()); + InternalChild = arrow = (skin?.GetAnimation(lookupName, true, true, maxSize: OsuHitObject.OBJECT_DIMENSIONS) ?? Empty()).With(d => + { + d.Anchor = Anchor.Centre; + d.Origin = Anchor.Centre; + }); + textureIsDefaultSkin = skin is ISkinTransformer transformer && transformer.Skin is DefaultLegacySkin; drawableObject.ApplyCustomUpdateState += updateStateTransforms; From b234a453da2319a4fc5101ecc5b5d41865232cce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Oct 2023 16:01:15 +0900 Subject: [PATCH 29/35] Fix legacy beatmap importer not always handling nested paths correctly Addresses https://github.com/ppy/osu/discussions/24989. --- osu.Game.Tests/Database/LegacyBeatmapImporterTest.cs | 8 +++++++- osu.Game/Database/LegacyBeatmapImporter.cs | 5 ++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Database/LegacyBeatmapImporterTest.cs b/osu.Game.Tests/Database/LegacyBeatmapImporterTest.cs index 0144c0bf97..5f722e381c 100644 --- a/osu.Game.Tests/Database/LegacyBeatmapImporterTest.cs +++ b/osu.Game.Tests/Database/LegacyBeatmapImporterTest.cs @@ -44,17 +44,23 @@ namespace osu.Game.Tests.Database createFile(subdirectory2, Path.Combine("beatmap5", "beatmap.osu")); createFile(subdirectory2, Path.Combine("beatmap6", "beatmap.osu")); + // songs subdirectory with random file + var subdirectory3 = songsStorage.GetStorageForDirectory("subdirectory3"); + createFile(subdirectory3, "silly readme.txt"); + createFile(subdirectory3, Path.Combine("beatmap7", "beatmap.osu")); + // empty songs subdirectory songsStorage.GetStorageForDirectory("subdirectory3"); string[] paths = importer.GetStableImportPaths(songsStorage).ToArray(); - Assert.That(paths.Length, Is.EqualTo(6)); + Assert.That(paths.Length, Is.EqualTo(7)); Assert.That(paths.Contains(songsStorage.GetFullPath("beatmap1"))); Assert.That(paths.Contains(songsStorage.GetFullPath(Path.Combine("subdirectory", "beatmap2")))); Assert.That(paths.Contains(songsStorage.GetFullPath(Path.Combine("subdirectory", "beatmap3")))); Assert.That(paths.Contains(songsStorage.GetFullPath(Path.Combine("subdirectory", "sub-subdirectory", "beatmap4")))); Assert.That(paths.Contains(songsStorage.GetFullPath(Path.Combine("subdirectory2", "beatmap5")))); Assert.That(paths.Contains(songsStorage.GetFullPath(Path.Combine("subdirectory2", "beatmap6")))); + Assert.That(paths.Contains(songsStorage.GetFullPath(Path.Combine("subdirectory3", "beatmap7")))); } static void createFile(Storage storage, string path) diff --git a/osu.Game/Database/LegacyBeatmapImporter.cs b/osu.Game/Database/LegacyBeatmapImporter.cs index 20add54949..a090698a68 100644 --- a/osu.Game/Database/LegacyBeatmapImporter.cs +++ b/osu.Game/Database/LegacyBeatmapImporter.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using osu.Framework.IO.Stores; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Beatmaps; @@ -34,9 +33,9 @@ namespace osu.Game.Database try { - if (!directoryStorage.GetFiles(string.Empty).ExcludeSystemFileNames().Any()) + if (!directoryStorage.GetFiles(string.Empty, "*.osu").Any()) { - // if a directory doesn't contain files, attempt looking for beatmaps inside of that directory. + // if a directory doesn't contain any beatmap files, look for further nested beatmap directories. // this is a special behaviour in stable for beatmaps only, see https://github.com/ppy/osu/issues/18615. foreach (string subDirectory in GetStableImportPaths(directoryStorage)) paths.Add(subDirectory); From 2cbec6dbdf115562d64d44f515ee9ad520e20416 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Oct 2023 17:11:52 +0900 Subject: [PATCH 30/35] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 58e18d3187..0ee922e53a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + From 8178cf3a8dce61729699668898bd61b6b80ee5b8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Oct 2023 17:17:11 +0900 Subject: [PATCH 31/35] Tidy up background colour gradient logic This changes things visually a touch, but I think it feels better. And reads better. --- osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index 6cf1daa102..f2f71ab64d 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -267,10 +267,12 @@ namespace osu.Game.Screens.Play.HUD protected override Color4 ColourAt(float position) { if (position <= 0.128f) - return Color4.White.Opacity(0.5f); + return Color4.White.Opacity(0.8f); - position -= 0.128f; - return Interpolation.ValueAt(Math.Clamp(position, 0f, 1f), Color4.White.Opacity(0.5f), Color4.Black.Opacity(0.5f), -0.75f, 1f, Easing.OutQuart); + return Interpolation.ValueAt(position, + Color4.White.Opacity(0.8f), + Color4.Black.Opacity(0.2f), + -0.5f, 1f, Easing.OutQuint); } } From e1445fcc65cf60800fd6f86785db051d821b5f64 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Oct 2023 17:17:42 +0900 Subject: [PATCH 32/35] Adjust health display test scene's background colour to better visualise background fill --- osu.Game.Tests/Visual/Gameplay/TestSceneArgonHealthDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneArgonHealthDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneArgonHealthDisplay.cs index 12a2611a76..06a7763711 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneArgonHealthDisplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneArgonHealthDisplay.cs @@ -35,7 +35,7 @@ namespace osu.Game.Tests.Visual.Gameplay new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, + Colour = Color4.Gray, }, new ArgonHealthDisplay { From 4f9daa1c14eda97baf27a5ab547add008fe46171 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Oct 2023 17:31:50 +0900 Subject: [PATCH 33/35] Tidy up `ArgonHealthDisplay` code quality --- .../Screens/Play/HUD/ArgonHealthDisplay.cs | 183 +++++++++--------- 1 file changed, 88 insertions(+), 95 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index f2f71ab64d..6d16915576 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -25,55 +25,64 @@ namespace osu.Game.Screens.Play.HUD { public partial class ArgonHealthDisplay : HealthDisplay, ISerialisableDrawable { + public bool UsesFixedAnchor { get; set; } + private const float curve_start = 280; private const float curve_end = 310; private const float curve_smoothness = 10; private const float bar_length = 350; - private const float bar_height = 32.5f; + private const float bar_verticality = 32.5f; private BarPath healthBar = null!; private BarPath missBar = null!; + private BackgroundPath background = null!; private SliderPath barPath = null!; - private static readonly Colour4 health_bar_colour = Colour4.White; + private static readonly Colour4 main_bar_colour = Colour4.White; + private static readonly Colour4 main_bar_glow_colour = Color4Extensions.FromHex("#7ED7FD").Opacity(0.5f); - // the opacity isn't part of the design, it's only here to control glow intensity. - private static readonly Colour4 health_bar_glow_colour = Color4Extensions.FromHex("#7ED7FD").Opacity(0.5f); - private static readonly Colour4 health_bar_flash_colour = Color4Extensions.FromHex("#7ED7FD").Opacity(0.8f); + private ScheduledDelegate? resetMissBarDelegate; - private static readonly Colour4 miss_bar_colour = Color4Extensions.FromHex("#FF9393"); - private static readonly Colour4 miss_bar_glow_colour = Color4Extensions.FromHex("#FD0000"); + private readonly List missBarVertices = new List(); + private readonly List healthBarVertices = new List(); - // the "flashed" glow colour is just a lightened version of the original one, not part of the design. - private static readonly Colour4 miss_bar_flash_colour = Color4Extensions.FromHex("#FF5D5D"); + private double missBarValue = 1; - public bool UsesFixedAnchor { get; set; } + public double MissBarValue + { + get => missBarValue; + set + { + if (missBarValue == value) + return; + + missBarValue = value; + updatePathVertices(); + } + } + + private double healthBarValue = 1; + + public double HealthBarValue + { + get => healthBarValue; + set + { + if (healthBarValue == value) + return; + + healthBarValue = value; + updatePathVertices(); + } + } [BackgroundDependencyLoader] private void load() { AutoSizeAxes = Axes.Both; - Vector2 diagonalDir = (new Vector2(curve_end, bar_height) - new Vector2(curve_start, 0)).Normalized(); - - // todo: SliderPath or parts of it should be moved away to a utility class as they're useful for making curved paths in general, as done here. - barPath = new SliderPath(new[] - { - new PathControlPoint(new Vector2(0, 0), PathType.Linear), - new PathControlPoint(new Vector2(curve_start - curve_smoothness, 0), PathType.Bezier), - new PathControlPoint(new Vector2(curve_start, 0)), - new PathControlPoint(new Vector2(curve_start, 0) + diagonalDir * curve_smoothness, PathType.Linear), - new PathControlPoint(new Vector2(curve_end, bar_height) - diagonalDir * curve_smoothness, PathType.Bezier), - new PathControlPoint(new Vector2(curve_end, bar_height)), - new PathControlPoint(new Vector2(curve_end + curve_smoothness, bar_height), PathType.Linear), - new PathControlPoint(new Vector2(bar_length, bar_height)), - }); - - var vertices = new List(); - barPath.GetPathToProgress(vertices, 0.0, 1.0); - InternalChild = new FillFlowContainer { AutoSizeAxes = Axes.Both, @@ -83,7 +92,7 @@ namespace osu.Game.Screens.Play.HUD { new Circle { - Margin = new MarginPadding { Top = 10f - 3f / 2f, Left = -2f }, + Margin = new MarginPadding { Top = 8.5f, Left = -2 }, Size = new Vector2(50f, 3f), }, new Container @@ -91,10 +100,9 @@ namespace osu.Game.Screens.Play.HUD AutoSizeAxes = Axes.Both, Children = new Drawable[] { - new BackgroundPath + background = new BackgroundPath { PathRadius = 10f, - Vertices = vertices, }, missBar = new BarPath { @@ -103,25 +111,26 @@ namespace osu.Game.Screens.Play.HUD Blending = BlendingParameters.Additive, Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(0.8f), Color4.White), PathRadius = 40f, - GlowPortion = 0.9f, + // Kinda hacky, but results in correct positioning with increased path radius. Margin = new MarginPadding(-30f), - Vertices = vertices + GlowPortion = 0.9f, }, healthBar = new BarPath { AutoSizeAxes = Axes.None, RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, - BarColour = health_bar_colour, - GlowColour = health_bar_glow_colour, + BarColour = main_bar_colour, + GlowColour = main_bar_glow_colour, PathRadius = 10f, GlowPortion = 0.6f, - Vertices = vertices }, } } }, }; + + updatePath(); } protected override void LoadComplete() @@ -137,28 +146,38 @@ namespace osu.Game.Screens.Play.HUD if (resetMissBarDelegate == null) this.TransformTo(nameof(MissBarValue), v.NewValue, 300, Easing.OutQuint); }, true); - - updatePathVertices(); } protected override void Update() { base.Update(); - healthBar.Alpha = (float)Interpolation.DampContinuously(healthBar.Alpha, (float)(Current.Value > 0 ? 1 : 0), 40, Time.Elapsed); - missBar.Alpha = (float)Interpolation.DampContinuously(missBar.Alpha, (float)(MissBarValue > 0 ? 1 : 0), 40, Time.Elapsed); + healthBar.Alpha = (float)Interpolation.DampContinuously(healthBar.Alpha, Current.Value > 0 ? 1 : 0, 40, Time.Elapsed); + missBar.Alpha = (float)Interpolation.DampContinuously(missBar.Alpha, MissBarValue > 0 ? 1 : 0, 40, Time.Elapsed); } - private ScheduledDelegate? resetMissBarDelegate; + protected override void Flash(JudgementResult result) + { + base.Flash(result); + + healthBar.TransformTo(nameof(BarPath.GlowColour), main_bar_glow_colour.Opacity(0.8f)) + .TransformTo(nameof(BarPath.GlowColour), main_bar_glow_colour, 300, Easing.OutQuint); + + if (resetMissBarDelegate == null) + { + missBar.TransformTo(nameof(BarPath.BarColour), Colour4.White, 100, Easing.OutQuint) + .Then() + .TransformTo(nameof(BarPath.BarColour), main_bar_colour, 800, Easing.OutQuint); + + missBar.TransformTo(nameof(BarPath.GlowColour), Colour4.White) + .TransformTo(nameof(BarPath.GlowColour), main_bar_glow_colour, 800, Easing.OutQuint); + } + } protected override void Miss(JudgementResult result) { base.Miss(result); - if (result.HealthAtJudgement == 0.0) - // health is already empty, nothing should be displayed here. - return; - if (resetMissBarDelegate != null) { resetMissBarDelegate.Cancel(); @@ -170,78 +189,52 @@ namespace osu.Game.Screens.Play.HUD this.Delay(500).Schedule(() => { this.TransformTo(nameof(MissBarValue), Current.Value, 300, Easing.OutQuint); - finishMissBarUsage(); }, out resetMissBarDelegate); - missBar.TransformTo(nameof(BarPath.BarColour), miss_bar_colour, 100, Easing.OutQuint) - .Then() - .TransformTo(nameof(BarPath.BarColour), miss_bar_flash_colour, 800, Easing.OutQuint); + missBar.TransformTo(nameof(BarPath.BarColour), new Colour4(255, 147, 147, 255), 100, Easing.OutQuint).Then() + .TransformTo(nameof(BarPath.BarColour), new Colour4(255, 93, 93, 255), 800, Easing.OutQuint); - missBar.TransformTo(nameof(BarPath.GlowColour), miss_bar_glow_colour.Lighten(0.2f)) - .TransformTo(nameof(BarPath.GlowColour), miss_bar_glow_colour, 800, Easing.OutQuint); + missBar.TransformTo(nameof(BarPath.GlowColour), new Colour4(253, 0, 0, 255).Lighten(0.2f)) + .TransformTo(nameof(BarPath.GlowColour), new Colour4(253, 0, 0, 255), 800, Easing.OutQuint); } private void finishMissBarUsage() { if (Current.Value > 0) { - missBar.TransformTo(nameof(BarPath.BarColour), health_bar_colour, 300, Easing.In); - missBar.TransformTo(nameof(BarPath.GlowColour), health_bar_glow_colour, 300, Easing.In); + missBar.TransformTo(nameof(BarPath.BarColour), main_bar_colour, 300, Easing.In); + missBar.TransformTo(nameof(BarPath.GlowColour), main_bar_glow_colour, 300, Easing.In); } resetMissBarDelegate?.Cancel(); resetMissBarDelegate = null; } - protected override void Flash(JudgementResult result) + private void updatePath() { - base.Flash(result); + Vector2 diagonalDir = (new Vector2(curve_end, bar_verticality) - new Vector2(curve_start, 0)).Normalized(); - healthBar.TransformTo(nameof(BarPath.GlowColour), health_bar_flash_colour) - .TransformTo(nameof(BarPath.GlowColour), health_bar_glow_colour, 300, Easing.OutQuint); - - if (resetMissBarDelegate == null) + barPath = new SliderPath(new[] { - missBar.TransformTo(nameof(BarPath.BarColour), Colour4.White, 100, Easing.OutQuint) - .Then() - .TransformTo(nameof(BarPath.BarColour), health_bar_colour, 800, Easing.OutQuint); + new PathControlPoint(new Vector2(0, 0), PathType.Linear), + new PathControlPoint(new Vector2(curve_start - curve_smoothness, 0), PathType.Bezier), + new PathControlPoint(new Vector2(curve_start, 0)), + new PathControlPoint(new Vector2(curve_start, 0) + diagonalDir * curve_smoothness, PathType.Linear), + new PathControlPoint(new Vector2(curve_end, bar_verticality) - diagonalDir * curve_smoothness, PathType.Bezier), + new PathControlPoint(new Vector2(curve_end, bar_verticality)), + new PathControlPoint(new Vector2(curve_end + curve_smoothness, bar_verticality), PathType.Linear), + new PathControlPoint(new Vector2(bar_length, bar_verticality)), + }); - missBar.TransformTo(nameof(BarPath.GlowColour), Colour4.White) - .TransformTo(nameof(BarPath.GlowColour), health_bar_glow_colour, 800, Easing.OutQuint); - } - } + List vertices = new List(); + barPath.GetPathToProgress(vertices, 0.0, 1.0); - private double missBarValue = 1.0; - private readonly List missBarVertices = new List(); + background.Vertices = vertices; + healthBar.Vertices = vertices; + missBar.Vertices = vertices; - public double MissBarValue - { - get => missBarValue; - set - { - if (missBarValue == value) - return; - - missBarValue = value; - updatePathVertices(); - } - } - - private double healthBarValue = 1.0; - private readonly List healthBarVertices = new List(); - - public double HealthBarValue - { - get => healthBarValue; - set - { - if (healthBarValue == value) - return; - - healthBarValue = value; - updatePathVertices(); - } + updatePathVertices(); } private void updatePathVertices() From 32b2ac4974d13d98f9abf73f47b6c72a12cd65a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Oct 2023 17:41:10 +0900 Subject: [PATCH 34/35] Rename and refactor glow/miss bars to hopefully make more sense --- .../Screens/Play/HUD/ArgonHealthDisplay.cs | 74 ++++++++++--------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index 6d16915576..f7b90fe563 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -34,8 +34,13 @@ namespace osu.Game.Screens.Play.HUD private const float bar_length = 350; private const float bar_verticality = 32.5f; - private BarPath healthBar = null!; - private BarPath missBar = null!; + private BarPath mainBar = null!; + + /// + /// Used to show a glow at the end of the main bar, or red "damage" area when missing. + /// + private BarPath glowBar = null!; + private BackgroundPath background = null!; private SliderPath barPath = null!; @@ -48,17 +53,17 @@ namespace osu.Game.Screens.Play.HUD private readonly List missBarVertices = new List(); private readonly List healthBarVertices = new List(); - private double missBarValue = 1; + private double glowBarValue = 1; - public double MissBarValue + public double GlowBarValue { - get => missBarValue; + get => glowBarValue; set { - if (missBarValue == value) + if (glowBarValue == value) return; - missBarValue = value; + glowBarValue = value; updatePathVertices(); } } @@ -104,7 +109,7 @@ namespace osu.Game.Screens.Play.HUD { PathRadius = 10f, }, - missBar = new BarPath + glowBar = new BarPath { BarColour = Color4.White, GlowColour = OsuColour.Gray(0.5f), @@ -115,7 +120,7 @@ namespace osu.Game.Screens.Play.HUD Margin = new MarginPadding(-30f), GlowPortion = 0.9f, }, - healthBar = new BarPath + mainBar = new BarPath { AutoSizeAxes = Axes.None, RelativeSizeAxes = Axes.Both, @@ -139,12 +144,12 @@ namespace osu.Game.Screens.Play.HUD Current.BindValueChanged(v => { - if (v.NewValue >= MissBarValue) - finishMissBarUsage(); + if (v.NewValue >= GlowBarValue) + finishMissDisplay(); this.TransformTo(nameof(HealthBarValue), v.NewValue, 300, Easing.OutQuint); if (resetMissBarDelegate == null) - this.TransformTo(nameof(MissBarValue), v.NewValue, 300, Easing.OutQuint); + this.TransformTo(nameof(GlowBarValue), v.NewValue, 300, Easing.OutQuint); }, true); } @@ -152,24 +157,24 @@ namespace osu.Game.Screens.Play.HUD { base.Update(); - healthBar.Alpha = (float)Interpolation.DampContinuously(healthBar.Alpha, Current.Value > 0 ? 1 : 0, 40, Time.Elapsed); - missBar.Alpha = (float)Interpolation.DampContinuously(missBar.Alpha, MissBarValue > 0 ? 1 : 0, 40, Time.Elapsed); + mainBar.Alpha = (float)Interpolation.DampContinuously(mainBar.Alpha, Current.Value > 0 ? 1 : 0, 40, Time.Elapsed); + glowBar.Alpha = (float)Interpolation.DampContinuously(glowBar.Alpha, GlowBarValue > 0 ? 1 : 0, 40, Time.Elapsed); } protected override void Flash(JudgementResult result) { base.Flash(result); - healthBar.TransformTo(nameof(BarPath.GlowColour), main_bar_glow_colour.Opacity(0.8f)) - .TransformTo(nameof(BarPath.GlowColour), main_bar_glow_colour, 300, Easing.OutQuint); + mainBar.TransformTo(nameof(BarPath.GlowColour), main_bar_glow_colour.Opacity(0.8f)) + .TransformTo(nameof(BarPath.GlowColour), main_bar_glow_colour, 300, Easing.OutQuint); if (resetMissBarDelegate == null) { - missBar.TransformTo(nameof(BarPath.BarColour), Colour4.White, 100, Easing.OutQuint) + glowBar.TransformTo(nameof(BarPath.BarColour), Colour4.White, 100, Easing.OutQuint) .Then() .TransformTo(nameof(BarPath.BarColour), main_bar_colour, 800, Easing.OutQuint); - missBar.TransformTo(nameof(BarPath.GlowColour), Colour4.White) + glowBar.TransformTo(nameof(BarPath.GlowColour), Colour4.White) .TransformTo(nameof(BarPath.GlowColour), main_bar_glow_colour, 800, Easing.OutQuint); } } @@ -184,27 +189,30 @@ namespace osu.Game.Screens.Play.HUD resetMissBarDelegate = null; } else - this.TransformTo(nameof(MissBarValue), HealthBarValue); + { + // Reset any ongoing animation immediately, else things get weird. + this.TransformTo(nameof(GlowBarValue), HealthBarValue); + } this.Delay(500).Schedule(() => { - this.TransformTo(nameof(MissBarValue), Current.Value, 300, Easing.OutQuint); - finishMissBarUsage(); + this.TransformTo(nameof(GlowBarValue), Current.Value, 300, Easing.OutQuint); + finishMissDisplay(); }, out resetMissBarDelegate); - missBar.TransformTo(nameof(BarPath.BarColour), new Colour4(255, 147, 147, 255), 100, Easing.OutQuint).Then() + glowBar.TransformTo(nameof(BarPath.BarColour), new Colour4(255, 147, 147, 255), 100, Easing.OutQuint).Then() .TransformTo(nameof(BarPath.BarColour), new Colour4(255, 93, 93, 255), 800, Easing.OutQuint); - missBar.TransformTo(nameof(BarPath.GlowColour), new Colour4(253, 0, 0, 255).Lighten(0.2f)) + glowBar.TransformTo(nameof(BarPath.GlowColour), new Colour4(253, 0, 0, 255).Lighten(0.2f)) .TransformTo(nameof(BarPath.GlowColour), new Colour4(253, 0, 0, 255), 800, Easing.OutQuint); } - private void finishMissBarUsage() + private void finishMissDisplay() { if (Current.Value > 0) { - missBar.TransformTo(nameof(BarPath.BarColour), main_bar_colour, 300, Easing.In); - missBar.TransformTo(nameof(BarPath.GlowColour), main_bar_glow_colour, 300, Easing.In); + glowBar.TransformTo(nameof(BarPath.BarColour), main_bar_colour, 300, Easing.In); + glowBar.TransformTo(nameof(BarPath.GlowColour), main_bar_glow_colour, 300, Easing.In); } resetMissBarDelegate?.Cancel(); @@ -231,8 +239,8 @@ namespace osu.Game.Screens.Play.HUD barPath.GetPathToProgress(vertices, 0.0, 1.0); background.Vertices = vertices; - healthBar.Vertices = vertices; - missBar.Vertices = vertices; + mainBar.Vertices = vertices; + glowBar.Vertices = vertices; updatePathVertices(); } @@ -240,7 +248,7 @@ namespace osu.Game.Screens.Play.HUD private void updatePathVertices() { barPath.GetPathToProgress(healthBarVertices, 0.0, healthBarValue); - barPath.GetPathToProgress(missBarVertices, healthBarValue, Math.Max(missBarValue, healthBarValue)); + barPath.GetPathToProgress(missBarVertices, healthBarValue, Math.Max(glowBarValue, healthBarValue)); if (healthBarVertices.Count == 0) healthBarVertices.Add(Vector2.Zero); @@ -248,11 +256,11 @@ namespace osu.Game.Screens.Play.HUD if (missBarVertices.Count == 0) missBarVertices.Add(Vector2.Zero); - missBar.Vertices = missBarVertices.Select(v => v - missBarVertices[0]).ToList(); - missBar.Position = missBarVertices[0]; + glowBar.Vertices = missBarVertices.Select(v => v - missBarVertices[0]).ToList(); + glowBar.Position = missBarVertices[0]; - healthBar.Vertices = healthBarVertices.Select(v => v - healthBarVertices[0]).ToList(); - healthBar.Position = healthBarVertices[0]; + mainBar.Vertices = healthBarVertices.Select(v => v - healthBarVertices[0]).ToList(); + mainBar.Position = healthBarVertices[0]; } private partial class BackgroundPath : SmoothPath From 4f3c433946173001e90f6768e9a06bc510c04f1b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 3 Oct 2023 17:41:52 +0900 Subject: [PATCH 35/35] Move vertex related constants local to method --- osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index f7b90fe563..62a4b958c2 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -27,13 +27,6 @@ namespace osu.Game.Screens.Play.HUD { public bool UsesFixedAnchor { get; set; } - private const float curve_start = 280; - private const float curve_end = 310; - private const float curve_smoothness = 10; - - private const float bar_length = 350; - private const float bar_verticality = 32.5f; - private BarPath mainBar = null!; /// @@ -221,6 +214,13 @@ namespace osu.Game.Screens.Play.HUD private void updatePath() { + const float curve_start = 280; + const float curve_end = 310; + const float curve_smoothness = 10; + + const float bar_length = 350; + const float bar_verticality = 32.5f; + Vector2 diagonalDir = (new Vector2(curve_end, bar_verticality) - new Vector2(curve_start, 0)).Normalized(); barPath = new SliderPath(new[]