diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs
index 4dfadbb835..c282a919ea 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs
@@ -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
///
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);
+ }
+
+ ///
+ /// Calculates the min. distances from the 's position to the playfield border for the slider to be fully inside of the playfield.
+ ///
+ private MarginPadding getMinSliderMargin(Slider slider)
+ {
+ var pathPositions = new List();
+ 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;
}
///
@@ -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;
}
}