diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs new file mode 100644 index 0000000000..181fc8ce98 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs @@ -0,0 +1,62 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Testing; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Judgements; +using osu.Game.Screens.Play; +using osuTK; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneSkinnableHealthDisplay : SkinnableTestScene + { + private IEnumerable healthDisplays => CreatedDrawables.OfType(); + + protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("Create health displays", () => + { + SetContents(() => new SkinnableHealthDisplay()); + }); + AddStep(@"Reset all", delegate + { + foreach (var s in healthDisplays) + s.Current.Value = 1; + }); + } + + [Test] + public void TestHealthDisplayIncrementing() + { + AddRepeatStep(@"decrease hp", delegate + { + foreach (var healthDisplay in healthDisplays) + healthDisplay.Current.Value -= 0.08f; + }, 10); + + AddRepeatStep(@"increase hp without flash", delegate + { + foreach (var healthDisplay in healthDisplays) + healthDisplay.Current.Value += 0.1f; + }, 3); + + AddRepeatStep(@"increase hp with flash", delegate + { + foreach (var healthDisplay in healthDisplays) + { + healthDisplay.Current.Value += 0.1f; + healthDisplay.Flash(new JudgementResult(null, new OsuJudgement())); + } + }, 3); + } + } +} diff --git a/osu.Game/Screens/Play/HUD/StandardHealthDisplay.cs b/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs similarity index 92% rename from osu.Game/Screens/Play/HUD/StandardHealthDisplay.cs rename to osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs index fc4a1a5d83..ae78d19c2d 100644 --- a/osu.Game/Screens/Play/HUD/StandardHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs @@ -16,7 +16,7 @@ using osu.Framework.Utils; namespace osu.Game.Screens.Play.HUD { - public class StandardHealthDisplay : HealthDisplay, IHasAccentColour + public class DefaultHealthDisplay : HealthDisplay, IHasAccentColour { /// /// The base opacity of the glow. @@ -71,8 +71,12 @@ namespace osu.Game.Screens.Play.HUD } } - public StandardHealthDisplay() + public DefaultHealthDisplay() { + Size = new Vector2(1, 5); + RelativeSizeAxes = Axes.X; + Margin = new MarginPadding { Top = 20 }; + Children = new Drawable[] { new Box @@ -103,7 +107,7 @@ namespace osu.Game.Screens.Play.HUD GlowColour = colours.BlueDarker; } - public void Flash(JudgementResult result) + public override void Flash(JudgementResult result) { if (!result.IsHit) return; diff --git a/osu.Game/Screens/Play/HUD/HealthDisplay.cs b/osu.Game/Screens/Play/HUD/HealthDisplay.cs index edc9dedf24..5c43e00192 100644 --- a/osu.Game/Screens/Play/HUD/HealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HealthDisplay.cs @@ -3,6 +3,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; @@ -12,14 +13,18 @@ namespace osu.Game.Screens.Play.HUD /// A container for components displaying the current player health. /// Gets bound automatically to the when inserted to hierarchy. /// - public abstract class HealthDisplay : Container + public abstract class HealthDisplay : Container, IHealthDisplay { - public readonly BindableDouble Current = new BindableDouble(1) + public Bindable Current { get; } = new BindableDouble(1) { MinValue = 0, MaxValue = 1 }; + public virtual void Flash(JudgementResult result) + { + } + /// /// Bind the tracked fields of to this health display. /// diff --git a/osu.Game/Screens/Play/HUD/IHealthDisplay.cs b/osu.Game/Screens/Play/HUD/IHealthDisplay.cs new file mode 100644 index 0000000000..b1a64bd844 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/IHealthDisplay.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Judgements; + +namespace osu.Game.Screens.Play.HUD +{ + /// + /// An interface providing a set of methods to update a health display. + /// + public interface IHealthDisplay : IDrawable + { + /// + /// The current health to be displayed. + /// + Bindable Current { get; } + + /// + /// Flash the display for a specified result type. + /// + /// The result type. + void Flash(JudgementResult result); + } +} diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index fa914c0ebc..0d92611e0e 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Play public readonly SkinnableComboCounter ComboCounter; public readonly SkinnableScoreCounter ScoreCounter; public readonly SkinnableAccuracyCounter AccuracyCounter; - public readonly HealthDisplay HealthDisplay; + public readonly SkinnableHealthDisplay HealthDisplay; public readonly SongProgress Progress; public readonly ModDisplay ModDisplay; public readonly HitErrorDisplay HitErrorDisplay; @@ -272,12 +272,7 @@ namespace osu.Game.Screens.Play protected virtual SkinnableComboCounter CreateComboCounter() => new SkinnableComboCounter(); - protected virtual HealthDisplay CreateHealthDisplay() => new StandardHealthDisplay - { - Size = new Vector2(1, 5), - RelativeSizeAxes = Axes.X, - Margin = new MarginPadding { Top = 20 } - }; + protected virtual SkinnableHealthDisplay CreateHealthDisplay() => new SkinnableHealthDisplay(); protected virtual FailingLayer CreateFailingLayer() => new FailingLayer { @@ -320,7 +315,7 @@ namespace osu.Game.Screens.Play AccuracyCounter?.Current.BindTo(processor.Accuracy); ComboCounter?.Current.BindTo(processor.Combo); - if (HealthDisplay is StandardHealthDisplay shd) + if (HealthDisplay.Drawable is IHealthDisplay shd) processor.NewJudgement += shd.Flash; } diff --git a/osu.Game/Screens/Play/SkinnableHealthDisplay.cs b/osu.Game/Screens/Play/SkinnableHealthDisplay.cs new file mode 100644 index 0000000000..5b77343278 --- /dev/null +++ b/osu.Game/Screens/Play/SkinnableHealthDisplay.cs @@ -0,0 +1,47 @@ +// 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 osu.Framework.Bindables; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Play.HUD; +using osu.Game.Skinning; + +namespace osu.Game.Screens.Play +{ + public class SkinnableHealthDisplay : SkinnableDrawable, IHealthDisplay + { + public Bindable Current { get; } = new Bindable(); + + public void Flash(JudgementResult result) => skinnedCounter?.Flash(result); + + private HealthProcessor processor; + + public void BindHealthProcessor(HealthProcessor processor) + { + if (this.processor != null) + throw new InvalidOperationException("Can't bind to a processor more than once"); + + this.processor = processor; + + Current.BindTo(processor.Health); + } + + public SkinnableHealthDisplay() + : base(new HUDSkinComponent(HUDSkinComponents.HealthDisplay), _ => new DefaultHealthDisplay()) + { + CentreComponent = false; + } + + private IHealthDisplay skinnedCounter; + + protected override void SkinChanged(ISkinSource skin, bool allowFallback) + { + base.SkinChanged(skin, allowFallback); + + skinnedCounter = Drawable as IHealthDisplay; + skinnedCounter?.Current.BindTo(Current); + } + } +} diff --git a/osu.Game/Skinning/HUDSkinComponents.cs b/osu.Game/Skinning/HUDSkinComponents.cs index d690a23dee..8772704cef 100644 --- a/osu.Game/Skinning/HUDSkinComponents.cs +++ b/osu.Game/Skinning/HUDSkinComponents.cs @@ -7,6 +7,7 @@ namespace osu.Game.Skinning { ComboCounter, ScoreCounter, - AccuracyCounter + AccuracyCounter, + HealthDisplay } }