From 254eba90080f04398ade62a52c85b67345068954 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Oct 2020 17:48:50 +0900 Subject: [PATCH 1/6] Add and consume skinnable accuracy counter --- .../UserInterface/PercentageCounter.cs | 4 -- .../Play/HUD/DefaultAccuracyCounter.cs | 41 ++++++++++++++++ osu.Game/Screens/Play/HUD/IAccuracyCounter.cs | 19 ++++++++ .../Play/HUD/SkinnableAccuracyCounter.cs | 29 ++++++++++++ osu.Game/Screens/Play/HUDOverlay.cs | 11 +---- osu.Game/Skinning/HUDSkinComponents.cs | 3 +- osu.Game/Skinning/LegacyAccuracyCounter.cs | 47 +++++++++++++++++++ osu.Game/Skinning/LegacySkin.cs | 3 ++ 8 files changed, 143 insertions(+), 14 deletions(-) create mode 100644 osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs create mode 100644 osu.Game/Screens/Play/HUD/IAccuracyCounter.cs create mode 100644 osu.Game/Screens/Play/HUD/SkinnableAccuracyCounter.cs create mode 100644 osu.Game/Skinning/LegacyAccuracyCounter.cs diff --git a/osu.Game/Graphics/UserInterface/PercentageCounter.cs b/osu.Game/Graphics/UserInterface/PercentageCounter.cs index 1ccf7798e5..2d53ec066b 100644 --- a/osu.Game/Graphics/UserInterface/PercentageCounter.cs +++ b/osu.Game/Graphics/UserInterface/PercentageCounter.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Utils; @@ -28,9 +27,6 @@ namespace osu.Game.Graphics.UserInterface Current.Value = DisplayedCount = 1.0f; } - [BackgroundDependencyLoader] - private void load(OsuColour colours) => Colour = colours.BlueLighter; - protected override string FormatCount(double count) => count.FormatAccuracy(); protected override double GetProportionalDuration(double currentValue, double newValue) diff --git a/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs new file mode 100644 index 0000000000..b286b380e0 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.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.Allocation; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osuTK; + +namespace osu.Game.Screens.Play.HUD +{ + public class DefaultAccuracyCounter : PercentageCounter, IAccuracyCounter + { + private readonly Vector2 offset = new Vector2(-20, 5); + + public DefaultAccuracyCounter() + { + Origin = Anchor.TopRight; + } + + [Resolved(canBeNull: true)] + private HUDOverlay hud { get; set; } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Colour = colours.BlueLighter; + } + + protected override void Update() + { + base.Update(); + + if (hud?.ScoreCounter.Drawable is DefaultScoreCounter score) + { + // for now align with the score counter. eventually this will be user customisable. + Position = Parent.ToLocalSpace(score.ScreenSpaceDrawQuad.TopLeft) + offset; + } + } + } +} diff --git a/osu.Game/Screens/Play/HUD/IAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/IAccuracyCounter.cs new file mode 100644 index 0000000000..0199250a08 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/IAccuracyCounter.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 accuracy counter. + /// + public interface IAccuracyCounter : IDrawable + { + /// + /// The current accuracy to be displayed. + /// + Bindable Current { get; } + } +} diff --git a/osu.Game/Screens/Play/HUD/SkinnableAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/SkinnableAccuracyCounter.cs new file mode 100644 index 0000000000..76c9c30813 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/SkinnableAccuracyCounter.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 SkinnableAccuracyCounter : SkinnableDrawable, IAccuracyCounter + { + public Bindable Current { get; } = new Bindable(); + + public SkinnableAccuracyCounter() + : base(new HUDSkinComponent(HUDSkinComponents.AccuracyCounter), _ => new DefaultAccuracyCounter()) + { + CentreComponent = false; + } + + private IAccuracyCounter skinnedCounter; + + protected override void SkinChanged(ISkinSource skin, bool allowFallback) + { + base.SkinChanged(skin, allowFallback); + + skinnedCounter = Drawable as IAccuracyCounter; + skinnedCounter?.Current.BindTo(Current); + } + } +} diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 639da7a3b6..bb35bd3d69 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Game.Configuration; -using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Mods; @@ -32,7 +31,7 @@ namespace osu.Game.Screens.Play public readonly KeyCounterDisplay KeyCounter; public readonly SkinnableComboCounter ComboCounter; public readonly SkinnableScoreCounter ScoreCounter; - public readonly RollingCounter AccuracyCounter; + public readonly SkinnableAccuracyCounter AccuracyCounter; public readonly HealthDisplay HealthDisplay; public readonly SongProgress Progress; public readonly ModDisplay ModDisplay; @@ -254,13 +253,7 @@ namespace osu.Game.Screens.Play return base.OnKeyDown(e); } - protected virtual RollingCounter CreateAccuracyCounter() => new PercentageCounter - { - BypassAutoSizeAxes = Axes.X, - Anchor = Anchor.TopLeft, - Origin = Anchor.TopRight, - Margin = new MarginPadding { Top = 5, Right = 20 }, - }; + protected virtual SkinnableAccuracyCounter CreateAccuracyCounter() => new SkinnableAccuracyCounter(); protected virtual SkinnableScoreCounter CreateScoreCounter() => new SkinnableScoreCounter(); diff --git a/osu.Game/Skinning/HUDSkinComponents.cs b/osu.Game/Skinning/HUDSkinComponents.cs index d810fc31d4..d690a23dee 100644 --- a/osu.Game/Skinning/HUDSkinComponents.cs +++ b/osu.Game/Skinning/HUDSkinComponents.cs @@ -6,6 +6,7 @@ namespace osu.Game.Skinning public enum HUDSkinComponents { ComboCounter, - ScoreCounter + ScoreCounter, + AccuracyCounter } } diff --git a/osu.Game/Skinning/LegacyAccuracyCounter.cs b/osu.Game/Skinning/LegacyAccuracyCounter.cs new file mode 100644 index 0000000000..0f3ac19ce6 --- /dev/null +++ b/osu.Game/Skinning/LegacyAccuracyCounter.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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD; +using osuTK; + +namespace osu.Game.Skinning +{ + public class LegacyAccuracyCounter : PercentageCounter, IAccuracyCounter + { + private readonly ISkin skin; + + public LegacyAccuracyCounter(ISkin skin) + { + Origin = Anchor.TopRight; + Scale = new Vector2(0.75f); + + this.skin = skin; + } + + [Resolved(canBeNull: true)] + private HUDOverlay hud { get; set; } + + protected sealed override OsuSpriteText CreateSpriteText() => + new LegacySpriteText(skin, "score" /*, true*/) + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }; + + protected override void Update() + { + base.Update(); + + if (hud?.ScoreCounter.Drawable is LegacyScoreCounter score) + { + // for now align with the score counter. eventually this will be user customisable. + Position = Parent.ToLocalSpace(score.ScreenSpaceDrawQuad.BottomRight); + } + } + } +} diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index c8460ad797..e1cd095ba8 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -344,6 +344,9 @@ namespace osu.Game.Skinning case HUDSkinComponents.ScoreCounter: return new LegacyScoreCounter(this); + + case HUDSkinComponents.AccuracyCounter: + return new LegacyAccuracyCounter(this); } return null; From 4f6dd1586939eef71e4578131e4e5f55155421ad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Oct 2020 17:56:37 +0900 Subject: [PATCH 2/6] Add legacy font lookup support for comma/percent --- osu.Game/Skinning/LegacySpriteText.cs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacySpriteText.cs b/osu.Game/Skinning/LegacySpriteText.cs index 858bbcd6a8..8394657b1c 100644 --- a/osu.Game/Skinning/LegacySpriteText.cs +++ b/osu.Game/Skinning/LegacySpriteText.cs @@ -34,7 +34,9 @@ namespace osu.Game.Skinning public ITexturedCharacterGlyph Get(string fontName, char character) { - var texture = skin.GetTexture($"{fontName}-{character}"); + var lookup = getLookupName(character); + + var texture = skin.GetTexture($"{fontName}-{lookup}"); if (texture == null) return null; @@ -42,6 +44,24 @@ namespace osu.Game.Skinning return new TexturedCharacterGlyph(new CharacterGlyph(character, 0, 0, texture.Width, null), texture, 1f / texture.ScaleAdjust); } + private static string getLookupName(char character) + { + switch (character) + { + case ',': + return "comma"; + + case '.': + return "dot"; + + case '%': + return "percent"; + + default: + return character.ToString(); + } + } + public Task GetAsync(string fontName, char character) => Task.Run(() => Get(fontName, character)); } } From b31a3fbabbe83ec779f789b9286c0f1bb025c1cf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Oct 2020 18:11:30 +0900 Subject: [PATCH 3/6] Add test --- .../TestSceneSkinnableAccuracyCounter.cs | 49 +++++++++++++++++++ .../Play/HUD/DefaultAccuracyCounter.cs | 2 + osu.Game/Skinning/LegacyAccuracyCounter.cs | 4 +- 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs new file mode 100644 index 0000000000..709929dcb0 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs @@ -0,0 +1,49 @@ +// 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 TestSceneSkinnableAccuracyCounter : SkinnableTestScene + { + private IEnumerable accuracyCounters => CreatedDrawables.OfType(); + + protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("Create combo counters", () => SetContents(() => + { + var accuracyCounter = new SkinnableAccuracyCounter(); + + accuracyCounter.Current.Value = 1; + + return accuracyCounter; + })); + } + + [Test] + public void TestChangingAccuracy() + { + AddStep(@"Reset all", delegate + { + foreach (var s in accuracyCounters) + s.Current.Value = 1; + }); + + AddStep(@"Hit! :D", delegate + { + foreach (var s in accuracyCounters) + s.Current.Value -= 0.023f; + }); + } + } +} diff --git a/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs index b286b380e0..d5d8ec570a 100644 --- a/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs @@ -16,6 +16,7 @@ namespace osu.Game.Screens.Play.HUD public DefaultAccuracyCounter() { Origin = Anchor.TopRight; + Anchor = Anchor.TopRight; } [Resolved(canBeNull: true)] @@ -34,6 +35,7 @@ namespace osu.Game.Screens.Play.HUD if (hud?.ScoreCounter.Drawable is DefaultScoreCounter score) { // for now align with the score counter. eventually this will be user customisable. + Anchor = Anchor.TopLeft; Position = Parent.ToLocalSpace(score.ScreenSpaceDrawQuad.TopLeft) + offset; } } diff --git a/osu.Game/Skinning/LegacyAccuracyCounter.cs b/osu.Game/Skinning/LegacyAccuracyCounter.cs index 0f3ac19ce6..815580e85f 100644 --- a/osu.Game/Skinning/LegacyAccuracyCounter.cs +++ b/osu.Game/Skinning/LegacyAccuracyCounter.cs @@ -17,7 +17,9 @@ namespace osu.Game.Skinning public LegacyAccuracyCounter(ISkin skin) { + Anchor = Anchor.TopRight; Origin = Anchor.TopRight; + Scale = new Vector2(0.75f); this.skin = skin; @@ -40,7 +42,7 @@ namespace osu.Game.Skinning if (hud?.ScoreCounter.Drawable is LegacyScoreCounter score) { // for now align with the score counter. eventually this will be user customisable. - Position = Parent.ToLocalSpace(score.ScreenSpaceDrawQuad.BottomRight); + Y = Parent.ToLocalSpace(score.ScreenSpaceDrawQuad.BottomRight).Y; } } } From ca74cf824c6fd01b21b78e862cae58bd6eca534b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Oct 2020 18:24:28 +0900 Subject: [PATCH 4/6] Add padding --- osu.Game/Skinning/LegacyAccuracyCounter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Skinning/LegacyAccuracyCounter.cs b/osu.Game/Skinning/LegacyAccuracyCounter.cs index 815580e85f..9354b2b3bc 100644 --- a/osu.Game/Skinning/LegacyAccuracyCounter.cs +++ b/osu.Game/Skinning/LegacyAccuracyCounter.cs @@ -21,6 +21,7 @@ namespace osu.Game.Skinning Origin = Anchor.TopRight; Scale = new Vector2(0.75f); + Margin = new MarginPadding(10); this.skin = skin; } From 6983978c989c5063d8d7fb77cbdc5bed95ede85b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Oct 2020 18:30:44 +0900 Subject: [PATCH 5/6] Correct top-right element offset by finding the lower top anchor element --- osu.Game/Screens/Play/HUDOverlay.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index bb35bd3d69..7553f332cd 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -16,6 +16,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play.HUD; +using osu.Game.Skinning; using osuTK; using osuTK.Input; @@ -65,6 +66,8 @@ namespace osu.Game.Screens.Play private readonly FillFlowContainer bottomRightElements; private readonly FillFlowContainer topRightElements; + private Container mainUIElements; + private IEnumerable hideTargets => new Drawable[] { visibilityContainer, KeyCounter }; public HUDOverlay(ScoreProcessor scoreProcessor, HealthProcessor healthProcessor, DrawableRuleset drawableRuleset, IReadOnlyList mods) @@ -89,7 +92,7 @@ namespace osu.Game.Screens.Play { new Drawable[] { - new Container + mainUIElements = new Container { RelativeSizeAxes = Axes.Both, Children = new Drawable[] @@ -205,7 +208,17 @@ namespace osu.Game.Screens.Play { base.Update(); - topRightElements.Y = ToLocalSpace(ScoreCounter.Drawable.ScreenSpaceDrawQuad.BottomRight).Y; + float topRightOffset = 0; + + // fetch the bottom-most position of any main ui element that is anchored to the top of the screen. + // consider this kind of temporary. + foreach (var d in mainUIElements) + { + if (d is SkinnableDrawable sd && (sd.Drawable.Anchor & Anchor.y0) > 0) + topRightOffset = Math.Max(sd.Drawable.ScreenSpaceDrawQuad.BottomRight.Y, topRightOffset); + } + + topRightElements.Y = ToLocalSpace(new Vector2(0, topRightOffset)).Y; bottomRightElements.Y = -Progress.Height; } From d76365ed1b26252b3c54aef204bbd3312526ad4b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Oct 2020 18:38:41 +0900 Subject: [PATCH 6/6] Make container readonly --- osu.Game/Screens/Play/HUDOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 7553f332cd..fa914c0ebc 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -66,7 +66,7 @@ namespace osu.Game.Screens.Play private readonly FillFlowContainer bottomRightElements; private readonly FillFlowContainer topRightElements; - private Container mainUIElements; + private readonly Container mainUIElements; private IEnumerable hideTargets => new Drawable[] { visibilityContainer, KeyCounter };