mirror of
https://github.com/ppy/osu.git
synced 2025-03-11 01:07:23 +08:00
osu!taiko further considerations for rhythm (#31339)
* further considerations for rhythm * new rhythm balancing * fix license header * use isNormal to validate ratio * adjust tests --------- Co-authored-by: StanR <hi@stanr.info>
This commit is contained in:
parent
a83f917d87
commit
a42c03cea4
@ -14,13 +14,13 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
|
||||
|
||||
[TestCase(3.3172381854905493d, 200, "diffcalc-test")]
|
||||
[TestCase(3.3172381854905493d, 200, "diffcalc-test-strong")]
|
||||
[TestCase(3.3167800835687551d, 200, "diffcalc-test")]
|
||||
[TestCase(3.3167800835687551d, 200, "diffcalc-test-strong")]
|
||||
public void Test(double expectedStarRating, int expectedMaxCombo, string name)
|
||||
=> base.Test(expectedStarRating, expectedMaxCombo, name);
|
||||
|
||||
[TestCase(4.4640702427013101d, 200, "diffcalc-test")]
|
||||
[TestCase(4.4640702427013101d, 200, "diffcalc-test-strong")]
|
||||
[TestCase(4.4631326105105122d, 200, "diffcalc-test")]
|
||||
[TestCase(4.4631326105105122d, 200, "diffcalc-test-strong")]
|
||||
public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name)
|
||||
=> Test(expectedStarRating, expectedMaxCombo, name, new TaikoModDoubleTime());
|
||||
|
||||
|
@ -21,27 +21,39 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
|
||||
return -multiplier * Math.Pow(Math.Cos(denominator * Math.PI * ratio), power);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the ratio by ensuring it is a normal number in cases where maps breach regular mapping conditions.
|
||||
/// </summary>
|
||||
private static double validateRatio(double ratio)
|
||||
{
|
||||
return double.IsNormal(ratio) ? ratio : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the difficulty of a given ratio using a combination of periodic penalties and bonuses.
|
||||
/// </summary>
|
||||
private static double ratioDifficulty(double ratio, int terms = 8)
|
||||
{
|
||||
double difficulty = 0;
|
||||
ratio = validateRatio(ratio);
|
||||
|
||||
for (int i = 1; i <= terms; ++i)
|
||||
{
|
||||
difficulty += termPenalty(ratio, i, 2, 1);
|
||||
difficulty += termPenalty(ratio, i, 4, 1);
|
||||
}
|
||||
|
||||
difficulty += terms;
|
||||
difficulty += terms / (1 + ratio);
|
||||
|
||||
// Give bonus to near-1 ratios
|
||||
difficulty += DifficultyCalculationUtils.BellCurve(ratio, 1, 0.7);
|
||||
difficulty += DifficultyCalculationUtils.BellCurve(ratio, 1, 0.5);
|
||||
|
||||
// Penalize ratios that are VERY near 1
|
||||
difficulty -= DifficultyCalculationUtils.BellCurve(ratio, 1, 0.5);
|
||||
difficulty -= DifficultyCalculationUtils.BellCurve(ratio, 1, 0.3);
|
||||
|
||||
return difficulty / Math.Sqrt(8);
|
||||
difficulty = Math.Max(difficulty, 0);
|
||||
difficulty /= Math.Sqrt(8);
|
||||
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -55,10 +67,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
|
||||
? sameInterval(sameRhythmHitObjects, 4)
|
||||
: 1.0; // Returns a non-penalty if there are 6 or more notes within an interval.
|
||||
|
||||
// Scale penalties dynamically based on hit object duration relative to hitWindow.
|
||||
double penaltyScaling = Math.Max(1 - sameRhythmHitObjects.Duration / (hitWindow * 2), 0.5);
|
||||
// The duration penalty is based on hit object duration relative to hitWindow.
|
||||
double durationPenalty = Math.Max(1 - sameRhythmHitObjects.Duration * 2 / hitWindow, 0.5);
|
||||
|
||||
return Math.Min(longIntervalPenalty, shortIntervalPenalty) * penaltyScaling;
|
||||
return Math.Min(longIntervalPenalty, shortIntervalPenalty) * durationPenalty;
|
||||
|
||||
double sameInterval(SameRhythmHitObjects startObject, int intervalCount)
|
||||
{
|
||||
@ -82,7 +94,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
|
||||
{
|
||||
double ratio = intervals[i]!.Value / intervals[j]!.Value;
|
||||
if (Math.Abs(1 - ratio) <= threshold) // If any two intervals are similar, apply a penalty.
|
||||
return 0.3;
|
||||
return 0.80;
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,6 +107,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
|
||||
double intervalDifficulty = ratioDifficulty(sameRhythmHitObjects.HitObjectIntervalRatio);
|
||||
double? previousInterval = sameRhythmHitObjects.Previous?.HitObjectInterval;
|
||||
|
||||
intervalDifficulty *= repeatedIntervalPenalty(sameRhythmHitObjects, hitWindow);
|
||||
|
||||
// If a previous interval exists and there are multiple hit objects in the sequence:
|
||||
if (previousInterval != null && sameRhythmHitObjects.Children.Count > 1)
|
||||
{
|
||||
@ -111,9 +125,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
|
||||
}
|
||||
}
|
||||
|
||||
// Apply consistency penalty.
|
||||
intervalDifficulty *= repeatedIntervalPenalty(sameRhythmHitObjects, hitWindow);
|
||||
|
||||
// Penalise patterns that can be hit within a single hit window.
|
||||
intervalDifficulty *= DifficultyCalculationUtils.Logistic(
|
||||
sameRhythmHitObjects.Duration / hitWindow,
|
||||
@ -137,11 +148,20 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
|
||||
TaikoDifficultyHitObjectRhythm rhythm = ((TaikoDifficultyHitObject)hitObject).Rhythm;
|
||||
double difficulty = 0.0d;
|
||||
|
||||
double sameRhythm = 0;
|
||||
double samePattern = 0;
|
||||
double intervalPenalty = 0;
|
||||
|
||||
if (rhythm.SameRhythmHitObjects?.FirstHitObject == hitObject) // Difficulty for SameRhythmHitObjects
|
||||
difficulty += evaluateDifficultyOf(rhythm.SameRhythmHitObjects, hitWindow);
|
||||
{
|
||||
sameRhythm += 10.0 * evaluateDifficultyOf(rhythm.SameRhythmHitObjects, hitWindow);
|
||||
intervalPenalty = repeatedIntervalPenalty(rhythm.SameRhythmHitObjects, hitWindow);
|
||||
}
|
||||
|
||||
if (rhythm.SamePatterns?.FirstHitObject == hitObject) // Difficulty for SamePatterns
|
||||
difficulty += 0.5 * evaluateDifficultyOf(rhythm.SamePatterns);
|
||||
samePattern += 1.15 * evaluateDifficultyOf(rhythm.SamePatterns);
|
||||
|
||||
difficulty += Math.Max(sameRhythm, samePattern) * intervalPenalty;
|
||||
|
||||
return difficulty;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user