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 NUnit.Framework;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Online.Spectator;
using osu.Game.Rulesets.Judgements;
@ -139,6 +140,29 @@ namespace osu.Game.Tests.Gameplay
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
{
public override HitResult MaxResult { get; }

View File

@ -39,6 +39,18 @@ namespace osu.Game.Rulesets.Scoring
/// </summary>
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>
/// The current combo.
/// </summary>
@ -264,6 +276,10 @@ namespace osu.Game.Rulesets.Scoring
private void updateScore()
{
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);
}

View File

@ -1,9 +1,10 @@
// 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.
#nullable disable
using System.ComponentModel;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Scoring;
@ -11,10 +12,53 @@ namespace osu.Game.Screens.Play.HUD
{
public abstract partial class GameplayAccuracyCounter : PercentageCounter
{
[BackgroundDependencyLoader]
private void load(ScoreProcessor scoreProcessor)
[SettingSource("Accuracy display mode", "Which accuracy mode should be displayed.")]
public Bindable<AccuracyDisplayMode> AccuracyDisplay { get; } = new Bindable<AccuracyDisplayMode>();
[Resolved]
private ScoreProcessor scoreProcessor { get; set; } = null!;
protected override void LoadComplete()
{
Current.BindTo(scoreProcessor.Accuracy);
base.LoadComplete();
AccuracyDisplay.BindValueChanged(mod =>
{
Current.UnbindBindings();
switch (mod.NewValue)
{
case AccuracyDisplayMode.Standard:
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
}
}
}