diff --git a/osu.Game.Rulesets.Osu/Mods/OsuEaseHitObjectPositionsMod.cs b/osu.Game.Rulesets.Osu/Mods/OsuEaseHitObjectPositionsMod.cs
index 2c344b7a68..74391e53a2 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuEaseHitObjectPositionsMod.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuEaseHitObjectPositionsMod.cs
@@ -20,10 +20,10 @@ namespace osu.Game.Rulesets.Osu.Mods
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay) };
- protected BindableFloat EasementStrength = new BindableFloat(0.5f);
+ public abstract BindableFloat EasementStrength { get; }
protected Vector2 CursorPosition;
protected DrawableHitObject WorkingHitObject;
- protected virtual Vector2 DestinationVector => WorkingHitObject.Position;
+ protected abstract Vector2 DestinationVector { get; }
private IFrameStableClock gameplayClock;
@@ -47,27 +47,27 @@ namespace osu.Game.Rulesets.Osu.Mods
switch (drawable)
{
case DrawableHitCircle circle:
- EaseHitObjectPositionToVector(circle, DestinationVector);
+ easeHitObjectPositionToVector(circle, DestinationVector);
break;
case DrawableSlider slider:
if (!slider.HeadCircle.Result.HasResult)
- EaseHitObjectPositionToVector(slider, DestinationVector);
+ easeHitObjectPositionToVector(slider, DestinationVector);
else
- EaseHitObjectPositionToVector(slider, DestinationVector - slider.Ball.DrawPosition);
+ easeHitObjectPositionToVector(slider, DestinationVector - slider.Ball.DrawPosition);
break;
}
}
}
- protected void EaseHitObjectPositionToVector(DrawableHitObject hitObject, Vector2 destination)
+ private void easeHitObjectPositionToVector(DrawableHitObject hitObject, Vector2 destination)
{
double dampLength = Interpolation.Lerp(3000, 40, EasementStrength.Value);
- float x = (float)Interpolation.DampContinuously(hitObject.X, Math.Clamp(destination.X, 0, OsuPlayfield.BASE_SIZE.X), dampLength, gameplayClock.ElapsedFrameTime);
- float y = (float)Interpolation.DampContinuously(hitObject.Y, Math.Clamp(destination.Y, 0, OsuPlayfield.BASE_SIZE.Y), dampLength, gameplayClock.ElapsedFrameTime);
+ float x = (float)Interpolation.DampContinuously(hitObject.X, destination.X, dampLength, gameplayClock.ElapsedFrameTime);
+ float y = (float)Interpolation.DampContinuously(hitObject.Y, destination.Y, dampLength, gameplayClock.ElapsedFrameTime);
hitObject.Position = new Vector2(x, y);
}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs
index ca69085e31..1c10d61c99 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs
@@ -21,16 +21,11 @@ namespace osu.Game.Rulesets.Osu.Mods
protected override Vector2 DestinationVector => CursorPosition;
[SettingSource("Attraction strength", "How strong the pull is.", 0)]
- public BindableFloat AttractionStrength { get; } = new BindableFloat(0.5f)
+ public override BindableFloat EasementStrength { get; } = new BindableFloat(0.5f)
{
Precision = 0.05f,
MinValue = 0.05f,
MaxValue = 1.0f,
};
-
- public OsuModMagnetised()
- {
- EasementStrength.BindTo(AttractionStrength);
- }
}
}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs
index 35f369d9c5..fec66e3ef1 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs
@@ -6,6 +6,9 @@ using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Game.Configuration;
+using osu.Game.Rulesets.Osu.Utils;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Rulesets.Osu.UI;
using osuTK;
namespace osu.Game.Rulesets.Osu.Mods
@@ -19,21 +22,35 @@ namespace osu.Game.Rulesets.Osu.Mods
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModMagnetised)).ToArray();
[SettingSource("Repulsion strength", "How strong the repulsion is.", 0)]
- public BindableFloat RepulsionStrength { get; } = new BindableFloat(0.5f)
+ public override BindableFloat EasementStrength { get; } = new BindableFloat(0.5f)
{
Precision = 0.05f,
MinValue = 0.05f,
MaxValue = 1.0f,
};
- protected override Vector2 DestinationVector => new Vector2(
- 2 * WorkingHitObject.X - CursorPosition.X,
- 2 * WorkingHitObject.Y - CursorPosition.Y
- );
-
- public OsuModRepel()
+ protected override Vector2 DestinationVector
{
- EasementStrength.BindTo(RepulsionStrength);
+ get
+ {
+ float x = Math.Clamp(2 * WorkingHitObject.X - CursorPosition.X, 0, OsuPlayfield.BASE_SIZE.X);
+ float y = Math.Clamp(2 * WorkingHitObject.Y - CursorPosition.Y, 0, OsuPlayfield.BASE_SIZE.Y);
+
+ if (WorkingHitObject.HitObject is Slider slider)
+ {
+ var possibleMovementBounds = OsuHitObjectGenerationUtils.CalculatePossibleMovementBounds(slider, false);
+
+ x = possibleMovementBounds.Width < 0
+ ? x
+ : Math.Clamp(x, possibleMovementBounds.Left, possibleMovementBounds.Right);
+
+ y = possibleMovementBounds.Height < 0
+ ? y
+ : Math.Clamp(y, possibleMovementBounds.Top, possibleMovementBounds.Bottom);
+ }
+
+ return new Vector2(x, y);
+ }
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils_Reposition.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils_Reposition.cs
index d1bc3b45df..765477fba2 100644
--- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils_Reposition.cs
+++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils_Reposition.cs
@@ -167,7 +167,7 @@ namespace osu.Game.Rulesets.Osu.Utils
private static Vector2 clampSliderToPlayfield(WorkingObject workingObject)
{
var slider = (Slider)workingObject.HitObject;
- var possibleMovementBounds = calculatePossibleMovementBounds(slider);
+ var possibleMovementBounds = CalculatePossibleMovementBounds(slider);
var previousPosition = workingObject.PositionModified;
@@ -212,10 +212,13 @@ namespace osu.Game.Rulesets.Osu.Utils
/// Calculates a which contains all of the possible movements of the slider (in relative X/Y coordinates)
/// such that the entire slider is inside the playfield.
///
+ /// The for which to calculate a movement bounding box.
+ /// Whether the movement bounding box should account for the slider's follow circle. Defaults to true.
+ /// A which contains all of the possible movements of the slider such that the entire slider is inside the playfield.
///
/// If the slider is larger than the playfield, the returned may have negative width/height.
///
- private static RectangleF calculatePossibleMovementBounds(Slider slider)
+ public static RectangleF CalculatePossibleMovementBounds(Slider slider, bool accountForFollowCircleRadius = true)
{
var pathPositions = new List();
slider.Path.GetPathToProgress(pathPositions, 0, 1);
@@ -236,14 +239,17 @@ namespace osu.Game.Rulesets.Osu.Utils
maxY = MathF.Max(maxY, pos.Y);
}
- // Take the circle radius into account.
- float radius = (float)slider.Radius;
+ if (accountForFollowCircleRadius)
+ {
+ // Take the circle radius into account.
+ float radius = (float)slider.Radius;
- minX -= radius;
- minY -= radius;
+ minX -= radius;
+ minY -= radius;
- maxX += radius;
- maxY += radius;
+ maxX += radius;
+ maxY += radius;
+ }
// Given the bounding box of the slider (via min/max X/Y),
// the amount that the slider can move to the left is minX (with the sign flipped, since positive X is to the right),