mirror of
https://github.com/osukey/osukey.git
synced 2025-05-30 01:47:30 +09:00
Merge pull request #16860 from sh0ckR6/issues/16839-spun-out-rate
Give "Spun Out" dynamic spin rate
This commit is contained in:
commit
7302e66c5f
@ -8,12 +8,15 @@ using NUnit.Framework;
|
|||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Skinning.Default;
|
using osu.Game.Rulesets.Osu.Skinning.Default;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||||
@ -23,13 +26,37 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
|||||||
protected override bool AllowFail => true;
|
protected override bool AllowFail => true;
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSpinnerAutoCompleted() => CreateModTest(new ModTestData
|
public void TestSpinnerAutoCompleted()
|
||||||
{
|
{
|
||||||
Mod = new OsuModSpunOut(),
|
DrawableSpinner spinner = null;
|
||||||
Autoplay = false,
|
JudgementResult lastResult = null;
|
||||||
Beatmap = singleSpinnerBeatmap,
|
|
||||||
PassCondition = () => Player.ChildrenOfType<DrawableSpinner>().SingleOrDefault()?.Progress >= 1
|
CreateModTest(new ModTestData
|
||||||
});
|
{
|
||||||
|
Mod = new OsuModSpunOut(),
|
||||||
|
Autoplay = false,
|
||||||
|
Beatmap = singleSpinnerBeatmap,
|
||||||
|
PassCondition = () =>
|
||||||
|
{
|
||||||
|
// Bind to the first spinner's results for further tracking.
|
||||||
|
if (spinner == null)
|
||||||
|
{
|
||||||
|
// We only care about the first spinner we encounter for this test.
|
||||||
|
var nextSpinner = Player.ChildrenOfType<DrawableSpinner>().SingleOrDefault();
|
||||||
|
|
||||||
|
if (nextSpinner == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
lastResult = null;
|
||||||
|
|
||||||
|
spinner = nextSpinner;
|
||||||
|
spinner.OnNewResult += (o, result) => lastResult = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastResult?.Type == HitResult.Great;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[TestCase(null)]
|
[TestCase(null)]
|
||||||
[TestCase(typeof(OsuModDoubleTime))]
|
[TestCase(typeof(OsuModDoubleTime))]
|
||||||
@ -48,7 +75,57 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
|||||||
PassCondition = () =>
|
PassCondition = () =>
|
||||||
{
|
{
|
||||||
var counter = Player.ChildrenOfType<SpinnerSpmCalculator>().SingleOrDefault();
|
var counter = Player.ChildrenOfType<SpinnerSpmCalculator>().SingleOrDefault();
|
||||||
return counter != null && Precision.AlmostEquals(counter.Result.Value, 286, 1);
|
var spinner = Player.ChildrenOfType<DrawableSpinner>().FirstOrDefault();
|
||||||
|
|
||||||
|
if (counter == null || spinner == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// ignore cases where the spinner hasn't started as these lead to false-positives
|
||||||
|
if (Precision.AlmostEquals(counter.Result.Value, 0, 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
float rotationSpeed = (float)(1.01 * spinner.HitObject.SpinsRequired / spinner.HitObject.Duration);
|
||||||
|
|
||||||
|
return Precision.AlmostEquals(counter.Result.Value, rotationSpeed * 1000 * 60, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSpinnerGetsNoBonusScore()
|
||||||
|
{
|
||||||
|
DrawableSpinner spinner = null;
|
||||||
|
List<JudgementResult> results = new List<JudgementResult>();
|
||||||
|
|
||||||
|
CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new OsuModSpunOut(),
|
||||||
|
Autoplay = false,
|
||||||
|
Beatmap = singleSpinnerBeatmap,
|
||||||
|
PassCondition = () =>
|
||||||
|
{
|
||||||
|
// Bind to the first spinner's results for further tracking.
|
||||||
|
if (spinner == null)
|
||||||
|
{
|
||||||
|
// We only care about the first spinner we encounter for this test.
|
||||||
|
var nextSpinner = Player.ChildrenOfType<DrawableSpinner>().SingleOrDefault();
|
||||||
|
|
||||||
|
if (nextSpinner == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
spinner = nextSpinner;
|
||||||
|
spinner.OnNewResult += (o, result) => results.Add(result);
|
||||||
|
|
||||||
|
results.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// we should only be checking the bonus/progress after the spinner has fully completed.
|
||||||
|
if (results.OfType<OsuSpinnerJudgementResult>().All(r => r.TimeCompleted == null))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return
|
||||||
|
results.Any(r => r.Type == HitResult.SmallBonus)
|
||||||
|
&& results.All(r => r.Type != HitResult.LargeBonus);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,11 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
// for that reason using ElapsedFrameTime directly leads to fewer SPM with Half Time and more SPM with Double Time.
|
// for that reason using ElapsedFrameTime directly leads to fewer SPM with Half Time and more SPM with Double Time.
|
||||||
// for spinners we want the real (wall clock) elapsed time; to achieve that, unapply the clock rate locally here.
|
// for spinners we want the real (wall clock) elapsed time; to achieve that, unapply the clock rate locally here.
|
||||||
double rateIndependentElapsedTime = spinner.Clock.ElapsedFrameTime / spinner.Clock.Rate;
|
double rateIndependentElapsedTime = spinner.Clock.ElapsedFrameTime / spinner.Clock.Rate;
|
||||||
spinner.RotationTracker.AddRotation(MathUtils.RadiansToDegrees((float)rateIndependentElapsedTime * 0.03f));
|
|
||||||
|
// multiply the SPM by 1.01 to ensure that the spinner is completed. if the calculation is left exact,
|
||||||
|
// some spinners may not complete due to very minor decimal loss during calculation
|
||||||
|
float rotationSpeed = (float)(1.01 * spinner.HitObject.SpinsRequired / spinner.HitObject.Duration);
|
||||||
|
spinner.RotationTracker.AddRotation(MathUtils.RadiansToDegrees((float)rateIndependentElapsedTime * rotationSpeed * MathF.PI * 2.0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user