mirror of
https://github.com/ppy/osu.git
synced 2025-03-05 19:12:56 +08:00
Merge pull request #9833 from bdach/fix-spun-out-mod-rate-dependency
This commit is contained in:
commit
52374ac9c9
65
osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs
Normal file
65
osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// 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 System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||||
|
{
|
||||||
|
public class TestSceneOsuModSpunOut : OsuModTestScene
|
||||||
|
{
|
||||||
|
protected override bool AllowFail => true;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSpinnerAutoCompleted() => CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new OsuModSpunOut(),
|
||||||
|
Autoplay = false,
|
||||||
|
Beatmap = singleSpinnerBeatmap,
|
||||||
|
PassCondition = () => Player.ChildrenOfType<DrawableSpinner>().Single().Progress >= 1
|
||||||
|
});
|
||||||
|
|
||||||
|
[TestCase(null)]
|
||||||
|
[TestCase(typeof(OsuModDoubleTime))]
|
||||||
|
[TestCase(typeof(OsuModHalfTime))]
|
||||||
|
public void TestSpinRateUnaffectedByMods(Type additionalModType)
|
||||||
|
{
|
||||||
|
var mods = new List<Mod> { new OsuModSpunOut() };
|
||||||
|
if (additionalModType != null)
|
||||||
|
mods.Add((Mod)Activator.CreateInstance(additionalModType));
|
||||||
|
|
||||||
|
CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mods = mods,
|
||||||
|
Autoplay = false,
|
||||||
|
Beatmap = singleSpinnerBeatmap,
|
||||||
|
PassCondition = () => Precision.AlmostEquals(Player.ChildrenOfType<SpinnerSpmCounter>().Single().SpinsPerMinute, 286, 1)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Beatmap singleSpinnerBeatmap => new Beatmap
|
||||||
|
{
|
||||||
|
HitObjects = new List<HitObject>
|
||||||
|
{
|
||||||
|
new Spinner
|
||||||
|
{
|
||||||
|
Position = new Vector2(256, 192),
|
||||||
|
StartTime = 500,
|
||||||
|
Duration = 2000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -1,59 +0,0 @@
|
|||||||
// 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.Linq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
|
||||||
using osu.Game.Tests.Visual;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class TestSceneSpinnerSpunOut : OsuTestScene
|
|
||||||
{
|
|
||||||
[SetUp]
|
|
||||||
public void SetUp() => Schedule(() =>
|
|
||||||
{
|
|
||||||
SelectedMods.Value = new[] { new OsuModSpunOut() };
|
|
||||||
});
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestSpunOut()
|
|
||||||
{
|
|
||||||
DrawableSpinner spinner = null;
|
|
||||||
|
|
||||||
AddStep("create spinner", () => spinner = createSpinner());
|
|
||||||
|
|
||||||
AddUntilStep("wait for end", () => Time.Current > spinner.LifetimeEnd);
|
|
||||||
|
|
||||||
AddAssert("spinner is completed", () => spinner.Progress >= 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private DrawableSpinner createSpinner()
|
|
||||||
{
|
|
||||||
var spinner = new Spinner
|
|
||||||
{
|
|
||||||
StartTime = Time.Current + 500,
|
|
||||||
EndTime = Time.Current + 2500
|
|
||||||
};
|
|
||||||
spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
|
||||||
|
|
||||||
var drawableSpinner = new DrawableSpinner(spinner)
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var mod in SelectedMods.Value.OfType<IApplicableToDrawableHitObjects>())
|
|
||||||
mod.ApplyToDrawableHitObjects(new[] { drawableSpinner });
|
|
||||||
|
|
||||||
Add(drawableSpinner);
|
|
||||||
return drawableSpinner;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -41,7 +41,16 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
var spinner = (DrawableSpinner)drawable;
|
var spinner = (DrawableSpinner)drawable;
|
||||||
|
|
||||||
spinner.RotationTracker.Tracking = true;
|
spinner.RotationTracker.Tracking = true;
|
||||||
spinner.RotationTracker.AddRotation(MathUtils.RadiansToDegrees((float)spinner.Clock.ElapsedFrameTime * 0.03f));
|
|
||||||
|
// early-return if we were paused to avoid division-by-zero in the subsequent calculations.
|
||||||
|
if (Precision.AlmostEquals(spinner.Clock.Rate, 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// because the spinner is under the gameplay clock, it is affected by rate adjustments on the track;
|
||||||
|
// 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.
|
||||||
|
var rateIndependentElapsedTime = spinner.Clock.ElapsedFrameTime / spinner.Clock.Rate;
|
||||||
|
spinner.RotationTracker.AddRotation(MathUtils.RadiansToDegrees((float)rateIndependentElapsedTime * 0.03f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,8 +40,8 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
var mods = new List<Mod>(SelectedMods.Value);
|
var mods = new List<Mod>(SelectedMods.Value);
|
||||||
|
|
||||||
if (currentTestData.Mod != null)
|
if (currentTestData.Mods != null)
|
||||||
mods.Add(currentTestData.Mod);
|
mods.AddRange(currentTestData.Mods);
|
||||||
if (currentTestData.Autoplay)
|
if (currentTestData.Autoplay)
|
||||||
mods.Add(ruleset.GetAutoplayMod());
|
mods.Add(ruleset.GetAutoplayMod());
|
||||||
|
|
||||||
@ -85,9 +85,18 @@ namespace osu.Game.Tests.Visual
|
|||||||
public Func<bool> PassCondition;
|
public Func<bool> PassCondition;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The <see cref="Mod"/> this test case tests.
|
/// The <see cref="Mod"/>s this test case tests.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Mod Mod;
|
public IReadOnlyList<Mod> Mods;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convenience property for setting <see cref="Mods"/> if only
|
||||||
|
/// a single mod is to be tested.
|
||||||
|
/// </summary>
|
||||||
|
public Mod Mod
|
||||||
|
{
|
||||||
|
set => Mods = new[] { value };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user