mirror of
https://github.com/ppy/osu.git
synced 2026-05-18 04:59:52 +08:00
Penalize angle repetition depending on the difference between vectors (#36559)
This is a slightly more intelligent angle repetition nerf that checks the previous vectors to see if the pattern has any rotation or not, this allows for harsh nerfs on current meta patterning like the N, X and V patterns while keeping things like rotating 1-2s and triangles less nerfed. The effect the vectors have on angle repetition is adjustable. --------- Co-authored-by: StanR <hi@stanr.info>
This commit is contained in:
committed by
GitHub
Unverified
parent
c2e9b052e7
commit
f3d97c0835
@@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Difficulty.Utils;
|
||||
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
|
||||
@@ -11,11 +12,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
{
|
||||
public static class SnapAimEvaluator
|
||||
{
|
||||
private const double wide_angle_multiplier = 1.3;
|
||||
private const double acute_angle_multiplier = 2.5;
|
||||
private const double slider_multiplier = 1.9;
|
||||
private const double velocity_change_multiplier = 1.0;
|
||||
private const double wide_angle_multiplier = 1.05;
|
||||
private const double acute_angle_multiplier = 2.41;
|
||||
private const double slider_multiplier = 1.5;
|
||||
private const double velocity_change_multiplier = 0.9;
|
||||
private const double wiggle_multiplier = 1.02; // WARNING: Increasing this multiplier beyond 1.02 reduces difficulty as distance increases. Refer to the desmos link above the wiggle bonus calculation
|
||||
private const double maximum_repetition_nerf = 0.15;
|
||||
private const double maximum_vector_influence = 0.5;
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the difficulty of aiming the current object, based on:
|
||||
@@ -117,7 +120,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
|
||||
if (distance < 1)
|
||||
{
|
||||
wideAngleBonus *= 1 - 0.35 * (1 - distance);
|
||||
wideAngleBonus *= 1 - 0.55 * (1 - distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,6 +152,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime;
|
||||
}
|
||||
|
||||
// Penalize angle repetition.
|
||||
aimStrain *= vectorAngleRepetition(osuCurrObj, osuLastObj);
|
||||
|
||||
aimStrain += wiggleBonus * wiggle_multiplier;
|
||||
aimStrain += velocityChangeBonus * velocity_change_multiplier;
|
||||
|
||||
@@ -173,6 +179,49 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
private static double highBpmBonus(double ms, double distance) => 1 / (1 - Math.Pow(0.03, Math.Pow(ms / 1000, 0.65)))
|
||||
* DifficultyCalculationUtils.Smootherstep(distance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS);
|
||||
|
||||
private static double vectorAngleRepetition(OsuDifficultyHitObject current, OsuDifficultyHitObject previous)
|
||||
{
|
||||
if (current.Angle == null || previous.Angle == null)
|
||||
return 1;
|
||||
|
||||
const double note_limit = 6;
|
||||
|
||||
double constantAngleCount = 0;
|
||||
|
||||
for (int index = 0; index < note_limit; index++)
|
||||
{
|
||||
var loopObj = (OsuDifficultyHitObject)current.Previous(index);
|
||||
|
||||
if (loopObj.IsNull())
|
||||
break;
|
||||
|
||||
// Only consider vectors in the same jump section, stopping to change rhythm ruins momentum
|
||||
if (Math.Max(current.AdjustedDeltaTime, loopObj.AdjustedDeltaTime) > 1.1 * Math.Min(current.AdjustedDeltaTime, loopObj.AdjustedDeltaTime))
|
||||
break;
|
||||
|
||||
if (loopObj.NormalisedVectorAngle.IsNotNull() && current.NormalisedVectorAngle.IsNotNull())
|
||||
{
|
||||
double angleDifference = Math.Abs(current.NormalisedVectorAngle.Value - loopObj.NormalisedVectorAngle.Value);
|
||||
// Refer to this desmos for tuning, constants need to be precise so that values stay within the range of 0 and 1.
|
||||
// https://www.desmos.com/calculator/a8jesv5sv2
|
||||
constantAngleCount += Math.Cos(8 * Math.Min(double.DegreesToRadians(11.25), angleDifference));
|
||||
}
|
||||
}
|
||||
|
||||
double vectorRepetition = Math.Pow(Math.Min(0.5 / constantAngleCount, 1), 2);
|
||||
|
||||
double stackFactor = DifficultyCalculationUtils.Smootherstep(current.LazyJumpDistance, 0, OsuDifficultyHitObject.NORMALISED_DIAMETER);
|
||||
|
||||
double currAngle = current.Angle.Value;
|
||||
double lastAngle = previous.Angle.Value;
|
||||
|
||||
double angleDifferenceAdjusted = Math.Cos(2 * Math.Min(double.DegreesToRadians(45), Math.Abs(currAngle - lastAngle) * stackFactor));
|
||||
|
||||
double baseNerf = 1 - maximum_repetition_nerf * CalcAcuteAngleBonus(lastAngle) * angleDifferenceAdjusted;
|
||||
|
||||
return Math.Pow(baseNerf + (1 - baseNerf) * vectorRepetition * maximum_vector_influence * stackFactor, 2);
|
||||
}
|
||||
|
||||
private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140));
|
||||
|
||||
public static double CalcAcuteAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(140), double.DegreesToRadians(40));
|
||||
|
||||
@@ -118,6 +118,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
|
||||
public double? AngularVelocity { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Angle of the vector created between current and current-1
|
||||
/// normalised to consider symmetrical vectors in any axis to be the same angle.
|
||||
/// </summary>
|
||||
public double? NormalisedVectorAngle { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Selective bonus for maps with higher circle size.
|
||||
/// </summary>
|
||||
@@ -261,6 +267,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
double angle = calculateAngle(BaseObject.StackedPosition, lastCursorPosition, lastLastCursorPosition);
|
||||
double sliderAngle = calculateSliderAngle(lastDifficultyObject!, lastLastCursorPosition);
|
||||
|
||||
Vector2 v = BaseObject.StackedPosition - lastCursorPosition;
|
||||
NormalisedVectorAngle = Math.Atan2(Math.Abs(v.Y), Math.Abs(v.X));
|
||||
|
||||
Angle = Math.Min(angle, sliderAngle);
|
||||
|
||||
if (lastLastDifficultyObject.Angle != null)
|
||||
|
||||
@@ -30,10 +30,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
|
||||
private double currentStrain;
|
||||
|
||||
private double skillMultiplierSnap => 65.2;
|
||||
private double skillMultiplierAgility => 2.7;
|
||||
private double skillMultiplierFlow => 262.0;
|
||||
private double skillMultiplierTotal => 1.0;
|
||||
private double skillMultiplierSnap => 71.0;
|
||||
private double skillMultiplierAgility => 2.0;
|
||||
private double skillMultiplierFlow => 238.0;
|
||||
private double skillMultiplierTotal => 1.1;
|
||||
private double meanExponent => 1.2;
|
||||
|
||||
private readonly List<double> sliderStrains = new List<double>();
|
||||
|
||||
Reference in New Issue
Block a user