From 78a3b5961e8590e85a9303fb362d3ab8d1993c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 20 Feb 2022 15:48:33 +0100 Subject: [PATCH 1/4] Implement basic difficulty multiplier display --- .../TestSceneDifficultyMultiplierDisplay.cs | 40 +++++ .../Mods/DifficultyMultiplierDisplay.cs | 166 ++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneDifficultyMultiplierDisplay.cs create mode 100644 osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDifficultyMultiplierDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDifficultyMultiplierDisplay.cs new file mode 100644 index 0000000000..cd84f8b380 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDifficultyMultiplierDisplay.cs @@ -0,0 +1,40 @@ +// 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.Game.Overlays; +using osu.Game.Overlays.Mods; + +namespace osu.Game.Tests.Visual.UserInterface +{ + [TestFixture] + public class TestSceneDifficultyMultiplierDisplay : OsuTestScene + { + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); + + [Test] + public void TestDifficultyMultiplierDisplay() + { + DifficultyMultiplierDisplay multiplierDisplay = null; + + AddStep("create content", () => Child = multiplierDisplay = new DifficultyMultiplierDisplay + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }); + + AddStep("set multiplier below 1", () => multiplierDisplay.Current.Value = 0.5); + AddStep("set multiplier to 1", () => multiplierDisplay.Current.Value = 1); + AddStep("set multiplier above 1", () => multiplierDisplay.Current.Value = 1.5); + + AddSliderStep("set multiplier", 0, 2, 1d, multiplier => + { + if (multiplierDisplay != null) + multiplierDisplay.Current.Value = multiplier; + }); + } + } +} diff --git a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs new file mode 100644 index 0000000000..1d4aa9e0f5 --- /dev/null +++ b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs @@ -0,0 +1,166 @@ +// 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.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Mods; +using osuTK; + +namespace osu.Game.Overlays.Mods +{ + public class DifficultyMultiplierDisplay : CompositeDrawable, IHasCurrentValue + { + public Bindable Current + { + get => current.Current; + set => current.Current = value; + } + + private readonly BindableNumberWithCurrent current = new BindableNumberWithCurrent(1); + + private readonly Box underlayBackground; + private readonly Box contentBackground; + private readonly FillFlowContainer multiplierFlow; + private readonly OsuSpriteText multiplierText; + + [Resolved] + private OsuColour colours { get; set; } + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + + private const float height = 42; + private const float transition_duration = 200; + + public DifficultyMultiplierDisplay() + { + Height = height; + AutoSizeAxes = Axes.X; + + InternalChild = new Container + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Masking = true, + CornerRadius = ModPanel.CORNER_RADIUS, + Shear = new Vector2(ModPanel.SHEAR_X, 0), + Children = new Drawable[] + { + underlayBackground = new Box + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Y, + Width = height + ModPanel.CORNER_RADIUS + }, + new GridContainer + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Absolute, height) + }, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Masking = true, + CornerRadius = ModPanel.CORNER_RADIUS, + Children = new Drawable[] + { + contentBackground = new Box + { + RelativeSizeAxes = Axes.Both + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding { Horizontal = 18 }, + Shear = new Vector2(-ModPanel.SHEAR_X, 0), + Text = "Difficulty Multiplier", + Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold) + } + } + }, + multiplierFlow = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Shear = new Vector2(-ModPanel.SHEAR_X, 0), + Direction = FillDirection.Horizontal, + Spacing = new Vector2(2, 0), + Children = new Drawable[] + { + multiplierText = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold) + }, + new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Icon = FontAwesome.Solid.Times, + Size = new Vector2(7), + Margin = new MarginPadding { Top = 1 } + } + } + } + } + } + } + } + }; + } + + [BackgroundDependencyLoader] + private void load() + { + contentBackground.Colour = colourProvider.Background4; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + current.BindValueChanged(_ => updateState(), true); + FinishTransforms(true); + } + + private void updateState() + { + multiplierText.Text = current.Value.ToLocalisableString(@"N1"); + + if (Current.IsDefault) + { + underlayBackground.FadeColour(colourProvider.Background3, transition_duration, Easing.OutQuint); + multiplierFlow.FadeColour(Colour4.White, transition_duration, Easing.OutQuint); + } + else + { + var backgroundColour = Current.Value < 1 + ? colours.ForModType(ModType.DifficultyReduction) + : colours.ForModType(ModType.DifficultyIncrease); + + underlayBackground.FadeColour(backgroundColour, transition_duration, Easing.OutQuint); + multiplierFlow.FadeColour(colourProvider.Background5, transition_duration, Easing.OutQuint); + } + } + } +} From c25d7a1c75f0b964ff0434f58f621a2a22645d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 20 Feb 2022 16:02:46 +0100 Subject: [PATCH 2/4] Use rolling counter for multiplier display --- .../Mods/DifficultyMultiplierDisplay.cs | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs index 1d4aa9e0f5..3fbba0b8ed 100644 --- a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs +++ b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs @@ -9,8 +9,10 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Mods; using osuTK; @@ -24,12 +26,15 @@ namespace osu.Game.Overlays.Mods set => current.Current = value; } - private readonly BindableNumberWithCurrent current = new BindableNumberWithCurrent(1); + private readonly BindableNumberWithCurrent current = new BindableNumberWithCurrent(1) + { + Precision = 0.1 + }; private readonly Box underlayBackground; private readonly Box contentBackground; private readonly FillFlowContainer multiplierFlow; - private readonly OsuSpriteText multiplierText; + private readonly MultiplierCounter multiplierCounter; [Resolved] private OsuColour colours { get; set; } @@ -107,11 +112,11 @@ namespace osu.Game.Overlays.Mods Spacing = new Vector2(2, 0), Children = new Drawable[] { - multiplierText = new OsuSpriteText + multiplierCounter = new MultiplierCounter { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold) + Current = { BindTarget = Current } }, new SpriteIcon { @@ -141,12 +146,11 @@ namespace osu.Game.Overlays.Mods base.LoadComplete(); current.BindValueChanged(_ => updateState(), true); FinishTransforms(true); + multiplierCounter.StopRolling(); } private void updateState() { - multiplierText.Text = current.Value.ToLocalisableString(@"N1"); - if (Current.IsDefault) { underlayBackground.FadeColour(colourProvider.Background3, transition_duration, Easing.OutQuint); @@ -162,5 +166,17 @@ namespace osu.Game.Overlays.Mods multiplierFlow.FadeColour(colourProvider.Background5, transition_duration, Easing.OutQuint); } } + + private class MultiplierCounter : RollingCounter + { + protected override double RollingDuration => 500; + + protected override LocalisableString FormatCount(double count) => count.ToLocalisableString(@"N1"); + + protected override OsuSpriteText CreateSpriteText() => new OsuSpriteText + { + Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold) + }; + } } } From 019f4d965de8165675aae9027105b2e54730f7b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 7 Mar 2022 22:55:55 +0100 Subject: [PATCH 3/4] Show two decimal digits on mod multiplier rather than one --- osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs index 3fbba0b8ed..e10edb1ebc 100644 --- a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs +++ b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Mods private readonly BindableNumberWithCurrent current = new BindableNumberWithCurrent(1) { - Precision = 0.1 + Precision = 0.01 }; private readonly Box underlayBackground; @@ -43,6 +43,7 @@ namespace osu.Game.Overlays.Mods private OverlayColourProvider colourProvider { get; set; } private const float height = 42; + private const float multiplier_value_area_width = 56; private const float transition_duration = 200; public DifficultyMultiplierDisplay() @@ -64,7 +65,7 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, RelativeSizeAxes = Axes.Y, - Width = height + ModPanel.CORNER_RADIUS + Width = multiplier_value_area_width + ModPanel.CORNER_RADIUS }, new GridContainer { @@ -73,7 +74,7 @@ namespace osu.Game.Overlays.Mods ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.Absolute, height) + new Dimension(GridSizeMode.Absolute, multiplier_value_area_width) }, Content = new[] { @@ -171,7 +172,7 @@ namespace osu.Game.Overlays.Mods { protected override double RollingDuration => 500; - protected override LocalisableString FormatCount(double count) => count.ToLocalisableString(@"N1"); + protected override LocalisableString FormatCount(double count) => count.ToLocalisableString(@"N2"); protected override OsuSpriteText CreateSpriteText() => new OsuSpriteText { From 643f68e8447d7cf946508c7632fab0e239303eb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 7 Mar 2022 23:11:20 +0100 Subject: [PATCH 4/4] Better annotate initial rolling counter value set --- osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs index e10edb1ebc..4fc3a904fa 100644 --- a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs +++ b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs @@ -147,7 +147,9 @@ namespace osu.Game.Overlays.Mods base.LoadComplete(); current.BindValueChanged(_ => updateState(), true); FinishTransforms(true); - multiplierCounter.StopRolling(); + // required to prevent the counter initially rolling up from 0 to 1 + // due to `Current.Value` having a nonstandard default value of 1. + multiplierCounter.SetCountWithoutRolling(Current.Value); } private void updateState()