1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-14 02:22:56 +08:00

Merge branch 'aim-refactor-velocity' into aim-refactor-ppcalc

This commit is contained in:
Xexxar 2021-11-07 14:56:50 +00:00
commit 4493ca4dda
3 changed files with 30 additions and 29 deletions

View File

@ -15,13 +15,13 @@ namespace osu.Game.Rulesets.Osu.Tests
{ {
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu"; protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
[TestCase(6.5295339534769958d, "diffcalc-test")] [TestCase(6.531832890435525d, "diffcalc-test")]
[TestCase(1.1514260533755143d, "zero-length-sliders")] [TestCase(1.4644923495008817d, "zero-length-sliders")]
public void Test(double expected, string name) public void Test(double expected, string name)
=> base.Test(expected, name); => base.Test(expected, name);
[TestCase(9.047752485219954d, "diffcalc-test")] [TestCase(8.8067616302940852d, "diffcalc-test")]
[TestCase(1.3985711787077566d, "zero-length-sliders")] [TestCase(1.7763214959309293d, "zero-length-sliders")]
public void TestClockRateAdjusted(double expected, string name) public void TestClockRateAdjusted(double expected, string name)
=> Test(expected, name, new OsuModDoubleTime()); => Test(expected, name, new OsuModDoubleTime());

View File

@ -101,7 +101,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
// such that they're not jumping from the lazy position but rather from very close to (or the end of) the slider. // such that they're not jumping from the lazy position but rather from very close to (or the end of) the slider.
// In such cases, a leniency is applied by also considering the jump distance from the tail of the slider, and taking the minimum jump distance. // In such cases, a leniency is applied by also considering the jump distance from the tail of the slider, and taking the minimum jump distance.
// Additional distance is removed based on position of jump relative to slider follow circle radius. // Additional distance is removed based on position of jump relative to slider follow circle radius.
// JumpDistance is the distance beyond the s. tailJumpDistance is maximum_slider_radius since the full distance of radial leniency is still possible. // JumpDistance is the leniency distance beyond the assumed_slider_radius. tailJumpDistance is maximum_slider_radius since the full distance of radial leniency is still possible.
MovementDistance = Math.Max(0, Math.Min(JumpDistance - (maximum_slider_radius - assumed_slider_radius), tailJumpDistance - maximum_slider_radius)); MovementDistance = Math.Max(0, Math.Min(JumpDistance - (maximum_slider_radius - assumed_slider_radius), tailJumpDistance - maximum_slider_radius));
} }
else else
@ -148,6 +148,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
Vector2 currMovement = Vector2.Subtract(currMovementObj.StackedPosition, currCursorPosition); Vector2 currMovement = Vector2.Subtract(currMovementObj.StackedPosition, currCursorPosition);
double currMovementLength = scalingFactor * currMovement.Length; double currMovementLength = scalingFactor * currMovement.Length;
// Amount of movement required so that the cursor position needs to be updated.
double requiredMovement = assumed_slider_radius;
if (i == slider.NestedHitObjects.Count - 1) if (i == slider.NestedHitObjects.Count - 1)
{ {
// The end of a slider has special aim rules due to the relaxed time constraint on position. // The end of a slider has special aim rules due to the relaxed time constraint on position.
@ -160,31 +163,23 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
currMovement = lazyMovement; currMovement = lazyMovement;
currMovementLength = scalingFactor * currMovement.Length; currMovementLength = scalingFactor * currMovement.Length;
if (currMovementLength > assumed_slider_radius)
{
// Calculate the vector movement, regardless of final location to get the true lazy end position.
currCursorPosition = Vector2.Add(currCursorPosition, Vector2.Multiply(currMovement, (float)((currMovementLength - assumed_slider_radius) / currMovementLength)));
currMovementLength *= (currMovementLength - assumed_slider_radius) / currMovementLength;
slider.LazyTravelDistance += (float)currMovementLength;
} }
else if (currMovementObj is SliderRepeat)
slider.LazyEndPosition = currCursorPosition;
}
else if (currMovementObj is SliderRepeat && currMovementLength > normalized_radius)
{ {
// For a slider repeat, assume a tighter movement threshold to better assess repeat sliders. // For a slider repeat, assume a tighter movement threshold to better assess repeat sliders.
currCursorPosition = Vector2.Add(currCursorPosition, Vector2.Multiply(currMovement, (float)((currMovementLength - normalized_radius) / currMovementLength))); requiredMovement = normalized_radius;
currMovementLength *= (currMovementLength - normalized_radius) / currMovementLength;
slider.LazyTravelDistance += (float)currMovementLength;
} }
else if (currMovementLength > assumed_slider_radius)
if (currMovementLength > requiredMovement)
{ {
// For a slider ticks, use the assumed slider radius for a more accurate movement assessment. // this finds the positional delta from the required radius and the current position, and updates the currCursorPosition accordingly, as well as rewarding distance.
currCursorPosition = Vector2.Add(currCursorPosition, Vector2.Multiply(currMovement, (float)((currMovementLength - assumed_slider_radius) / currMovementLength))); currCursorPosition = Vector2.Add(currCursorPosition, Vector2.Multiply(currMovement, (float)((currMovementLength - requiredMovement) / currMovementLength)));
currMovementLength *= (currMovementLength - assumed_slider_radius) / currMovementLength; currMovementLength *= (currMovementLength - requiredMovement) / currMovementLength;
slider.LazyTravelDistance += (float)currMovementLength; slider.LazyTravelDistance += (float)currMovementLength;
} }
if (i == slider.NestedHitObjects.Count - 1)
slider.LazyEndPosition = currCursorPosition;
} }
slider.LazyTravelDistance *= (float)Math.Pow(1 + slider.RepeatCount / 2.5, 1.0 / 2.5); // Bonus for repeat sliders until a better per nested object strain system can be achieved. slider.LazyTravelDistance *= (float)Math.Pow(1 + slider.RepeatCount / 2.5, 1.0 / 2.5); // Bonus for repeat sliders until a better per nested object strain system can be achieved.

