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:
commit
aba98f2985
157
osu.Game.Rulesets.Catch.Tests/TestSceneScoring.cs
Normal file
157
osu.Game.Rulesets.Catch.Tests/TestSceneScoring.cs
Normal 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 };
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user