mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 09:27:29 +08:00
clamp sliders, expose slider bounds function
This commit is contained in:
parent
5d838628d7
commit
b7bdad4074
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 <see cref="RectangleF"/> which contains all of the possible movements of the slider (in relative X/Y coordinates)
|
||||
/// such that the entire slider is inside the playfield.
|
||||
/// </summary>
|
||||
/// <param name="slider">The <see cref="Slider"/> for which to calculate a movement bounding box.</param>
|
||||
/// <param name="accountForFollowCircleRadius">Whether the movement bounding box should account for the slider's follow circle. Defaults to true.</param>
|
||||
/// <returns>A <see cref="RectangleF"/> which contains all of the possible movements of the slider such that the entire slider is inside the playfield.</returns>
|
||||
/// <remarks>
|
||||
/// If the slider is larger than the playfield, the returned <see cref="RectangleF"/> may have negative width/height.
|
||||
/// </remarks>
|
||||
private static RectangleF calculatePossibleMovementBounds(Slider slider)
|
||||
public static RectangleF CalculatePossibleMovementBounds(Slider slider, bool accountForFollowCircleRadius = true)
|
||||
{
|
||||
var pathPositions = new List<Vector2>();
|
||||
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),
|
||||
|
Loading…
Reference in New Issue
Block a user