1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-27 00:23:01 +08:00

Merge pull request #21945 from cdwcgt/acc-UI

Add new display modes for accuracy counter
This commit is contained in:
Dean Herbert 2023-01-01 23:20:12 +08:00 committed by GitHub
commit 7e39ee3982
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 89 additions and 5 deletions

View File

@ -8,6 +8,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Online.Spectator; using osu.Game.Online.Spectator;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
@ -139,6 +140,29 @@ namespace osu.Game.Tests.Gameplay
Assert.That(score.MaximumStatistics[HitResult.LargeBonus], Is.EqualTo(1)); Assert.That(score.MaximumStatistics[HitResult.LargeBonus], Is.EqualTo(1));
} }
[Test]
public void TestAccuracyModes()
{
var beatmap = new Beatmap<HitObject>
{
HitObjects = Enumerable.Range(0, 4).Select(_ => new TestHitObject(HitResult.Great)).ToList<HitObject>()
};
var scoreProcessor = new ScoreProcessor(new OsuRuleset());
scoreProcessor.ApplyBeatmap(beatmap);
Assert.That(scoreProcessor.Accuracy.Value, Is.EqualTo(1));
Assert.That(scoreProcessor.MinimumAccuracy.Value, Is.EqualTo(0));
Assert.That(scoreProcessor.MaximumAccuracy.Value, Is.EqualTo(1));
scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], beatmap.HitObjects[0].CreateJudgement()) { Type = HitResult.Ok });
scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[1], beatmap.HitObjects[1].CreateJudgement()) { Type = HitResult.Great });
Assert.That(scoreProcessor.Accuracy.Value, Is.EqualTo((double)(100 + 300) / (2 * 300)).Within(Precision.DOUBLE_EPSILON));
Assert.That(scoreProcessor.MinimumAccuracy.Value, Is.EqualTo((double)(100 + 300) / (4 * 300)).Within(Precision.DOUBLE_EPSILON));
Assert.That(scoreProcessor.MaximumAccuracy.Value, Is.EqualTo((double)(100 + 3 * 300) / (4 * 300)).Within(Precision.DOUBLE_EPSILON));
}
private class TestJudgement : Judgement private class TestJudgement : Judgement
{ {
public override HitResult MaxResult { get; } public override HitResult MaxResult { get; }

View File

@ -39,6 +39,18 @@ namespace osu.Game.Rulesets.Scoring
/// </summary> /// </summary>
public readonly BindableDouble Accuracy = new BindableDouble(1) { MinValue = 0, MaxValue = 1 }; public readonly BindableDouble Accuracy = new BindableDouble(1) { MinValue = 0, MaxValue = 1 };
/// <summary>
/// The minimum achievable accuracy for the whole beatmap at this stage of gameplay.
/// Assumes that all objects that have not been judged yet will receive the minimum hit result.
/// </summary>
public readonly BindableDouble MinimumAccuracy = new BindableDouble { MinValue = 0, MaxValue = 1 };
/// <summary>
/// The maximum achievable accuracy for the whole beatmap at this stage of gameplay.
/// Assumes that all objects that have not been judged yet will receive the maximum hit result.
/// </summary>
public readonly BindableDouble MaximumAccuracy = new BindableDouble(1) { MinValue = 0, MaxValue = 1 };
/// <summary> /// <summary>
/// The current combo. /// The current combo.
/// </summary> /// </summary>
@ -264,6 +276,10 @@ namespace osu.Game.Rulesets.Scoring
private void updateScore() private void updateScore()
{ {
Accuracy.Value = currentMaximumScoringValues.BaseScore > 0 ? (double)currentScoringValues.BaseScore / currentMaximumScoringValues.BaseScore : 1; Accuracy.Value = currentMaximumScoringValues.BaseScore > 0 ? (double)currentScoringValues.BaseScore / currentMaximumScoringValues.BaseScore : 1;
MinimumAccuracy.Value = maximumScoringValues.BaseScore > 0 ? (double)currentScoringValues.BaseScore / maximumScoringValues.BaseScore : 0;
MaximumAccuracy.Value = maximumScoringValues.BaseScore > 0
? (double)(currentScoringValues.BaseScore + (maximumScoringValues.BaseScore - currentMaximumScoringValues.BaseScore)) / maximumScoringValues.BaseScore
: 1;
TotalScore.Value = computeScore(Mode.Value, currentScoringValues, maximumScoringValues); TotalScore.Value = computeScore(Mode.Value, currentScoringValues, maximumScoringValues);
} }

View File

@ -1,9 +1,10 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable using System.ComponentModel;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -11,10 +12,53 @@ namespace osu.Game.Screens.Play.HUD
{ {
public abstract partial class GameplayAccuracyCounter : PercentageCounter public abstract partial class GameplayAccuracyCounter : PercentageCounter
{ {
[BackgroundDependencyLoader] [SettingSource("Accuracy display mode", "Which accuracy mode should be displayed.")]
private void load(ScoreProcessor scoreProcessor) public Bindable<AccuracyDisplayMode> AccuracyDisplay { get; } = new Bindable<AccuracyDisplayMode>();
[Resolved]
private ScoreProcessor scoreProcessor { get; set; } = null!;
protected override void LoadComplete()
{ {
base.LoadComplete();
AccuracyDisplay.BindValueChanged(mod =>
{
Current.UnbindBindings();
switch (mod.NewValue)
{
case AccuracyDisplayMode.Standard:
Current.BindTo(scoreProcessor.Accuracy); Current.BindTo(scoreProcessor.Accuracy);
break;
case AccuracyDisplayMode.MinimumAchievable:
Current.BindTo(scoreProcessor.MinimumAccuracy);
break;
case AccuracyDisplayMode.MaximumAchievable:
Current.BindTo(scoreProcessor.MaximumAccuracy);
break;
}
}, true);
// if the accuracy counter is using the "minimum achievable" mode,
// then its initial value is 0%, rather than the 100% that the base PercentageCounter assumes.
// to counteract this, manually finish transforms on DisplayedCount once after the initial callback above
// to stop it from rolling down from 100% to 0%.
FinishTransforms(targetMember: nameof(DisplayedCount));
}
public enum AccuracyDisplayMode
{
[Description("Standard")]
Standard,
[Description("Maximum achievable")]
MaximumAchievable,
[Description("Minimum achievable")]
MinimumAchievable
} }
} }
} }