From 9aa3021bbc5f1f2ba2383cb96aef012d19ba5713 Mon Sep 17 00:00:00 2001 From: Chinmay Patil Date: Wed, 3 Nov 2021 22:22:44 -0600 Subject: [PATCH] Added Unstable Rate Counter as a skinable element --- .../Screens/Play/HUD/UnstableRateCounter.cs | 124 ++++++++++++++++++ osu.Game/Skinning/DefaultSkin.cs | 14 +- 2 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Screens/Play/HUD/UnstableRateCounter.cs diff --git a/osu.Game/Screens/Play/HUD/UnstableRateCounter.cs b/osu.Game/Screens/Play/HUD/UnstableRateCounter.cs new file mode 100644 index 0000000000..7109ea1995 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/UnstableRateCounter.cs @@ -0,0 +1,124 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Threading; +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Localisation; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Ranking.Statistics; +using osu.Game.Skinning; + +namespace osu.Game.Screens.Play.HUD +{ + public class UnstableRateCounter : RollingCounter, ISkinnableDrawable + { + public bool UsesFixedAnchor { get; set; } + + protected override bool IsRollingProportional => true; + + protected override double RollingDuration => 750; + + private const float alpha_when_invalid = 0.3f; + + [CanBeNull] + [Resolved(CanBeNull = true)] + private ScoreProcessor scoreProcessor { get; set; } + + [Resolved(CanBeNull = true)] + [CanBeNull] + private GameplayState gameplayState { get; set; } + + private readonly CancellationTokenSource loadCancellationSource = new CancellationTokenSource(); + + public UnstableRateCounter() + { + Current.Value = DisplayedCount = 0.0; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours, BeatmapDifficultyCache difficultyCache) + { + Colour = colours.BlueLighter; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + if (scoreProcessor != null) + { + scoreProcessor.NewJudgement += onJudgementChanged; + scoreProcessor.JudgementReverted += onJudgementChanged; + } + } + + private bool isValid; + + protected bool IsValid + { + set + { + if (value == isValid) + return; + + isValid = value; + DrawableCount.FadeTo(isValid ? 1 : alpha_when_invalid, 1000, Easing.OutQuint); + } + } + + private void onJudgementChanged(JudgementResult judgement) + { + + if (gameplayState == null) + { + isValid = false; + return; + } + + double ur = new UnstableRate(gameplayState.Score.ScoreInfo.HitEvents).Value; + if (double.IsNaN(ur)) // Error handling: If the user misses the first few notes, the UR is NaN. + { + isValid = false; + return; + } + Current.Value = ur; + IsValid = true; + } + + protected override LocalisableString FormatCount(double count) + { + return count.ToLocalisableString("0.00 UR"); + } + + + protected override OsuSpriteText CreateSpriteText() + => base.CreateSpriteText().With(s => { + s.Font = s.Font.With(size: 12f, fixedWidth: true); + s.Alpha = alpha_when_invalid; + }); + + + + + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (scoreProcessor != null) + scoreProcessor.NewJudgement -= onJudgementChanged; + + loadCancellationSource?.Cancel(); + } + + + } +} diff --git a/osu.Game/Skinning/DefaultSkin.cs b/osu.Game/Skinning/DefaultSkin.cs index c377f16f8b..e887ccb2e3 100644 --- a/osu.Game/Skinning/DefaultSkin.cs +++ b/osu.Game/Skinning/DefaultSkin.cs @@ -68,6 +68,7 @@ namespace osu.Game.Skinning var accuracy = container.OfType().FirstOrDefault(); var combo = container.OfType().FirstOrDefault(); var ppCounter = container.OfType().FirstOrDefault(); + var unstableRate = container.OfType().FirstOrDefault(); if (score != null) { @@ -84,9 +85,17 @@ namespace osu.Game.Skinning if (ppCounter != null) { ppCounter.Y = score.Position.Y + ppCounter.ScreenSpaceDeltaToParentSpace(score.ScreenSpaceDrawQuad.Size).Y - 4; - ppCounter.Origin = Anchor.TopCentre; + ppCounter.X = ppCounter.ScreenSpaceDeltaToParentSpace(score.ScreenSpaceDrawQuad.Size).X / 2 - horizontal_padding; + ppCounter.Origin = Anchor.TopRight; ppCounter.Anchor = Anchor.TopCentre; } + if (unstableRate != null) + { + unstableRate.Y = ppCounter.Position.Y; + unstableRate.X = -unstableRate.ScreenSpaceDeltaToParentSpace(score.ScreenSpaceDrawQuad.Size).X / 2 + horizontal_padding; + unstableRate.Origin = Anchor.TopLeft; + unstableRate.Anchor = Anchor.TopCentre; + } if (accuracy != null) { @@ -130,7 +139,8 @@ namespace osu.Game.Skinning new SongProgress(), new BarHitErrorMeter(), new BarHitErrorMeter(), - new PerformancePointsCounter() + new PerformancePointsCounter(), + new UnstableRateCounter() } };