1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-13 08:32:57 +08:00

Merge pull request #24823 from bdach/scoring-test-scene-catch

Add scoring test scene for catch
This commit is contained in:
Dean Herbert 2023-09-19 13:59:11 +09:00 committed by GitHub
commit aba98f2985
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 177 additions and 5 deletions

View File

@ -0,0 +1,157 @@
// 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.
using System;
using NUnit.Framework;
using osu.Framework.Bindables;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Beatmaps;
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Scoring;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
using osu.Game.Tests.Visual.Gameplay;
namespace osu.Game.Rulesets.Catch.Tests
{
[TestFixture]
public partial class TestSceneScoring : ScoringTestScene
{
public TestSceneScoring()
: base(supportsNonPerfectJudgements: false)
{
}
private Bindable<double> scoreMultiplier { get; } = new BindableDouble
{
Default = 4,
Value = 4
};
protected override IBeatmap CreateBeatmap(int maxCombo)
{
var beatmap = new CatchBeatmap();
for (int i = 0; i < maxCombo; ++i)
beatmap.HitObjects.Add(new Fruit());
return beatmap;
}
protected override IScoringAlgorithm CreateScoreV1() => new ScoreV1 { ScoreMultiplier = { BindTarget = scoreMultiplier } };
protected override IScoringAlgorithm CreateScoreV2(int maxCombo) => new ScoreV2(maxCombo);
protected override ProcessorBasedScoringAlgorithm CreateScoreAlgorithm(IBeatmap beatmap, ScoringMode mode) => new CatchProcessorBasedScoringAlgorithm(beatmap, mode);
[Test]
public void TestBasicScenarios()
{
AddStep("set up score multiplier", () =>
{
scoreMultiplier.BindValueChanged(_ => Rerun());
});
AddStep("set max combo to 100", () => MaxCombo.Value = 100);
AddStep("set perfect score", () =>
{
NonPerfectLocations.Clear();
MissLocations.Clear();
});
AddStep("set score with misses", () =>
{
NonPerfectLocations.Clear();
MissLocations.Clear();
MissLocations.AddRange(new[] { 24d, 49 });
});
AddSliderStep("adjust score multiplier", 0, 10, (int)scoreMultiplier.Default, multiplier => scoreMultiplier.Value = multiplier);
}
private const int base_great = 300;
private class ScoreV1 : IScoringAlgorithm
{
private int currentCombo;
public BindableDouble ScoreMultiplier { get; } = new BindableDouble();
public void ApplyHit() => applyHitV1(base_great);
public void ApplyNonPerfect() => throw new NotSupportedException("catch does not have \"non-perfect\" judgements.");
public void ApplyMiss() => applyHitV1(0);
private void applyHitV1(int baseScore)
{
if (baseScore == 0)
{
currentCombo = 0;
return;
}
TotalScore += baseScore;
// combo multiplier
// ReSharper disable once PossibleLossOfFraction
TotalScore += (int)(Math.Max(0, currentCombo - 1) * (baseScore / 25 * ScoreMultiplier.Value));
currentCombo++;
}
public long TotalScore { get; private set; }
}
private class ScoreV2 : IScoringAlgorithm
{
private int currentCombo;
private double comboPortion;
private readonly double comboPortionMax;
private const double combo_base = 4;
private const int combo_cap = 200;
public ScoreV2(int maxCombo)
{
for (int i = 0; i < maxCombo; i++)
ApplyHit();
comboPortionMax = comboPortion;
currentCombo = 0;
comboPortion = 0;
}
public void ApplyHit() => applyHitV2(base_great);
public void ApplyNonPerfect() => throw new NotSupportedException("catch does not have \"non-perfect\" judgements.");
private void applyHitV2(int baseScore)
{
comboPortion += baseScore * Math.Min(Math.Max(0.5, Math.Log(++currentCombo, combo_base)), Math.Log(combo_cap, combo_base));
}
public void ApplyMiss()
{
currentCombo = 0;
}
public long TotalScore
=> (int)Math.Round(1000000 * comboPortion / comboPortionMax); // vast simplification, as we're not doing ticks here.
}
private class CatchProcessorBasedScoringAlgorithm : ProcessorBasedScoringAlgorithm
{
public CatchProcessorBasedScoringAlgorithm(IBeatmap beatmap, ScoringMode mode)
: base(beatmap, mode)
{
}
protected override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor();
protected override JudgementResult CreatePerfectJudgementResult() => new CatchJudgementResult(new Fruit(), new CatchJudgement()) { Type = HitResult.Great };
protected override JudgementResult CreateNonPerfectJudgementResult() => throw new NotSupportedException("catch does not have \"non-perfect\" judgements.");
protected override JudgementResult CreateMissJudgementResult() => new CatchJudgementResult(new Fruit(), new CatchJudgement()) { Type = HitResult.Miss };
}
}
}

