diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index cd63b618bd..e134dcef89 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -67,34 +67,32 @@ namespace osu.Game.Rulesets.Osu.Mods applyRandomisation(rateOfChangeMultiplier, previous, current); - // Move hit objects back into the playfield if they are outside of it, - // which would sometimes happen during big jumps otherwise. - current.PositionRandomised = clampToPlayfield(current.PositionRandomised, (float)hitObject.Radius); + // Move hit objects back into the playfield if they are outside of it + Vector2 shift = Vector2.Zero; - hitObject.Position = current.PositionRandomised; - - // update end position as it may have changed as a result of the position update. - current.EndPositionRandomised = current.PositionRandomised; - - if (hitObject is Slider slider) + if (hitObject is HitCircle circle) { - Vector2 shift = moveSliderIntoPlayfield(slider, current); + shift = clampHitCircleToPlayfield(circle, current); + } + else if (hitObject is Slider slider) + { + shift = clampSliderToPlayfield(slider, current); + } - if (shift != Vector2.Zero) + if (shift != Vector2.Zero) + { + var toBeShifted = new List(); + + for (int j = i - 1; j >= i - objects_to_shift_before_slider && j >= 0; j--) { - var toBeShifted = new List(); + // only shift hit circles + if (!(hitObjects[j] is HitCircle)) break; - for (int j = i - 1; j >= i - objects_to_shift_before_slider && j >= 0; j--) - { - // only shift hit circles - if (!(hitObjects[j] is HitCircle)) break; - - toBeShifted.Add(hitObjects[j]); - } - - if (toBeShifted.Count > 0) - applyDecreasingShift(toBeShifted, shift); + toBeShifted.Add(hitObjects[j]); } + + if (toBeShifted.Count > 0) + applyDecreasingShift(toBeShifted, shift); } previous = current; @@ -145,31 +143,29 @@ namespace osu.Game.Rulesets.Osu.Mods /// /// Moves the and all necessary nested s into the if they aren't already. /// - /// The that this slider has been shifted by. - private Vector2 moveSliderIntoPlayfield(Slider slider, RandomObjectInfo currentObjectInfo) + /// The deviation from the original randomised position in order to fit within the playfield. + private Vector2 clampSliderToPlayfield(Slider slider, RandomObjectInfo objectInfo) { var area = calculatePossibleMovementBounds(slider); - var prevPosition = slider.Position; + var previousPosition = objectInfo.PositionRandomised; // Clamp slider position to the placement area // If the slider is larger than the playfield, force it to stay at the original position var newX = area.Width < 0 - ? currentObjectInfo.PositionOriginal.X - : Math.Clamp(slider.Position.X, area.Left, area.Right); + ? objectInfo.PositionOriginal.X + : Math.Clamp(previousPosition.X, area.Left, area.Right); var newY = area.Height < 0 - ? currentObjectInfo.PositionOriginal.Y - : Math.Clamp(slider.Position.Y, area.Top, area.Bottom); + ? objectInfo.PositionOriginal.Y + : Math.Clamp(previousPosition.Y, area.Top, area.Bottom); - slider.Position = new Vector2(newX, newY); + slider.Position = objectInfo.PositionRandomised = new Vector2(newX, newY); + objectInfo.EndPositionRandomised = slider.EndPosition; - currentObjectInfo.PositionRandomised = slider.Position; - currentObjectInfo.EndPositionRandomised = slider.EndPosition; + shiftNestedObjects(slider, objectInfo.PositionRandomised - objectInfo.PositionOriginal); - shiftNestedObjects(slider, currentObjectInfo.PositionRandomised - currentObjectInfo.PositionOriginal); - - return slider.Position - prevPosition; + return objectInfo.PositionRandomised - previousPosition; } /// @@ -187,7 +183,7 @@ namespace osu.Game.Rulesets.Osu.Mods // The last object is shifted by a vector slightly larger than zero Vector2 position = hitObject.Position + shift * ((hitObjects.Count - i) / (float)(hitObjects.Count + 1)); - hitObject.Position = clampToPlayfield(position, (float)hitObject.Radius); + hitObject.Position = clampToPlayfieldWithPadding(position, (float)hitObject.Radius); } } @@ -256,12 +252,35 @@ namespace osu.Game.Rulesets.Osu.Mods } } - private Vector2 clampToPlayfield(Vector2 position, float radius) + /// + /// Move the randomised position of a hit circle so that it fits inside the playfield. + /// + /// The deviation from the original randomised position in order to fit within the playfield. + private Vector2 clampHitCircleToPlayfield(HitCircle circle, RandomObjectInfo objectInfo) { - position.X = Math.Clamp(position.X, radius, OsuPlayfield.BASE_SIZE.X - radius); - position.Y = Math.Clamp(position.Y, radius, OsuPlayfield.BASE_SIZE.Y - radius); + var previousPosition = objectInfo.PositionRandomised; + objectInfo.EndPositionRandomised = objectInfo.PositionRandomised = clampToPlayfieldWithPadding( + objectInfo.PositionRandomised, + (float)circle.Radius + ); - return position; + circle.Position = objectInfo.PositionRandomised; + + return objectInfo.PositionRandomised - previousPosition; + } + + /// + /// Clamp a position to playfield, keeping a specified distance from the edges. + /// + /// The position to be clamped. + /// The minimum distance allowed from playfield edges. + /// The clamped position. + private Vector2 clampToPlayfieldWithPadding(Vector2 position, float padding) + { + return new Vector2( + Math.Clamp(position.X, padding, OsuPlayfield.BASE_SIZE.X - padding), + Math.Clamp(position.Y, padding, OsuPlayfield.BASE_SIZE.Y - padding) + ); } private class RandomObjectInfo