diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScoreCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScoreCounter.cs index ab010bee9f..34c657bf7f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScoreCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScoreCounter.cs @@ -16,7 +16,7 @@ namespace osu.Game.Tests.Visual.Gameplay { int numerator = 0, denominator = 0; - ScoreCounter score = new ScoreCounter(7) + ScoreCounter score = new DefaultScoreCounter { Origin = Anchor.TopRight, Anchor = Anchor.TopRight, diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs new file mode 100644 index 0000000000..2d5003d1da --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.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.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Testing; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Play.HUD; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneSkinnableScoreCounter : SkinnableTestScene + { + private IEnumerable scoreCounters => CreatedDrawables.OfType(); + + protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("Create combo counters", () => SetContents(() => + { + var comboCounter = new SkinnableScoreCounter(); + comboCounter.Current.Value = 1; + return comboCounter; + })); + } + + [Test] + public void TestScoreCounterIncrementing() + { + AddStep(@"Reset all", delegate + { + foreach (var s in scoreCounters) + s.Current.Value = 0; + }); + + AddStep(@"Hit! :D", delegate + { + foreach (var s in scoreCounters) + s.Current.Value += 300; + }); + } + } +} diff --git a/osu.Game/Graphics/UserInterface/ScoreCounter.cs b/osu.Game/Graphics/UserInterface/ScoreCounter.cs index 73bbe5f03e..17e5ceedb9 100644 --- a/osu.Game/Graphics/UserInterface/ScoreCounter.cs +++ b/osu.Game/Graphics/UserInterface/ScoreCounter.cs @@ -1,18 +1,21 @@ // 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.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Screens.Play.HUD; namespace osu.Game.Graphics.UserInterface { - public class ScoreCounter : RollingCounter + public abstract class ScoreCounter : RollingCounter, IScoreCounter { protected override double RollingDuration => 1000; protected override Easing RollingEasing => Easing.Out; - public bool UseCommaSeparator; + /// + /// Whether comma separators should be displayed. + /// + public bool UseCommaSeparator { get; } /// /// How many leading zeroes the counter has. @@ -23,14 +26,13 @@ namespace osu.Game.Graphics.UserInterface /// Displays score. /// /// How many leading zeroes the counter will have. - public ScoreCounter(uint leading = 0) + /// Whether comma separators should be displayed. + protected ScoreCounter(uint leading = 0, bool useCommaSeparator = false) { + UseCommaSeparator = useCommaSeparator; LeadingZeroes = leading; } - [BackgroundDependencyLoader] - private void load(OsuColour colours) => Colour = colours.BlueLighter; - protected override double GetProportionalDuration(double currentValue, double newValue) { return currentValue > newValue ? currentValue - newValue : newValue - currentValue; diff --git a/osu.Game/Screens/Play/HUD/DefaultComboCounter.cs b/osu.Game/Screens/Play/HUD/DefaultComboCounter.cs index d6a4d30af6..a5c33f6dbe 100644 --- a/osu.Game/Screens/Play/HUD/DefaultComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/DefaultComboCounter.cs @@ -32,10 +32,10 @@ namespace osu.Game.Screens.Play.HUD { base.Update(); - if (hud != null) + if (hud?.ScoreCounter.Drawable is DefaultScoreCounter score) { // for now align with the score counter. eventually this will be user customisable. - Position = Parent.ToLocalSpace(hud.ScoreCounter.ScreenSpaceDrawQuad.TopRight) + offset; + Position = Parent.ToLocalSpace(score.ScreenSpaceDrawQuad.TopRight) + offset; } } diff --git a/osu.Game/Screens/Play/HUD/DefaultScoreCounter.cs b/osu.Game/Screens/Play/HUD/DefaultScoreCounter.cs new file mode 100644 index 0000000000..1dcfe2e067 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/DefaultScoreCounter.cs @@ -0,0 +1,35 @@ +// 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.Allocation; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Screens.Play.HUD +{ + public class DefaultScoreCounter : ScoreCounter + { + public DefaultScoreCounter() + : base(6) + { + Anchor = Anchor.TopCentre; + Origin = Anchor.TopCentre; + } + + [Resolved(canBeNull: true)] + private HUDOverlay hud { get; set; } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Colour = colours.BlueLighter; + + // todo: check if default once health display is skinnable + hud?.ShowHealthbar.BindValueChanged(healthBar => + { + this.MoveToY(healthBar.NewValue ? 30 : 0, HUDOverlay.FADE_DURATION, HUDOverlay.FADE_EASING); + }, true); + } + } +} diff --git a/osu.Game/Screens/Play/HUD/IScoreCounter.cs b/osu.Game/Screens/Play/HUD/IScoreCounter.cs new file mode 100644 index 0000000000..2d39a64cfe --- /dev/null +++ b/osu.Game/Screens/Play/HUD/IScoreCounter.cs @@ -0,0 +1,19 @@ +// 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; + +namespace osu.Game.Screens.Play.HUD +{ + /// + /// An interface providing a set of methods to update a score counter. + /// + public interface IScoreCounter : IDrawable + { + /// + /// The current score to be displayed. + /// + Bindable Current { get; } + } +} diff --git a/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs b/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs index 5d96a48117..cc9398bc35 100644 --- a/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Play.HUD Anchor = Anchor.BottomLeft; Origin = Anchor.BottomLeft; - Margin = new MarginPadding { Bottom = 10, Left = 10 }; + Margin = new MarginPadding(10); Scale = new Vector2(1.2f); } diff --git a/osu.Game/Screens/Play/HUD/ModDisplay.cs b/osu.Game/Screens/Play/HUD/ModDisplay.cs index 99c31241f1..68d019bf71 100644 --- a/osu.Game/Screens/Play/HUD/ModDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ModDisplay.cs @@ -48,22 +48,29 @@ namespace osu.Game.Screens.Play.HUD { AutoSizeAxes = Axes.Both; - Children = new Drawable[] + Child = new FillFlowContainer { - iconsContainer = new ReverseChildIDFillFlowContainer + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, + iconsContainer = new ReverseChildIDFillFlowContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + }, + unrankedText = new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = @"/ UNRANKED /", + Font = OsuFont.Numeric.With(size: 12) + } }, - unrankedText = new OsuSpriteText - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.TopCentre, - Text = @"/ UNRANKED /", - Font = OsuFont.Numeric.With(size: 12) - } }; Current.ValueChanged += mods => diff --git a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs index fc80983834..ffcbb06fb3 100644 --- a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs +++ b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs @@ -20,14 +20,13 @@ namespace osu.Game.Screens.Play.HUD public readonly VisualSettings VisualSettings; - //public readonly CollectionSettings CollectionSettings; - - //public readonly DiscussionSettings DiscussionSettings; - public PlayerSettingsOverlay() { AlwaysPresent = true; - RelativeSizeAxes = Axes.Both; + + Anchor = Anchor.TopRight; + Origin = Anchor.TopRight; + AutoSizeAxes = Axes.Both; Child = new FillFlowContainer { @@ -36,7 +35,6 @@ namespace osu.Game.Screens.Play.HUD AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, Spacing = new Vector2(0, 20), - Margin = new MarginPadding { Top = 100, Right = 10 }, Children = new PlayerSettingsGroup[] { //CollectionSettings = new CollectionSettings(), diff --git a/osu.Game/Screens/Play/HUD/SkinnableScoreCounter.cs b/osu.Game/Screens/Play/HUD/SkinnableScoreCounter.cs new file mode 100644 index 0000000000..a442ad0d9a --- /dev/null +++ b/osu.Game/Screens/Play/HUD/SkinnableScoreCounter.cs @@ -0,0 +1,29 @@ +// 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.Game.Skinning; + +namespace osu.Game.Screens.Play.HUD +{ + public class SkinnableScoreCounter : SkinnableDrawable, IScoreCounter + { + public Bindable Current { get; } = new Bindable(); + + public SkinnableScoreCounter() + : base(new HUDSkinComponent(HUDSkinComponents.ScoreCounter), _ => new DefaultScoreCounter()) + { + CentreComponent = false; + } + + private IScoreCounter skinnedCounter; + + protected override void SkinChanged(ISkinSource skin, bool allowFallback) + { + base.SkinChanged(skin, allowFallback); + + skinnedCounter = Drawable as IScoreCounter; + skinnedCounter?.Current.BindTo(Current); + } + } +} diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index a3547bbc68..639da7a3b6 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -25,12 +25,13 @@ namespace osu.Game.Screens.Play [Cached] public class HUDOverlay : Container { - private const float fade_duration = 400; - private const Easing fade_easing = Easing.Out; + public const float FADE_DURATION = 400; + + public const Easing FADE_EASING = Easing.Out; public readonly KeyCounterDisplay KeyCounter; public readonly SkinnableComboCounter ComboCounter; - public readonly ScoreCounter ScoreCounter; + public readonly SkinnableScoreCounter ScoreCounter; public readonly RollingCounter AccuracyCounter; public readonly HealthDisplay HealthDisplay; public readonly SongProgress Progress; @@ -62,9 +63,8 @@ namespace osu.Game.Screens.Play public Action RequestSeek; - private readonly Container topScoreContainer; - private readonly FillFlowContainer bottomRightElements; + private readonly FillFlowContainer topRightElements; private IEnumerable hideTargets => new Drawable[] { visibilityContainer, KeyCounter }; @@ -96,21 +96,10 @@ namespace osu.Game.Screens.Play Children = new Drawable[] { HealthDisplay = CreateHealthDisplay(), - topScoreContainer = new Container - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - AccuracyCounter = CreateAccuracyCounter(), - ScoreCounter = CreateScoreCounter(), - }, - }, + AccuracyCounter = CreateAccuracyCounter(), + ScoreCounter = CreateScoreCounter(), ComboCounter = CreateComboCounter(), - ModDisplay = CreateModsContainer(), HitErrorDisplay = CreateHitErrorDisplayOverlay(), - PlayerSettingsOverlay = CreatePlayerSettingsOverlay(), } }, }, @@ -126,14 +115,29 @@ namespace osu.Game.Screens.Play } }, }, + topRightElements = new FillFlowContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Margin = new MarginPadding(10), + Spacing = new Vector2(10), + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + ModDisplay = CreateModsContainer(), + PlayerSettingsOverlay = CreatePlayerSettingsOverlay(), + } + }, bottomRightElements = new FillFlowContainer { Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, - X = -5, + Margin = new MarginPadding(10), + Spacing = new Vector2(10), AutoSizeAxes = Axes.Both, - LayoutDuration = fade_duration / 2, - LayoutEasing = fade_easing, + LayoutDuration = FADE_DURATION / 2, + LayoutEasing = FADE_EASING, Direction = FillDirection.Vertical, Children = new Drawable[] { @@ -186,21 +190,8 @@ namespace osu.Game.Screens.Play { base.LoadComplete(); - ShowHud.BindValueChanged(visible => hideTargets.ForEach(d => d.FadeTo(visible.NewValue ? 1 : 0, fade_duration, fade_easing))); - - ShowHealthbar.BindValueChanged(healthBar => - { - if (healthBar.NewValue) - { - HealthDisplay.FadeIn(fade_duration, fade_easing); - topScoreContainer.MoveToY(30, fade_duration, fade_easing); - } - else - { - HealthDisplay.FadeOut(fade_duration, fade_easing); - topScoreContainer.MoveToY(0, fade_duration, fade_easing); - } - }, true); + ShowHealthbar.BindValueChanged(healthBar => HealthDisplay.FadeTo(healthBar.NewValue ? 1 : 0, FADE_DURATION, FADE_EASING), true); + ShowHud.BindValueChanged(visible => hideTargets.ForEach(d => d.FadeTo(visible.NewValue ? 1 : 0, FADE_DURATION, FADE_EASING))); configShowHud.BindValueChanged(visible => { @@ -214,6 +205,8 @@ namespace osu.Game.Screens.Play protected override void Update() { base.Update(); + + topRightElements.Y = ToLocalSpace(ScoreCounter.Drawable.ScreenSpaceDrawQuad.BottomRight).Y; bottomRightElements.Y = -Progress.Height; } @@ -269,11 +262,7 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding { Top = 5, Right = 20 }, }; - protected virtual ScoreCounter CreateScoreCounter() => new ScoreCounter(6) - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - }; + protected virtual SkinnableScoreCounter CreateScoreCounter() => new SkinnableScoreCounter(); protected virtual SkinnableComboCounter CreateComboCounter() => new SkinnableComboCounter(); @@ -293,7 +282,6 @@ namespace osu.Game.Screens.Play { Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, - Margin = new MarginPadding(10), }; protected virtual SongProgress CreateProgress() => new SongProgress @@ -314,7 +302,6 @@ namespace osu.Game.Screens.Play Anchor = Anchor.TopRight, Origin = Anchor.TopRight, AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Top = 20, Right = 20 }, }; protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay(scoreProcessor, drawableRuleset?.FirstAvailableHitWindows); diff --git a/osu.Game/Skinning/HUDSkinComponents.cs b/osu.Game/Skinning/HUDSkinComponents.cs index 06b22dc693..d810fc31d4 100644 --- a/osu.Game/Skinning/HUDSkinComponents.cs +++ b/osu.Game/Skinning/HUDSkinComponents.cs @@ -6,5 +6,6 @@ namespace osu.Game.Skinning public enum HUDSkinComponents { ComboCounter, + ScoreCounter } } diff --git a/osu.Game/Skinning/LegacyScoreCounter.cs b/osu.Game/Skinning/LegacyScoreCounter.cs new file mode 100644 index 0000000000..f94bef6652 --- /dev/null +++ b/osu.Game/Skinning/LegacyScoreCounter.cs @@ -0,0 +1,41 @@ +// 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.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Skinning +{ + public class LegacyScoreCounter : ScoreCounter + { + private readonly ISkin skin; + + protected override double RollingDuration => 1000; + protected override Easing RollingEasing => Easing.Out; + + public new Bindable Current { get; } = new Bindable(); + + public LegacyScoreCounter(ISkin skin) + : base(6) + { + Anchor = Anchor.TopRight; + Origin = Anchor.TopRight; + + this.skin = skin; + + // base class uses int for display, but externally we bind to ScoreProcesssor as a double for now. + Current.BindValueChanged(v => base.Current.Value = (int)v.NewValue); + + Margin = new MarginPadding(10); + } + + protected sealed override OsuSpriteText CreateSpriteText() => + new LegacySpriteText(skin, "score" /*, true*/) + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }; + } +} diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index ea5a6e4e20..c8460ad797 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -341,6 +341,9 @@ namespace osu.Game.Skinning { case HUDSkinComponents.ComboCounter: return new LegacyComboCounter(); + + case HUDSkinComponents.ScoreCounter: + return new LegacyScoreCounter(this); } return null;