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

Merge pull request #13337 from Pasi4K5/fix-sliders-out-of-screen

Fix sliders sometimes being outside of the playfield with osu! random mod enabled
This commit is contained in:
Dean Herbert 2021-06-08 21:18:21 +09:00 committed by GitHub
commit 475788041a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Utils;
@ -30,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Mods
private static readonly float border_distance_x = OsuPlayfield.BASE_SIZE.X * playfield_edge_ratio;
private static readonly float border_distance_y = OsuPlayfield.BASE_SIZE.Y * playfield_edge_ratio;
private static readonly Vector2 playfield_middle = Vector2.Divide(OsuPlayfield.BASE_SIZE, 2);
private static readonly Vector2 playfield_middle = OsuPlayfield.BASE_SIZE / 2;
private static readonly float playfield_diagonal = OsuPlayfield.BASE_SIZE.LengthFast;
@ -74,22 +75,8 @@ namespace osu.Game.Rulesets.Osu.Mods
// update end position as it may have changed as a result of the position update.
current.EndPositionRandomised = current.PositionRandomised;
switch (hitObject)
{
case Slider slider:
// Shift nested objects the same distance as the slider got shifted in the randomisation process
// so that moveSliderIntoPlayfield() can determine their relative distances to slider.Position and thus minMargin
shiftNestedObjects(slider, Vector2.Subtract(slider.Position, current.PositionOriginal));
var oldPos = new Vector2(slider.Position.X, slider.Position.Y);
moveSliderIntoPlayfield(slider, current);
// Shift them again to move them to their final position after the slider got moved into the playfield
shiftNestedObjects(slider, Vector2.Subtract(slider.Position, oldPos));
break;
}
if (hitObject is Slider slider)
moveSliderIntoPlayfield(slider, current);
previous = current;
}
@ -131,7 +118,7 @@ namespace osu.Game.Rulesets.Osu.Mods
current.AngleRad = (float)Math.Atan2(posRelativeToPrev.Y, posRelativeToPrev.X);
var position = Vector2.Add(previous.EndPositionRandomised, posRelativeToPrev);
var position = previous.EndPositionRandomised + posRelativeToPrev;
// Move hit objects back into the playfield if they are outside of it,
// which would sometimes happen during big jumps otherwise.
@ -146,34 +133,41 @@ namespace osu.Game.Rulesets.Osu.Mods
/// </summary>
private void moveSliderIntoPlayfield(Slider slider, RandomObjectInfo currentObjectInfo)
{
// Min. distances from the slider's position to the playfield border
var minMargin = new MarginPadding();
var minMargin = getMinSliderMargin(slider);
foreach (var hitObject in slider.NestedHitObjects.Where(o => o is SliderTick || o is SliderEndCircle))
{
if (!(hitObject is OsuHitObject osuHitObject))
continue;
var relativePos = Vector2.Subtract(osuHitObject.Position, slider.Position);
minMargin.Left = Math.Max(minMargin.Left, -relativePos.X);
minMargin.Right = Math.Max(minMargin.Right, relativePos.X);
minMargin.Top = Math.Max(minMargin.Top, -relativePos.Y);
minMargin.Bottom = Math.Max(minMargin.Bottom, relativePos.Y);
}
if (slider.Position.X < minMargin.Left)
slider.Position = new Vector2(minMargin.Left, slider.Position.Y);
else if (slider.Position.X + minMargin.Right > OsuPlayfield.BASE_SIZE.X)
slider.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - minMargin.Right, slider.Position.Y);
if (slider.Position.Y < minMargin.Top)
slider.Position = new Vector2(slider.Position.X, minMargin.Top);
else if (slider.Position.Y + minMargin.Bottom > OsuPlayfield.BASE_SIZE.Y)
slider.Position = new Vector2(slider.Position.X, OsuPlayfield.BASE_SIZE.Y - minMargin.Bottom);
slider.Position = new Vector2(
Math.Clamp(slider.Position.X, minMargin.Left, OsuPlayfield.BASE_SIZE.X - minMargin.Right),
Math.Clamp(slider.Position.Y, minMargin.Top, OsuPlayfield.BASE_SIZE.Y - minMargin.Bottom)
);
currentObjectInfo.PositionRandomised = slider.Position;
currentObjectInfo.EndPositionRandomised = slider.EndPosition;
shiftNestedObjects(slider, currentObjectInfo.PositionRandomised - currentObjectInfo.PositionOriginal);
}
/// <summary>
/// Calculates the min. distances from the <see cref="Slider"/>'s position to the playfield border for the slider to be fully inside of the playfield.
/// </summary>
private MarginPadding getMinSliderMargin(Slider slider)
{
var pathPositions = new List<Vector2>();
slider.Path.GetPathToProgress(pathPositions, 0, 1);
var minMargin = new MarginPadding();
foreach (var pos in pathPositions)
{
minMargin.Left = Math.Max(minMargin.Left, -pos.X);
minMargin.Right = Math.Max(minMargin.Right, pos.X);
minMargin.Top = Math.Max(minMargin.Top, -pos.Y);
minMargin.Bottom = Math.Max(minMargin.Bottom, pos.Y);
}
minMargin.Left = Math.Min(minMargin.Left, OsuPlayfield.BASE_SIZE.X - minMargin.Right);
minMargin.Top = Math.Min(minMargin.Top, OsuPlayfield.BASE_SIZE.Y - minMargin.Bottom);
return minMargin;
}
/// <summary>
@ -188,7 +182,7 @@ namespace osu.Game.Rulesets.Osu.Mods
if (!(hitObject is OsuHitObject osuHitObject))
continue;
osuHitObject.Position = Vector2.Add(osuHitObject.Position, shift);
osuHitObject.Position += shift;
}
}