mirror of
https://github.com/ppy/osu.git
synced 2025-01-12 18:23:04 +08:00
Merge pull request #24932 from smoogipoo/spinner-od-based-max-rpm
Cap maximum spinner RPM based on OD
This commit is contained in:
commit
0a208a5a47
@ -43,7 +43,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
AddUntilStep("Pitch starts low", () => getSpinningSample().Frequency.Value < 0.8);
|
AddUntilStep("Pitch starts low", () => getSpinningSample().Frequency.Value < 0.8);
|
||||||
AddUntilStep("Pitch increases", () => getSpinningSample().Frequency.Value > 0.8);
|
AddUntilStep("Pitch increases", () => getSpinningSample().Frequency.Value > 0.8);
|
||||||
|
|
||||||
PausableSkinnableSound getSpinningSample() => drawableSpinner.ChildrenOfType<PausableSkinnableSound>().FirstOrDefault(s => s.Samples.Any(i => i.LookupNames.Any(l => l.Contains("spinnerspin"))));
|
PausableSkinnableSound getSpinningSample() =>
|
||||||
|
drawableSpinner.ChildrenOfType<PausableSkinnableSound>().FirstOrDefault(s => s.Samples.Any(i => i.LookupNames.Any(l => l.Contains("spinnerspin"))));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(false)]
|
[TestCase(false)]
|
||||||
@ -64,6 +65,39 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
AddUntilStep("Short spinner implicitly completes", () => drawableSpinner.Progress == 1);
|
AddUntilStep("Short spinner implicitly completes", () => drawableSpinner.Progress == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase(0, 4, 6)]
|
||||||
|
[TestCase(5, 7, 10)]
|
||||||
|
[TestCase(10, 11, 8)]
|
||||||
|
public void TestSpinnerSpinRequirements(int od, int normalTicks, int bonusTicks)
|
||||||
|
{
|
||||||
|
Spinner spinner = null;
|
||||||
|
|
||||||
|
AddStep("add spinner", () => SetContents(_ =>
|
||||||
|
{
|
||||||
|
spinner = new Spinner
|
||||||
|
{
|
||||||
|
StartTime = Time.Current,
|
||||||
|
EndTime = Time.Current + 3000,
|
||||||
|
Samples = new List<HitSampleInfo>
|
||||||
|
{
|
||||||
|
new HitSampleInfo(HitSampleInfo.HIT_NORMAL)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { OverallDifficulty = od });
|
||||||
|
|
||||||
|
return drawableSpinner = new TestDrawableSpinner(spinner, true)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Depth = depthIndex++,
|
||||||
|
Scale = new Vector2(0.75f)
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
AddAssert("number of normal ticks matches", () => spinner.SpinsRequired, () => Is.EqualTo(normalTicks));
|
||||||
|
AddAssert("number of bonus ticks matches", () => spinner.MaximumBonusSpins, () => Is.EqualTo(bonusTicks));
|
||||||
|
}
|
||||||
|
|
||||||
private Drawable testSingle(float circleSize, bool auto = false, double length = 3000)
|
private Drawable testSingle(float circleSize, bool auto = false, double length = 3000)
|
||||||
{
|
{
|
||||||
const double delay = 2000;
|
const double delay = 2000;
|
||||||
|
@ -18,6 +18,16 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
{
|
{
|
||||||
public class Spinner : OsuHitObject, IHasDuration
|
public class Spinner : OsuHitObject, IHasDuration
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The RPM required to clear the spinner at ODs [ 0, 5, 10 ].
|
||||||
|
/// </summary>
|
||||||
|
private static readonly (int min, int mid, int max) clear_rpm_range = (90, 150, 225);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The RPM required to complete the spinner and receive full score at ODs [ 0, 5, 10 ].
|
||||||
|
/// </summary>
|
||||||
|
private static readonly (int min, int mid, int max) complete_rpm_range = (250, 380, 430);
|
||||||
|
|
||||||
public double EndTime
|
public double EndTime
|
||||||
{
|
{
|
||||||
get => StartTime + Duration;
|
get => StartTime + Duration;
|
||||||
@ -52,13 +62,16 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
{
|
{
|
||||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||||
|
|
||||||
const double maximum_rotations_per_second = 477f / 60f;
|
// The average RPS required over the length of the spinner to clear the spinner.
|
||||||
|
double minRps = IBeatmapDifficultyInfo.DifficultyRange(difficulty.OverallDifficulty, clear_rpm_range) / 60;
|
||||||
|
|
||||||
|
// The RPS required over the length of the spinner to receive full score (all normal + bonus ticks).
|
||||||
|
double maxRps = IBeatmapDifficultyInfo.DifficultyRange(difficulty.OverallDifficulty, complete_rpm_range) / 60;
|
||||||
|
|
||||||
double secondsDuration = Duration / 1000;
|
double secondsDuration = Duration / 1000;
|
||||||
double minimumRotationsPerSecond = IBeatmapDifficultyInfo.DifficultyRange(difficulty.OverallDifficulty, 1.5, 2.5, 3.75);
|
|
||||||
|
|
||||||
SpinsRequired = (int)(secondsDuration * minimumRotationsPerSecond);
|
SpinsRequired = (int)(minRps * secondsDuration);
|
||||||
MaximumBonusSpins = (int)((maximum_rotations_per_second - minimumRotationsPerSecond) * secondsDuration) - bonus_spins_gap;
|
MaximumBonusSpins = Math.Max(0, (int)(maxRps * secondsDuration) - SpinsRequired - bonus_spins_gap);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
|
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
|
||||||
|
Loading…
Reference in New Issue
Block a user