mirror of
https://github.com/ppy/osu.git
synced 2025-02-21 03:43:21 +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 double ScoreMultiplier => 1;
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay) };
|
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 Vector2 CursorPosition;
|
||||||
protected DrawableHitObject WorkingHitObject;
|
protected DrawableHitObject WorkingHitObject;
|
||||||
protected virtual Vector2 DestinationVector => WorkingHitObject.Position;
|
protected abstract Vector2 DestinationVector { get; }
|
||||||
|
|
||||||
private IFrameStableClock gameplayClock;
|
private IFrameStableClock gameplayClock;
|
||||||
|
|
||||||
@ -47,27 +47,27 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
switch (drawable)
|
switch (drawable)
|
||||||
{
|
{
|
||||||
case DrawableHitCircle circle:
|
case DrawableHitCircle circle:
|
||||||
EaseHitObjectPositionToVector(circle, DestinationVector);
|
easeHitObjectPositionToVector(circle, DestinationVector);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DrawableSlider slider:
|
case DrawableSlider slider:
|
||||||
|
|
||||||
if (!slider.HeadCircle.Result.HasResult)
|
if (!slider.HeadCircle.Result.HasResult)
|
||||||
EaseHitObjectPositionToVector(slider, DestinationVector);
|
easeHitObjectPositionToVector(slider, DestinationVector);
|
||||||
else
|
else
|
||||||
EaseHitObjectPositionToVector(slider, DestinationVector - slider.Ball.DrawPosition);
|
easeHitObjectPositionToVector(slider, DestinationVector - slider.Ball.DrawPosition);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void EaseHitObjectPositionToVector(DrawableHitObject hitObject, Vector2 destination)
|
private void easeHitObjectPositionToVector(DrawableHitObject hitObject, Vector2 destination)
|
||||||
{
|
{
|
||||||
double dampLength = Interpolation.Lerp(3000, 40, EasementStrength.Value);
|
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 x = (float)Interpolation.DampContinuously(hitObject.X, destination.X, dampLength, gameplayClock.ElapsedFrameTime);
|
||||||
float y = (float)Interpolation.DampContinuously(hitObject.Y, Math.Clamp(destination.Y, 0, OsuPlayfield.BASE_SIZE.Y), dampLength, gameplayClock.ElapsedFrameTime);
|
float y = (float)Interpolation.DampContinuously(hitObject.Y, destination.Y, dampLength, gameplayClock.ElapsedFrameTime);
|
||||||
|
|
||||||
hitObject.Position = new Vector2(x, y);
|
hitObject.Position = new Vector2(x, y);
|
||||||
}
|
}
|
||||||
|
@ -21,16 +21,11 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
protected override Vector2 DestinationVector => CursorPosition;
|
protected override Vector2 DestinationVector => CursorPosition;
|
||||||
|
|
||||||
[SettingSource("Attraction strength", "How strong the pull is.", 0)]
|
[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,
|
Precision = 0.05f,
|
||||||
MinValue = 0.05f,
|
MinValue = 0.05f,
|
||||||
MaxValue = 1.0f,
|
MaxValue = 1.0f,
|
||||||
};
|
};
|
||||||
|
|
||||||
public OsuModMagnetised()
|
|
||||||
{
|
|
||||||
EasementStrength.BindTo(AttractionStrength);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,9 @@ using System.Linq;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Rulesets.Osu.Utils;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Mods
|
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();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModMagnetised)).ToArray();
|
||||||
|
|
||||||
[SettingSource("Repulsion strength", "How strong the repulsion is.", 0)]
|
[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,
|
Precision = 0.05f,
|
||||||
MinValue = 0.05f,
|
MinValue = 0.05f,
|
||||||
MaxValue = 1.0f,
|
MaxValue = 1.0f,
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override Vector2 DestinationVector => new Vector2(
|
protected override Vector2 DestinationVector
|
||||||
2 * WorkingHitObject.X - CursorPosition.X,
|
|
||||||
2 * WorkingHitObject.Y - CursorPosition.Y
|
|
||||||
);
|
|
||||||
|
|
||||||
public OsuModRepel()
|
|
||||||
{
|
{
|
||||||
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)
|
private static Vector2 clampSliderToPlayfield(WorkingObject workingObject)
|
||||||
{
|
{
|
||||||
var slider = (Slider)workingObject.HitObject;
|
var slider = (Slider)workingObject.HitObject;
|
||||||
var possibleMovementBounds = calculatePossibleMovementBounds(slider);
|
var possibleMovementBounds = CalculatePossibleMovementBounds(slider);
|
||||||
|
|
||||||
var previousPosition = workingObject.PositionModified;
|
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)
|
/// 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.
|
/// such that the entire slider is inside the playfield.
|
||||||
/// </summary>
|
/// </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>
|
/// <remarks>
|
||||||
/// If the slider is larger than the playfield, the returned <see cref="RectangleF"/> may have negative width/height.
|
/// If the slider is larger than the playfield, the returned <see cref="RectangleF"/> may have negative width/height.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private static RectangleF calculatePossibleMovementBounds(Slider slider)
|
public static RectangleF CalculatePossibleMovementBounds(Slider slider, bool accountForFollowCircleRadius = true)
|
||||||
{
|
{
|
||||||
var pathPositions = new List<Vector2>();
|
var pathPositions = new List<Vector2>();
|
||||||
slider.Path.GetPathToProgress(pathPositions, 0, 1);
|
slider.Path.GetPathToProgress(pathPositions, 0, 1);
|
||||||
@ -236,14 +239,17 @@ namespace osu.Game.Rulesets.Osu.Utils
|
|||||||
maxY = MathF.Max(maxY, pos.Y);
|
maxY = MathF.Max(maxY, pos.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take the circle radius into account.
|
if (accountForFollowCircleRadius)
|
||||||
float radius = (float)slider.Radius;
|
{
|
||||||
|
// Take the circle radius into account.
|
||||||
|
float radius = (float)slider.Radius;
|
||||||
|
|
||||||
minX -= radius;
|
minX -= radius;
|
||||||
minY -= radius;
|
minY -= radius;
|
||||||
|
|
||||||
maxX += radius;
|
maxX += radius;
|
||||||
maxY += radius;
|
maxY += radius;
|
||||||
|
}
|
||||||
|
|
||||||
// Given the bounding box of the slider (via min/max X/Y),
|
// 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),
|
// 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