View File

@ -40,6 +40,8 @@ namespace osu.Game.Tests.Visual.Gameplay
protected BindableList<double> NonPerfectLocations => graphs.NonPerfectLocations;
protected BindableList<double> MissLocations => graphs.MissLocations;
private readonly bool supportsNonPerfectJudgements;
private GraphContainer graphs = null!;
private SettingsSlider<int> sliderMaxCombo = null!;
private SettingsCheckbox scaleToMax = null!;
@ -54,11 +56,18 @@ namespace osu.Game.Tests.Visual.Gameplay
[Resolved]
private OsuColour colours { get; set; } = null!;
protected ScoringTestScene(bool supportsNonPerfectJudgements = true)
{
this.supportsNonPerfectJudgements = supportsNonPerfectJudgements;
}
[SetUpSteps]
public void SetUpSteps()
{
AddStep("setup tests", () =>
{
OsuTextFlowContainer clickExplainer;
Children = new Drawable[]
{
new Box
@ -79,7 +88,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
new Drawable[]
{
graphs = new GraphContainer
graphs = new GraphContainer(supportsNonPerfectJudgements)
{
RelativeSizeAxes = Axes.Both,
},
@ -120,11 +129,10 @@ namespace osu.Game.Tests.Visual.Gameplay
LabelText = "Rescale plots to 100%",
Current = { Value = true, Default = true }
},
new OsuTextFlowContainer
clickExplainer = new OsuTextFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Text = "Left click to add miss\nRight click to add OK",
Margin = new MarginPadding { Top = 20 }
}
}
@ -134,6 +142,10 @@ namespace osu.Game.Tests.Visual.Gameplay
}
};
clickExplainer.AddParagraph("Left click to add miss");
if (supportsNonPerfectJudgements)
clickExplainer.AddParagraph("Right click to add OK");
sliderMaxCombo.Current.BindValueChanged(_ => Rerun());
scaleToMax.Current.BindValueChanged(_ => Rerun());
@ -286,6 +298,8 @@ namespace osu.Game.Tests.Visual.Gameplay
public partial class GraphContainer : Container<LineGraph>, IHasCustomTooltip<IEnumerable<LineGraph>>
{
private readonly bool supportsNonPerfectJudgements;
public readonly BindableList<double> MissLocations = new BindableList<double>();
public readonly BindableList<double> NonPerfectLocations = new BindableList<double>();
@ -300,8 +314,9 @@ namespace osu.Game.Tests.Visual.Gameplay
public int CurrentHoverCombo { get; private set; }
public GraphContainer()
public GraphContainer(bool supportsNonPerfectJudgements)
{
this.supportsNonPerfectJudgements = supportsNonPerfectJudgements;
InternalChild = new Container
{
RelativeSizeAxes = Axes.Both,
@ -432,7 +447,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
if (e.Button == MouseButton.Left)
MissLocations.Add(CurrentHoverCombo);
else
else if (supportsNonPerfectJudgements)
NonPerfectLocations.Add(CurrentHoverCombo);
return true;