From 622cbc3af7e787257f8d5f31f0c98bfef8a97cf0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 16:07:45 +0900 Subject: [PATCH 1/5] Adjust test scene to actually make HP bars fit --- .../Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs index 4d8ddcd581..8d3eee2445 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs @@ -12,6 +12,7 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; +using osuTK; namespace osu.Game.Tests.Visual.Gameplay { @@ -20,9 +21,9 @@ 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(); + protected override Drawable CreateArgonImplementation() => new ArgonHealthDisplay { Scale = new Vector2(0.6f) }; + protected override Drawable CreateDefaultImplementation() => new DefaultHealthDisplay { Scale = new Vector2(0.6f) }; + protected override Drawable CreateLegacyImplementation() => new LegacyHealthDisplay { Scale = new Vector2(0.6f) }; [SetUpSteps] public void SetUpSteps() @@ -62,4 +63,4 @@ namespace osu.Game.Tests.Visual.Gameplay }, 3); } } -} \ No newline at end of file +} From 82ba545358723a8560de4444568b107f029a6bfa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2023 17:01:56 +0900 Subject: [PATCH 2/5] Add initial animation for health bars --- .../Screens/Play/HUD/ArgonHealthDisplay.cs | 4 +- osu.Game/Screens/Play/HUD/HealthDisplay.cs | 42 ++++++++++++++++++- osu.Game/Skinning/LegacyHealthDisplay.cs | 1 + 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs index 6cf1daa102..68685d7eb5 100644 --- a/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ArgonHealthDisplay.cs @@ -212,7 +212,7 @@ namespace osu.Game.Screens.Play.HUD } } - private double missBarValue = 1.0; + private double missBarValue; private readonly List missBarVertices = new List(); public double MissBarValue @@ -228,7 +228,7 @@ namespace osu.Game.Screens.Play.HUD } } - private double healthBarValue = 1.0; + private double healthBarValue; private readonly List healthBarVertices = new List(); public double HealthBarValue diff --git a/osu.Game/Screens/Play/HUD/HealthDisplay.cs b/osu.Game/Screens/Play/HUD/HealthDisplay.cs index 5131f93ca2..e4bb91e7ca 100644 --- a/osu.Game/Screens/Play/HUD/HealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HealthDisplay.cs @@ -6,7 +6,9 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Threading; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; @@ -23,12 +25,16 @@ namespace osu.Game.Screens.Play.HUD [Resolved] protected HealthProcessor HealthProcessor { get; private set; } = null!; - public Bindable Current { get; } = new BindableDouble(1) + public Bindable Current { get; } = new BindableDouble { MinValue = 0, MaxValue = 1 }; + private BindableNumber health = null!; + + private ScheduledDelegate? initialIncrease; + /// /// Triggered when a is a successful hit, signaling the health display to perform a flash animation (if designed to do so). /// @@ -52,14 +58,46 @@ namespace osu.Game.Screens.Play.HUD { base.LoadComplete(); - Current.BindTo(HealthProcessor.Health); HealthProcessor.NewJudgement += onNewJudgement; + // Don't bind directly so we can animate the startup procedure. + health = HealthProcessor.Health.GetBoundCopy(); + health.BindValueChanged(h => + { + Current.Value = h.NewValue; + finishInitialAnimation(); + }); + if (hudOverlay != null) showHealthBar.BindTo(hudOverlay.ShowHealthBar); // this probably shouldn't be operating on `this.` showHealthBar.BindValueChanged(healthBar => this.FadeTo(healthBar.NewValue ? 1 : 0, HUDOverlay.FADE_DURATION, HUDOverlay.FADE_EASING), true); + + startInitialAnimation(); + } + + private void startInitialAnimation() + { + // TODO: this should run in gameplay time, including showing a larger increase when skipping. + // TODO: it should also start increasing relative to the first hitobject. + const double increase_delay = 150; + + initialIncrease = Scheduler.AddDelayed(() => + { + double newValue = Current.Value + 0.05f; + this.TransformBindableTo(Current, newValue, increase_delay); + Flash(new JudgementResult(new HitObject(), new Judgement())); + + if (newValue >= 1) + finishInitialAnimation(); + }, increase_delay, true); + } + + private void finishInitialAnimation() + { + initialIncrease?.Cancel(); + initialIncrease = null; } private void onNewJudgement(JudgementResult judgement) diff --git a/osu.Game/Skinning/LegacyHealthDisplay.cs b/osu.Game/Skinning/LegacyHealthDisplay.cs index f785022f84..08add79fc1 100644 --- a/osu.Game/Skinning/LegacyHealthDisplay.cs +++ b/osu.Game/Skinning/LegacyHealthDisplay.cs @@ -66,6 +66,7 @@ namespace osu.Game.Skinning marker.Current.BindTo(Current); maxFillWidth = fill.Width; + fill.Width = 0; } protected override void Update() From 58448d3dd95f64e7b1d0c43492516b64f34f6086 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 7 Oct 2023 01:03:41 +0900 Subject: [PATCH 3/5] Fix health animation affecting failing tint --- osu.Game/Screens/Play/HUD/FailingLayer.cs | 2 ++ osu.Game/Screens/Play/HUD/HealthDisplay.cs | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/FailingLayer.cs b/osu.Game/Screens/Play/HUD/FailingLayer.cs index 67e7ae8f3f..3954e23cbe 100644 --- a/osu.Game/Screens/Play/HUD/FailingLayer.cs +++ b/osu.Game/Screens/Play/HUD/FailingLayer.cs @@ -29,6 +29,8 @@ namespace osu.Game.Screens.Play.HUD /// public readonly Bindable ShowHealth = new Bindable(); + protected override bool PlayInitialIncreaseAnimation => false; + private const float max_alpha = 0.4f; private const int fade_time = 400; private const float gradient_size = 0.2f; diff --git a/osu.Game/Screens/Play/HUD/HealthDisplay.cs b/osu.Game/Screens/Play/HUD/HealthDisplay.cs index e4bb91e7ca..24af3051e3 100644 --- a/osu.Game/Screens/Play/HUD/HealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HealthDisplay.cs @@ -25,6 +25,8 @@ namespace osu.Game.Screens.Play.HUD [Resolved] protected HealthProcessor HealthProcessor { get; private set; } = null!; + protected virtual bool PlayInitialIncreaseAnimation => true; + public Bindable Current { get; } = new BindableDouble { MinValue = 0, @@ -74,7 +76,10 @@ namespace osu.Game.Screens.Play.HUD // this probably shouldn't be operating on `this.` showHealthBar.BindValueChanged(healthBar => this.FadeTo(healthBar.NewValue ? 1 : 0, HUDOverlay.FADE_DURATION, HUDOverlay.FADE_EASING), true); - startInitialAnimation(); + if (PlayInitialIncreaseAnimation) + startInitialAnimation(); + else + Current.Value = 1; } private void startInitialAnimation() From ce0d4bd0df26839eab2dec51f9312f5a614eb008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 6 Oct 2023 21:30:41 +0200 Subject: [PATCH 4/5] Fix health display potentially desyncing from actual if health was changed during initial animation --- osu.Game/Screens/Play/HUD/HealthDisplay.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HealthDisplay.cs b/osu.Game/Screens/Play/HUD/HealthDisplay.cs index 24af3051e3..2ec63feeae 100644 --- a/osu.Game/Screens/Play/HUD/HealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HealthDisplay.cs @@ -66,8 +66,8 @@ namespace osu.Game.Screens.Play.HUD health = HealthProcessor.Health.GetBoundCopy(); health.BindValueChanged(h => { - Current.Value = h.NewValue; finishInitialAnimation(); + Current.Value = h.NewValue; }); if (hudOverlay != null) @@ -103,6 +103,11 @@ namespace osu.Game.Screens.Play.HUD { initialIncrease?.Cancel(); initialIncrease = null; + + // aside from the repeating `initialIncrease` scheduled task, + // there may also be a `Current` transform in progress from that schedule. + // ensure it plays out fully, to prevent changes to `Current.Value` being discarded by the ongoing transform. + FinishTransforms(); } private void onNewJudgement(JudgementResult judgement) From b7d0bf37567fe198a9e15936f2ca46ccefe1a390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 6 Oct 2023 21:39:29 +0200 Subject: [PATCH 5/5] Only flush the `Current` transform specifically --- osu.Game/Screens/Play/HUD/HealthDisplay.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HealthDisplay.cs b/osu.Game/Screens/Play/HUD/HealthDisplay.cs index 2ec63feeae..986efe3036 100644 --- a/osu.Game/Screens/Play/HUD/HealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HealthDisplay.cs @@ -107,7 +107,9 @@ namespace osu.Game.Screens.Play.HUD // aside from the repeating `initialIncrease` scheduled task, // there may also be a `Current` transform in progress from that schedule. // ensure it plays out fully, to prevent changes to `Current.Value` being discarded by the ongoing transform. - FinishTransforms(); + // and yes, this funky `targetMember` spec is seemingly the only way to do this + // (see: https://github.com/ppy/osu-framework/blob/fe2769171c6e26d1b6fdd6eb7ea8353162fe9065/osu.Framework/Graphics/Transforms/TransformBindable.cs#L21) + FinishTransforms(targetMember: $"{Current.GetHashCode()}.{nameof(Current.Value)}"); } private void onNewJudgement(JudgementResult judgement)