View File

@ -94,18 +94,23 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
* Math.Pow(Math.Sin(Math.PI / 2 * (Math.Clamp(osuCurrObj.JumpDistance, 50, 100) - 50) / 50), 2); // Buff distance exceeding 50 (radius) up to 100 (diameter). * Math.Pow(Math.Sin(Math.PI / 2 * (Math.Clamp(osuCurrObj.JumpDistance, 50, 100) - 50) / 50), 2); // Buff distance exceeding 50 (radius) up to 100 (diameter).
} }
wideAngleBonus *= angleBonus * (1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3))); // Penalize wide angles if they're repeated, reducing the penalty as the lastAngle gets more acute. // Penalize wide angles if they're repeated, reducing the penalty as the lastAngle gets more acute.
acuteAngleBonus *= 0.5 + 0.5 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastLastAngle), 3))); // Penalize acute angles if they're repeated, reducing the penalty as the lastLastAngle gets more obtuse. wideAngleBonus *= angleBonus * (1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3)));
// Penalize acute angles if they're repeated, reducing the penalty as the lastLastAngle gets more obtuse.
acuteAngleBonus *= 0.5 + 0.5 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastLastAngle), 3)));
} }
} }
if (Math.Max(prevVelocity, currVelocity) != 0) if (Math.Max(prevVelocity, currVelocity) != 0)
{ {
prevVelocity = (osuLastObj.JumpDistance + osuLastObj.TravelDistance) / osuLastObj.StrainTime; // We want to use the average velocity over the whole object when awarding differences, not the individual jump and slider path velocities. // We want to use the average velocity over the whole object when awarding differences, not the individual jump and slider path velocities.
prevVelocity = (osuLastObj.JumpDistance + osuLastObj.TravelDistance) / osuLastObj.StrainTime;
currVelocity = (osuCurrObj.JumpDistance + osuCurrObj.TravelDistance) / osuCurrObj.StrainTime; currVelocity = (osuCurrObj.JumpDistance + osuCurrObj.TravelDistance) / osuCurrObj.StrainTime;
double distRatio = Math.Pow(Math.Sin(Math.PI / 2 * Math.Abs(prevVelocity - currVelocity) / Math.Max(prevVelocity, currVelocity)), 2); // scale with ratio of difference compared to 0.5 * max dist. // scale with ratio of difference compared to 0.5 * max dist.
double overlapVelocityBuff = Math.Min(125 / Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime), Math.Abs(prevVelocity - currVelocity)); // reward for % distance up to 125 / strainTime for overlaps where velocity is still changing. double distRatio = Math.Pow(Math.Sin(Math.PI / 2 * Math.Abs(prevVelocity - currVelocity) / Math.Max(prevVelocity, currVelocity)), 2);
// reward for % distance up to 125 / strainTime for overlaps where velocity is still changing.
double overlapVelocityBuff = Math.Min(125 / Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime), Math.Abs(prevVelocity - currVelocity));
double nonOverlapVelocityBuff = Math.Abs(prevVelocity - currVelocity) // reward for % distance slowed down compared to previous, paying attention to not award overlap double nonOverlapVelocityBuff = Math.Abs(prevVelocity - currVelocity) // reward for % distance slowed down compared to previous, paying attention to not award overlap
* Math.Pow(Math.Sin(Math.PI / 2 * Math.Min(1, Math.Min(osuCurrObj.JumpDistance, osuLastObj.JumpDistance) / 100)), 2); // do not award overlap * Math.Pow(Math.Sin(Math.PI / 2 * Math.Min(1, Math.Min(osuCurrObj.JumpDistance, osuLastObj.JumpDistance) / 100)), 2); // do not award overlap
@ -119,7 +124,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; // add some slider rewards sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; // add some slider rewards
} }
aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier + velChangeBonus * vel_change_multiplier); // Add in acute angle bonus or wide angle bonus + velchange bonus, whichever is larger. // Add in acute angle bonus or wide angle bonus + velchange bonus, whichever is larger.
aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier + velChangeBonus * vel_change_multiplier);
aimStrain += sliderBonus * slider_multiplier; // Add in additional slider velocity. aimStrain += sliderBonus * slider_multiplier; // Add in additional slider velocity.
return aimStrain; return aimStrain;