diff --git a/osu.Game/Screens/Play/HUD/ArgonCounterTextComponent.cs b/osu.Game/Screens/Play/HUD/ArgonCounterTextComponent.cs index bd8f17185b..3789fb1645 100644 --- a/osu.Game/Screens/Play/HUD/ArgonCounterTextComponent.cs +++ b/osu.Game/Screens/Play/HUD/ArgonCounterTextComponent.cs @@ -15,6 +15,7 @@ using osu.Framework.Text; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD { @@ -26,6 +27,8 @@ namespace osu.Game.Screens.Play.HUD public IBindable WireframeOpacity { get; } = new BindableFloat(); public Bindable ShowLabel { get; } = new BindableBool(); + public Bindable LabelColour { get; } = new Bindable(Color4.White); + public Bindable TextColour { get; } = new Bindable(Color4.White); public Container NumberContainer { get; private set; } @@ -58,7 +61,6 @@ namespace osu.Game.Screens.Play.HUD labelText = new OsuSpriteText { Alpha = 0, - BypassAutoSizeAxes = Axes.X, Text = label.GetValueOrDefault(), Font = OsuFont.Torus.With(size: 12, weight: FontWeight.Bold), Margin = new MarginPadding { Left = 2.5f }, @@ -110,7 +112,7 @@ namespace osu.Game.Screens.Play.HUD [BackgroundDependencyLoader] private void load(OsuColour colours) { - labelText.Colour = colours.Blue0; + LabelColour.Value = colours.Blue0; } protected override void LoadComplete() @@ -122,6 +124,12 @@ namespace osu.Game.Screens.Play.HUD labelText.Alpha = s.NewValue ? 1 : 0; NumberContainer.Y = s.NewValue ? 12 : 0; }, true); + LabelColour.BindValueChanged(c => labelText.Colour = c.NewValue, true); + TextColour.BindValueChanged(c => + { + textPart.Colour = c.NewValue; + wireframesPart.Colour = c.NewValue; + }, true); } private partial class ArgonCounterSpriteText : OsuSpriteText diff --git a/osu.Game/Skinning/Components/ArgonJudgmentCounter.cs b/osu.Game/Skinning/Components/ArgonJudgmentCounter.cs new file mode 100644 index 0000000000..2ab395eb6c --- /dev/null +++ b/osu.Game/Skinning/Components/ArgonJudgmentCounter.cs @@ -0,0 +1,68 @@ +// 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 System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Play.HUD.JudgementCounter; +using osuTK.Graphics; + +namespace osu.Game.Skinning.Components +{ + public sealed class ArgonJudgmentCounter : VisibilityContainer + { + public ArgonCounterTextComponent TextComponent; + private OsuColour colours = null!; + public readonly JudgementCount JudgementCounter; + public BindableInt DisplayedValue = new BindableInt(); + + public ArgonJudgmentCounter(JudgementCount judgementCounter) + { + this.JudgementCounter = judgementCounter; + + AutoSizeAxes = Axes.Both; + AddInternal(TextComponent = new ArgonCounterTextComponent(Anchor.TopRight, judgementCounter.DisplayName.ToUpper())); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + this.colours = colours; + } + + private void updateWireframe() + { + int wireframeLenght = Math.Max(2, TextComponent.Text.ToString().Length); + TextComponent.WireframeTemplate = new string('#', wireframeLenght); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + DisplayedValue.BindValueChanged(v => + { + TextComponent.Text = v.NewValue.ToString(); + updateWireframe(); + }, true); + + var result = JudgementCounter.Types.First(); + TextComponent.LabelColour.Value = getJudgementColor(result); + TextComponent.ShowLabel.BindValueChanged(v => TextComponent.TextColour.Value = !v.NewValue ? getJudgementColor(result) : Color4.White); + } + + private Color4 getJudgementColor(HitResult result) + { + return result.IsBasic() ? colours.ForHitResult(result) : !result.IsBonus() ? colours.PurpleLight : colours.PurpleLighter; + } + + protected override void PopIn() => this.FadeIn(JudgementCounterDisplay.TRANSFORM_DURATION, Easing.OutQuint); + protected override void PopOut() => this.FadeOut(100); + } +} diff --git a/osu.Game/Skinning/Components/ArgonJudgmentCounterDisplay.cs b/osu.Game/Skinning/Components/ArgonJudgmentCounterDisplay.cs new file mode 100644 index 0000000000..dc705b0981 --- /dev/null +++ b/osu.Game/Skinning/Components/ArgonJudgmentCounterDisplay.cs @@ -0,0 +1,146 @@ +// 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 System.Linq; +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Localisation.HUD; +using osu.Game.Localisation.SkinComponents; +using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Play.HUD.JudgementCounter; +using osuTK; + +namespace osu.Game.Skinning.Components +{ + [UsedImplicitly] + public partial class ArgonJudgmentCounterDisplay : CompositeDrawable, ISerialisableDrawable + { + [Resolved] + private JudgementCountController judgementCountController { get; set; } = null!; + + [SettingSource("Wireframe opacity", "Controls the opacity of the wireframes behind the digits.")] + public BindableFloat WireframeOpacity { get; } = new BindableFloat(0.25f) + { + Precision = 0.01f, + MinValue = 0, + MaxValue = 1, + }; + + [SettingSource(typeof(SkinnableComponentStrings), nameof(SkinnableComponentStrings.ShowLabel), nameof(SkinnableComponentStrings.ShowLabelDescription))] + public Bindable ShowLabel { get; } = new BindableBool(true); + + [SettingSource(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.ShowMaxJudgement))] + public BindableBool ShowMaxJudgement { get; } = new BindableBool(true); + + [SettingSource(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.JudgementDisplayMode))] + public Bindable Mode { get; } = new Bindable(); + + [SettingSource(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.FlowDirection))] + public Bindable FlowDirection { get; } = new Bindable(); + + private FillFlowContainer counterFlow = null!; + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + AutoSizeAxes = Axes.Both; + InternalChild = counterFlow = new FillFlowContainer + { + Direction = getFillDirection(FlowDirection.Value), + Spacing = new Vector2(16), + AutoSizeAxes = Axes.Both, + }; + + foreach (var counter in judgementCountController.Counters) + { + ArgonJudgmentCounter counterComponent = new ArgonJudgmentCounter(counter); + counterComponent.TextComponent.WireframeOpacity.BindTo(WireframeOpacity); + counterComponent.TextComponent.ShowLabel.BindTo(ShowLabel); + counterComponent.DisplayedValue.BindTo(counter.ResultCount); + counterFlow.Add(counterComponent); + } + } + + protected override void LoadComplete() + { + base.LoadComplete(); + Mode.BindValueChanged(_ => updateVisibility(), true); + ShowMaxJudgement.BindValueChanged(_ => updateVisibility(), true); + FlowDirection.BindValueChanged(d => counterFlow.Direction = getFillDirection(d.NewValue)); + } + + private void updateVisibility() + { + for (int i = 0; i < counterFlow.Children.Count; i++) + { + ArgonJudgmentCounter counter = counterFlow.Children[i]; + + if (shouldBeVisible(i, counter)) + counter.Show(); + else + counter.Hide(); + } + } + + private bool shouldBeVisible(int index, ArgonJudgmentCounter counter) + { + if (index == 0 && !ShowMaxJudgement.Value) + return false; + + var hitResult = counter.JudgementCounter.Types.First(); + if (hitResult.IsBasic()) + return true; + + switch (Mode.Value) + { + case DisplayMode.Simple: + return false; + + case DisplayMode.Normal: + return !hitResult.IsBonus(); + + case DisplayMode.All: + return true; + + default: + throw new ArgumentOutOfRangeException(); + } + } + + private FillDirection getFillDirection(Direction flow) + { + switch (flow) + { + case Direction.Horizontal: + return FillDirection.Horizontal; + + case Direction.Vertical: + return FillDirection.Vertical; + + default: + throw new ArgumentOutOfRangeException(nameof(flow), flow, @"Unsupported direction"); + } + } + + public enum DisplayMode + { + [LocalisableDescription(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.JudgementDisplayModeSimple))] + Simple, + + [LocalisableDescription(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.JudgementDisplayModeNormal))] + Normal, + + [LocalisableDescription(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.JudgementDisplayModeAll))] + All + } + + public bool UsesFixedAnchor { get; set; } + } +}