mirror of
https://github.com/ppy/osu.git
synced 2025-01-15 14:12:54 +08:00
Enhance target angle calculation
This commit is contained in:
parent
2a9fbea367
commit
c6ac60c0b5
@ -37,23 +37,51 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
var positionInfos = OsuHitObjectGenerationUtils.GeneratePositionInfos(osuBeatmap.HitObjects);
|
var positionInfos = OsuHitObjectGenerationUtils.GeneratePositionInfos(osuBeatmap.HitObjects);
|
||||||
|
|
||||||
float rateOfChangeMultiplier = 0;
|
float sequenceOffset = 0;
|
||||||
|
bool flowDirection = false;
|
||||||
|
|
||||||
foreach (var positionInfo in positionInfos)
|
for (int i = 0; i < positionInfos.Count; i++)
|
||||||
{
|
{
|
||||||
// rateOfChangeMultiplier only changes every 5 iterations in a combo
|
bool invertFlow = false;
|
||||||
// to prevent shaky-line-shaped streams
|
|
||||||
if (positionInfo.HitObject.IndexInCurrentCombo % 5 == 0)
|
|
||||||
rateOfChangeMultiplier = (float)rng.NextDouble() * 2 - 1;
|
|
||||||
|
|
||||||
if (positionInfo == positionInfos.First())
|
if (i == 0 ||
|
||||||
|
(positionInfos[i - 1].HitObject.NewCombo && (i <= 1 || !positionInfos[i - 2].HitObject.NewCombo) && (i <= 2 || !positionInfos[i - 3].HitObject.NewCombo)) ||
|
||||||
|
OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject, true) ||
|
||||||
|
(OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject) && rng.NextDouble() < 0.25))
|
||||||
{
|
{
|
||||||
positionInfo.DistanceFromPrevious = (float)(rng.NextDouble() * OsuPlayfield.BASE_SIZE.Y / 2);
|
sequenceOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.02f);
|
||||||
positionInfo.RelativeAngle = (float)(rng.NextDouble() * 2 * Math.PI - Math.PI);
|
|
||||||
|
if (rng.NextDouble() < 0.6)
|
||||||
|
invertFlow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
positionInfos[i].DistanceFromPrevious = (float)(rng.NextDouble() * OsuPlayfield.BASE_SIZE.Y / 2);
|
||||||
|
positionInfos[i].RelativeAngle = (float)(rng.NextDouble() * 2 * Math.PI - Math.PI);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
positionInfo.RelativeAngle = rateOfChangeMultiplier * 2 * (float)Math.PI * Math.Min(1f, positionInfo.DistanceFromPrevious / (playfield_diagonal * 0.5f));
|
float flowChangeOffset = 0;
|
||||||
|
float oneTimeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.03f);
|
||||||
|
|
||||||
|
if (positionInfos[i - 1].HitObject.NewCombo && (i <= 1 || !positionInfos[i - 2].HitObject.NewCombo) && rng.NextDouble() < 0.6)
|
||||||
|
{
|
||||||
|
flowChangeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.05f);
|
||||||
|
|
||||||
|
if (rng.NextDouble() < 0.8)
|
||||||
|
invertFlow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invertFlow)
|
||||||
|
flowDirection ^= true;
|
||||||
|
|
||||||
|
positionInfos[i].RelativeAngle = OsuHitObjectGenerationUtils.GetRelativeTargetAngle(
|
||||||
|
positionInfos[i].DistanceFromPrevious,
|
||||||
|
(sequenceOffset + oneTimeOffset) * (float)Math.Sqrt(positionInfos[i].DistanceFromPrevious) +
|
||||||
|
flowChangeOffset * (float)Math.Sqrt(640 - positionInfos[i].DistanceFromPrevious),
|
||||||
|
flowDirection
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ using System.Linq;
|
|||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Game.Rulesets.Osu.UI;
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -186,5 +187,37 @@ namespace osu.Game.Rulesets.Osu.Utils
|
|||||||
length * MathF.Sin(angle)
|
length * MathF.Sin(angle)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsHitObjectOnBeat(OsuBeatmap beatmap, OsuHitObject hitObject, bool downbeatsOnly = false)
|
||||||
|
{
|
||||||
|
var timingPoints = beatmap.ControlPointInfo.TimingPoints;
|
||||||
|
var currentTimingPoint = timingPoints.Reverse().FirstOrDefault(p => p.Time <= hitObject.StartTime);
|
||||||
|
|
||||||
|
if (currentTimingPoint == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
double timeSinceTimingPoint = hitObject.StartTime - currentTimingPoint.Time;
|
||||||
|
|
||||||
|
double length = downbeatsOnly
|
||||||
|
? currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator
|
||||||
|
: currentTimingPoint.BeatLength;
|
||||||
|
|
||||||
|
return (timeSinceTimingPoint + 1) % length < 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float GetRelativeTargetAngle(float targetDistance, float offset, bool flowDirection)
|
||||||
|
{
|
||||||
|
float angle = (float)(3.3 / (1 + 200 * Math.Pow(MathHelper.E, 0.016 * (targetDistance - 466))) + 0.45 + offset);
|
||||||
|
float relativeAngle = MathHelper.Pi - angle;
|
||||||
|
return flowDirection ? -relativeAngle : relativeAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float RandomGaussian(Random rng, float mean = 0, float stdDev = 1)
|
||||||
|
{
|
||||||
|
double x1 = 1 - rng.NextDouble();
|
||||||
|
double x2 = 1 - rng.NextDouble();
|
||||||
|
double stdNormal = Math.Sqrt(-2 * Math.Log(x1)) * Math.Sin(MathHelper.TwoPi * x2);
|
||||||
|
return mean + stdDev * (float)stdNormal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user