From 3f92bef9dfe3f58e98127705b75906bd06658aed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 16:50:37 +0900 Subject: [PATCH 1/7] Add setting for judgement line thickness --- .../Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 542731cf93..068a7f96cc 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -4,12 +4,14 @@ using System; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Game.Configuration; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osuTK; @@ -19,7 +21,14 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters public class BarHitErrorMeter : HitErrorMeter { private const int judgement_line_width = 14; - private const int judgement_line_height = 4; + + [SettingSource("Judgement line thickness", "How thick the individual lines should be.")] + public BindableNumber JudgementLineThickness { get; } = new BindableNumber(4) + { + MinValue = 1, + MaxValue = 8, + Precision = 0.1f, + }; private SpriteIcon arrow; private SpriteIcon iconEarly; @@ -255,6 +264,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters judgementsContainer.Add(new JudgementLine { + JudgementLineThickness = { BindTarget = JudgementLineThickness }, Y = getRelativeJudgementPosition(judgement.TimeOffset), Colour = GetColourForHitResult(judgement.Type), }); @@ -268,11 +278,12 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters internal class JudgementLine : CompositeDrawable { + public readonly BindableNumber JudgementLineThickness = new BindableFloat(); + public JudgementLine() { RelativeSizeAxes = Axes.X; RelativePositionAxes = Axes.Y; - Height = judgement_line_height; Blending = BlendingParameters.Additive; @@ -295,6 +306,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Alpha = 0; Width = 0; + JudgementLineThickness.BindValueChanged(thickness => Height = thickness.NewValue, true); + this .FadeTo(0.6f, judgement_fade_in_duration, Easing.OutQuint) .ResizeWidthTo(1, judgement_fade_in_duration, Easing.OutQuint) From 331cb2aa800fe4f8330534da0bd59127abf56f6d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 16:54:09 +0900 Subject: [PATCH 2/7] Add setting to show or hide the moving average arrow --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 068a7f96cc..c12411be64 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -30,6 +30,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Precision = 0.1f, }; + [SettingSource("Show moving average arrow", "Whether an arrow should move beneath the bar showing the average error.")] + public Bindable ShowMovingAverage { get; } = new BindableBool(true); + private SpriteIcon arrow; private SpriteIcon iconEarly; private SpriteIcon iconLate; @@ -41,6 +44,12 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private double maxHitWindow; + private double floatingAverage; + private Container colourBars; + private Container arrowContainer; + + private const int max_concurrent_judgements = 50; + public BarHitErrorMeter() { AutoSizeAxes = Axes.Both; @@ -134,13 +143,16 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters }, } }, - new Container + arrowContainer = new Container { Name = "average chevron", Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, + Origin = Anchor.CentreRight, Width = chevron_size, + X = chevron_size, RelativeSizeAxes = Axes.Y, + Alpha = 0, + Scale = new Vector2(0, 1), Child = arrow = new SpriteIcon { Anchor = Anchor.TopCentre, @@ -164,8 +176,15 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters colourBars.Height = 0; colourBars.ResizeHeightTo(1, 800, Easing.OutQuint); - arrow.Alpha = 0; - arrow.Delay(200).FadeInFromZero(600); + // delay the arrow appearance animation for only the initial appearance. + using (arrowContainer.BeginDelayedSequence(250)) + { + ShowMovingAverage.BindValueChanged(visible => + { + arrowContainer.FadeTo(visible.NewValue ? 1 : 0, 250, Easing.OutQuint); + arrowContainer.ScaleTo(visible.NewValue ? new Vector2(1) : new Vector2(0, 1), 250, Easing.OutQuint); + }, true); + } } protected override void Update() @@ -233,11 +252,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } - private double floatingAverage; - private Container colourBars; - - private const int max_concurrent_judgements = 50; - protected override void OnNewJudgement(JudgementResult judgement) { const int arrow_move_duration = 800; From cdeab1b14e2b6130f63e3a363f0275363fc2f7a7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 17:16:40 +0900 Subject: [PATCH 3/7] Add setting to change the style of the centre marker --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 100 ++++++++++++++---- 1 file changed, 79 insertions(+), 21 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index c12411be64..60b12476d1 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -33,6 +33,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [SettingSource("Show moving average arrow", "Whether an arrow should move beneath the bar showing the average error.")] public Bindable ShowMovingAverage { get; } = new BindableBool(true); + [SettingSource("Centre marker style", "How to signify the centre of the display")] + public Bindable CentreMarkerStyle { get; } = new Bindable(CentreMarker.Circle); + private SpriteIcon arrow; private SpriteIcon iconEarly; private SpriteIcon iconLate; @@ -48,8 +51,14 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private Container colourBars; private Container arrowContainer; + private (HitResult result, double length)[] hitWindows; + private const int max_concurrent_judgements = 50; + private Drawable[] centreMarkerDrawables; + + private const int centre_marker_size = 8; + public BarHitErrorMeter() { AutoSizeAxes = Axes.Both; @@ -58,13 +67,12 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [BackgroundDependencyLoader] private void load() { - const int centre_marker_size = 8; const int bar_height = 200; const int bar_width = 2; const float chevron_size = 8; const float icon_size = 14; - var hitWindows = HitWindows.GetAllAvailableWindows().ToArray(); + hitWindows = HitWindows.GetAllAvailableWindows().ToArray(); InternalChild = new Container { @@ -116,14 +124,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters RelativeSizeAxes = Axes.Y, Height = 0.5f, }, - new Circle - { - Name = "middle marker behind", - Colour = GetColourForHitResult(hitWindows.Last().result), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(centre_marker_size), - }, judgementsContainer = new Container { Name = "judgements", @@ -132,15 +132,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters RelativeSizeAxes = Axes.Y, Width = judgement_line_width, }, - new Circle - { - Name = "middle marker in front", - Colour = GetColourForHitResult(hitWindows.Last().result).Darken(0.3f), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(centre_marker_size), - Scale = new Vector2(0.5f), - }, } }, arrowContainer = new Container @@ -176,8 +167,10 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters colourBars.Height = 0; colourBars.ResizeHeightTo(1, 800, Easing.OutQuint); - // delay the arrow appearance animation for only the initial appearance. - using (arrowContainer.BeginDelayedSequence(250)) + CentreMarkerStyle.BindValueChanged(style => recreateCentreMarker(style.NewValue), true); + + // delay the appearance animations for only the initial appearance. + using (arrowContainer.BeginDelayedSequence(450)) { ShowMovingAverage.BindValueChanged(visible => { @@ -187,6 +180,65 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } + private void recreateCentreMarker(CentreMarker style) + { + if (centreMarkerDrawables != null) + { + foreach (var d in centreMarkerDrawables) + { + d.ScaleTo(0, 500, Easing.OutQuint) + .FadeOut(500, Easing.OutQuint); + + d.Expire(); + } + + centreMarkerDrawables = null; + } + + switch (style) + { + case CentreMarker.None: + break; + + case CentreMarker.Circle: + centreMarkerDrawables = new Drawable[] + { + new Circle + { + Name = "middle marker behind", + Colour = GetColourForHitResult(hitWindows.Last().result), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Depth = float.MaxValue, + Size = new Vector2(centre_marker_size), + }, + new Circle + { + Name = "middle marker in front", + Colour = GetColourForHitResult(hitWindows.Last().result).Darken(0.3f), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Depth = float.MinValue, + Size = new Vector2(centre_marker_size), + Scale = new Vector2(0.5f), + }, + }; + break; + } + + if (centreMarkerDrawables != null) + { + foreach (var d in centreMarkerDrawables) + { + colourBars.Add(d); + + Vector2 originalScale = d.Scale; + d.FadeInFromZero(500, Easing.OutQuint) + .ScaleTo(0).ScaleTo(originalScale, 1000, Easing.OutElasticHalf); + } + } + } + protected override void Update() { base.Update(); @@ -333,5 +385,11 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } public override void Clear() => judgementsContainer.Clear(); + + public enum CentreMarker + { + None, + Circle + } } } From 919583137e9bb2afd8514fbbbdcbe0cef043585d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 17:23:27 +0900 Subject: [PATCH 4/7] Add line style for centre marker --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 48 +++++++++++++++---- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 60b12476d1..3e583317e1 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters public Bindable ShowMovingAverage { get; } = new BindableBool(true); [SettingSource("Centre marker style", "How to signify the centre of the display")] - public Bindable CentreMarkerStyle { get; } = new Bindable(CentreMarker.Circle); + public Bindable CentreMarkerStyle { get; } = new Bindable(CentreMarkerStyles.Circle); private SpriteIcon arrow; private SpriteIcon iconEarly; @@ -180,7 +180,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } - private void recreateCentreMarker(CentreMarker style) + private void recreateCentreMarker(CentreMarkerStyles style) { if (centreMarkerDrawables != null) { @@ -197,10 +197,10 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters switch (style) { - case CentreMarker.None: + case CentreMarkerStyles.None: break; - case CentreMarker.Circle: + case CentreMarkerStyles.Circle: centreMarkerDrawables = new Drawable[] { new Circle @@ -219,11 +219,39 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Anchor = Anchor.Centre, Origin = Anchor.Centre, Depth = float.MinValue, - Size = new Vector2(centre_marker_size), - Scale = new Vector2(0.5f), + Size = new Vector2(centre_marker_size / 2f), }, }; break; + + case CentreMarkerStyles.Line: + const float border_size = 1.5f; + + centreMarkerDrawables = new Drawable[] + { + new Box + { + Name = "middle marker behind", + Colour = GetColourForHitResult(hitWindows.Last().result), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Depth = float.MaxValue, + Size = new Vector2(judgement_line_width, centre_marker_size / 3f), + }, + new Box + { + Name = "middle marker in front", + Colour = GetColourForHitResult(hitWindows.Last().result).Darken(0.3f), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Depth = float.MinValue, + Size = new Vector2(judgement_line_width - border_size, centre_marker_size / 3f - border_size), + }, + }; + break; + + default: + throw new ArgumentOutOfRangeException(nameof(style), style, null); } if (centreMarkerDrawables != null) @@ -232,9 +260,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { colourBars.Add(d); - Vector2 originalScale = d.Scale; d.FadeInFromZero(500, Easing.OutQuint) - .ScaleTo(0).ScaleTo(originalScale, 1000, Easing.OutElasticHalf); + .ScaleTo(0).ScaleTo(1, 1000, Easing.OutElasticHalf); } } } @@ -386,10 +413,11 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters public override void Clear() => judgementsContainer.Clear(); - public enum CentreMarker + public enum CentreMarkerStyles { None, - Circle + Circle, + Line } } } From 7c9fe4036cbde6f330c96e5da9dc55af0424d9e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 17:46:22 +0900 Subject: [PATCH 5/7] Add setting to change the style of the early/late markers --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 112 ++++++++++++++---- 1 file changed, 91 insertions(+), 21 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 3e583317e1..02c2a36918 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -12,6 +12,8 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osuTK; @@ -36,9 +38,12 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [SettingSource("Centre marker style", "How to signify the centre of the display")] public Bindable CentreMarkerStyle { get; } = new Bindable(CentreMarkerStyles.Circle); + [SettingSource("Label style", "How to show early/late extremities")] + public Bindable LabelStyle { get; } = new Bindable(LabelStyles.Icons); + private SpriteIcon arrow; - private SpriteIcon iconEarly; - private SpriteIcon iconLate; + private Drawable labelEarly; + private Drawable labelLate; private Container colourBarsEarly; private Container colourBarsLate; @@ -70,7 +75,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters const int bar_height = 200; const int bar_width = 2; const float chevron_size = 8; - const float icon_size = 14; hitWindows = HitWindows.GetAllAvailableWindows().ToArray(); @@ -91,22 +95,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters RelativeSizeAxes = Axes.Y, Children = new Drawable[] { - iconEarly = new SpriteIcon - { - Y = -10, - Size = new Vector2(icon_size), - Icon = FontAwesome.Solid.ShippingFast, - Anchor = Anchor.TopCentre, - Origin = Anchor.Centre, - }, - iconLate = new SpriteIcon - { - Y = 10, - Size = new Vector2(icon_size), - Icon = FontAwesome.Solid.Bicycle, - Anchor = Anchor.BottomCentre, - Origin = Anchor.Centre, - }, colourBarsEarly = new Container { Anchor = Anchor.Centre, @@ -168,6 +156,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters colourBars.ResizeHeightTo(1, 800, Easing.OutQuint); CentreMarkerStyle.BindValueChanged(style => recreateCentreMarker(style.NewValue), true); + LabelStyle.BindValueChanged(style => recreateLabels(style.NewValue), true); // delay the appearance animations for only the initial appearance. using (arrowContainer.BeginDelayedSequence(450)) @@ -266,13 +255,87 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } + private void recreateLabels(LabelStyles style) + { + const float icon_size = 14; + + labelEarly?.Expire(); + labelEarly = null; + + labelLate?.Expire(); + labelLate = null; + + switch (style) + { + case LabelStyles.None: + break; + + case LabelStyles.Icons: + labelEarly = new SpriteIcon + { + Y = -10, + Size = new Vector2(icon_size), + Icon = FontAwesome.Solid.ShippingFast, + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + }; + + labelLate = new SpriteIcon + { + Y = 10, + Size = new Vector2(icon_size), + Icon = FontAwesome.Solid.Bicycle, + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + }; + + break; + + case LabelStyles.Text: + labelEarly = new OsuSpriteText + { + Y = -10, + Text = "Early", + Font = OsuFont.Default.With(size: 10), + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + }; + + labelLate = new OsuSpriteText + { + Y = 10, + Text = "Late", + Font = OsuFont.Default.With(size: 10), + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + }; + + break; + + default: + throw new ArgumentOutOfRangeException(nameof(style), style, null); + } + + if (labelEarly != null) + { + colourBars.Add(labelEarly); + labelEarly.FadeInFromZero(500); + } + + if (labelLate != null) + { + colourBars.Add(labelLate); + labelLate.FadeInFromZero(500); + } + } + protected override void Update() { base.Update(); // undo any layout rotation to display icons in the correct orientation - iconEarly.Rotation = -Rotation; - iconLate.Rotation = -Rotation; + if (labelEarly != null) labelEarly.Rotation = -Rotation; + if (labelLate != null) labelLate.Rotation = -Rotation; } private void createColourBars((HitResult result, double length)[] windows) @@ -419,5 +482,12 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Circle, Line } + + public enum LabelStyles + { + None, + Icons, + Text + } } } From bd488d139d1f8431ed5c1541c159f0090590962d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 20:11:05 +0900 Subject: [PATCH 6/7] Better centre text labels for hit error meter --- osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 02c2a36918..e3a8b6cae6 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -294,6 +294,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters case LabelStyles.Text: labelEarly = new OsuSpriteText { + X = -1, Y = -10, Text = "Early", Font = OsuFont.Default.With(size: 10), @@ -303,6 +304,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters labelLate = new OsuSpriteText { + X = -1, Y = 10, Text = "Late", Font = OsuFont.Default.With(size: 10), From ed90dc6d6bba910f908ad23dca8fd5cfa227b3f6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 20:17:04 +0900 Subject: [PATCH 7/7] Fix centering of labels using `Height` instead of location to better handle rotations --- osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index e3a8b6cae6..dca50c07ad 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -294,20 +294,20 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters case LabelStyles.Text: labelEarly = new OsuSpriteText { - X = -1, Y = -10, Text = "Early", Font = OsuFont.Default.With(size: 10), + Height = 12, Anchor = Anchor.TopCentre, Origin = Anchor.Centre, }; labelLate = new OsuSpriteText { - X = -1, Y = 10, Text = "Late", Font = OsuFont.Default.With(size: 10), + Height = 12, Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, };