Initial game-wide update with the new SliderPath

This commit is contained in:
smoogipoo
2019-12-05 19:53:31 +09:00
parent c9a66c0d07
commit 3ebbf62b2a
16 changed files with 97 additions and 111 deletions

View File

@ -196,7 +196,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{ {
AddStep($"move mouse to control point {index}", () => AddStep($"move mouse to control point {index}", () =>
{ {
Vector2 position = slider.Position + slider.Path.ControlPoints[index]; Vector2 position = slider.Position + slider.Path.ControlPoints[index].Position.Value;
InputManager.MoveMouseTo(drawableObject.Parent.ToScreenSpace(position)); InputManager.MoveMouseTo(drawableObject.Parent.ToScreenSpace(position));
}); });
} }

View File

@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{ {
base.Update(); base.Update();
Position = slider.StackedPosition + slider.Path.ControlPoints[Index]; Position = slider.StackedPosition + slider.Path.ControlPoints[Index].Position.Value;
updateMarkerDisplay(); updateMarkerDisplay();
updateConnectingPath(); updateConnectingPath();
@ -116,10 +116,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{ {
path.ClearVertices(); path.ClearVertices();
if (Index != slider.Path.ControlPoints.Length - 1) if (Index != slider.Path.ControlPoints.Count - 1)
{ {
path.AddVertex(Vector2.Zero); path.AddVertex(Vector2.Zero);
path.AddVertex(slider.Path.ControlPoints[Index + 1] - slider.Path.ControlPoints[Index]); path.AddVertex(slider.Path.ControlPoints[Index + 1].Position.Value - slider.Path.ControlPoints[Index].Position.Value);
} }
path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero);
@ -156,8 +156,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
protected override bool OnDrag(DragEvent e) protected override bool OnDrag(DragEvent e)
{ {
var newControlPoints = slider.Path.ControlPoints.ToArray();
if (Index == 0) if (Index == 0)
{ {
// Special handling for the head control point - the position of the slider changes which means the snapped position and time have to be taken into account // Special handling for the head control point - the position of the slider changes which means the snapped position and time have to be taken into account
@ -168,29 +166,17 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
slider.StartTime = snappedTime; slider.StartTime = snappedTime;
// Since control points are relative to the position of the slider, they all need to be offset backwards by the delta // Since control points are relative to the position of the slider, they all need to be offset backwards by the delta
for (int i = 1; i < newControlPoints.Length; i++) for (int i = 1; i < slider.Path.ControlPoints.Count; i++)
newControlPoints[i] -= movementDelta; slider.Path.ControlPoints[i].Position.Value -= movementDelta;
} }
else else
newControlPoints[Index] += e.Delta; slider.Path.ControlPoints[Index].Position.Value += e.Delta;
if (isSegmentSeparatorWithNext)
newControlPoints[Index + 1] = newControlPoints[Index];
if (isSegmentSeparatorWithPrevious)
newControlPoints[Index - 1] = newControlPoints[Index];
ControlPointsChanged?.Invoke(newControlPoints);
return true; return true;
} }
protected override bool OnDragEnd(DragEndEvent e) => true; protected override bool OnDragEnd(DragEndEvent e) => true;
private bool isSegmentSeparator => isSegmentSeparatorWithNext || isSegmentSeparatorWithPrevious; private bool isSegmentSeparator => slider.Path.ControlPoints[Index].Type.Value.HasValue;
private bool isSegmentSeparatorWithNext => Index < slider.Path.ControlPoints.Length - 1 && slider.Path.ControlPoints[Index + 1] == slider.Path.ControlPoints[Index];
private bool isSegmentSeparatorWithPrevious => Index > 0 && slider.Path.ControlPoints[Index - 1] == slider.Path.ControlPoints[Index];
} }
} }

View File

@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{ {
base.Update(); base.Update();
while (slider.Path.ControlPoints.Length > Pieces.Count) while (slider.Path.ControlPoints.Count > Pieces.Count)
{ {
var piece = new PathControlPointPiece(slider, Pieces.Count) var piece = new PathControlPointPiece(slider, Pieces.Count)
{ {
@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
Pieces.Add(piece); Pieces.Add(piece);
} }
while (slider.Path.ControlPoints.Length < Pieces.Count) while (slider.Path.ControlPoints.Count < Pieces.Count)
Pieces.Remove(Pieces[Pieces.Count - 1]); Pieces.Remove(Pieces[Pieces.Count - 1]);
} }
@ -105,29 +105,32 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
private bool deleteSelected() private bool deleteSelected()
{ {
var newControlPoints = new List<Vector2>(); int countDeleted = 0;
foreach (var piece in Pieces) foreach (var piece in Pieces)
{ {
if (!piece.IsSelected.Value) if (piece.IsSelected.Value)
newControlPoints.Add(slider.Path.ControlPoints[piece.Index]); {
slider.Path.ControlPoints.RemoveAt(piece.Index);
countDeleted++;
}
} }
// Ensure that there are any points to be deleted // Ensure that there are any points to be deleted
if (newControlPoints.Count == slider.Path.ControlPoints.Length) if (countDeleted == 0)
return false; return false;
// If there are 0 remaining control points, treat the slider as being deleted // If there are 0 remaining control points, treat the slider as being deleted
if (newControlPoints.Count == 0) if (slider.Path.ControlPoints.Count == 0)
{ {
placementHandler?.Delete(slider); placementHandler?.Delete(slider);
return true; return true;
} }
// Make control points relative // Make control points relative
Vector2 first = newControlPoints[0]; Vector2 first = slider.Path.ControlPoints[0].Position.Value;
for (int i = 0; i < newControlPoints.Count; i++) for (int i = 0; i < slider.Path.ControlPoints.Count; i++)
newControlPoints[i] = newControlPoints[i] - first; slider.Path.ControlPoints[i].Position.Value = slider.Path.ControlPoints[i].Position.Value - first;
// The slider's position defines the position of the first control point, and all further control points are relative to that point // The slider's position defines the position of the first control point, and all further control points are relative to that point
slider.Position += first; slider.Position += first;
@ -136,7 +139,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
foreach (var piece in Pieces) foreach (var piece in Pieces)
piece.IsSelected.Value = false; piece.IsSelected.Value = false;
ControlPointsChanged?.Invoke(newControlPoints.ToArray());
return true; return true;
} }

View File

@ -27,8 +27,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
private HitCirclePiece headCirclePiece; private HitCirclePiece headCirclePiece;
private HitCirclePiece tailCirclePiece; private HitCirclePiece tailCirclePiece;
private readonly List<Segment> segments = new List<Segment>();
private Vector2 cursor;
private InputManager inputManager; private InputManager inputManager;
private PlacementState state; private PlacementState state;
@ -40,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
: base(new Objects.Slider()) : base(new Objects.Slider())
{ {
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
segments.Add(new Segment(Vector2.Zero)); HitObject.Path.ControlPoints.Add(new PathControlPoint { Position = { Value = Vector2.Zero } });
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -74,7 +72,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
case PlacementState.Body: case PlacementState.Body:
// The given screen-space position may have been externally snapped, but the unsnapped position from the input manager // The given screen-space position may have been externally snapped, but the unsnapped position from the input manager
// is used instead since snapping control points doesn't make much sense // is used instead since snapping control points doesn't make much sense
cursor = ToLocalSpace(inputManager.CurrentState.Mouse.Position) - HitObject.Position; HitObject.Path.ControlPoints[HitObject.Path.ControlPoints.Count - 1].Position.Value = ToLocalSpace(inputManager.CurrentState.Mouse.Position) - HitObject.Position;
break; break;
} }
} }
@ -91,7 +89,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
switch (e.Button) switch (e.Button)
{ {
case MouseButton.Left: case MouseButton.Left:
segments.Last().ControlPoints.Add(cursor); HitObject.Path.ControlPoints.Add(new PathControlPoint { Position = { Value = HitObject.Path.ControlPoints[HitObject.Path.ControlPoints.Count - 1].Position.Value } });
break; break;
} }
@ -110,7 +108,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
protected override bool OnDoubleClick(DoubleClickEvent e) protected override bool OnDoubleClick(DoubleClickEvent e)
{ {
segments.Add(new Segment(segments[segments.Count - 1].ControlPoints.Last())); HitObject.Path.ControlPoints[HitObject.Path.ControlPoints.Count - 2].Type.Value = PathType.Bezier;
return true; return true;
} }
@ -134,12 +132,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
private void updateSlider() private void updateSlider()
{ {
Vector2[] newControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToArray(); HitObject.Path.ExpectedDistance.Value = null;
HitObject.Path.ExpectedDistance.Value = composer?.GetSnappedDistanceFromDistance(HitObject.StartTime, (float)HitObject.Path.Distance) ?? (float)HitObject.Path.Distance;
var unsnappedPath = new SliderPath(newControlPoints.Length > 2 ? PathType.Bezier : PathType.Linear, newControlPoints);
var snappedDistance = composer?.GetSnappedDistanceFromDistance(HitObject.StartTime, (float)unsnappedPath.Distance) ?? (float)unsnappedPath.Distance;
HitObject.Path = new SliderPath(unsnappedPath.Type, newControlPoints, snappedDistance);
bodyPiece.UpdateFrom(HitObject); bodyPiece.UpdateFrom(HitObject);
headCirclePiece.UpdateFrom(HitObject.HeadCircle); headCirclePiece.UpdateFrom(HitObject.HeadCircle);

View File

@ -77,12 +77,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
{ {
Debug.Assert(placementControlPointIndex != null); Debug.Assert(placementControlPointIndex != null);
Vector2 position = e.MousePosition - HitObject.Position; HitObject.Path.ControlPoints[placementControlPointIndex.Value].Position.Value = e.MousePosition - HitObject.Position;
var controlPoints = HitObject.Path.ControlPoints.ToArray();
controlPoints[placementControlPointIndex.Value] = position;
onNewControlPoints(controlPoints);
return true; return true;
} }
@ -97,15 +92,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
{ {
position -= HitObject.Position; position -= HitObject.Position;
var controlPoints = new Vector2[HitObject.Path.ControlPoints.Length + 1];
HitObject.Path.ControlPoints.CopyTo(controlPoints);
int insertionIndex = 0; int insertionIndex = 0;
float minDistance = float.MaxValue; float minDistance = float.MaxValue;
for (int i = 0; i < controlPoints.Length - 2; i++) for (int i = 0; i < HitObject.Path.ControlPoints.Count - 2; i++)
{ {
float dist = new Line(controlPoints[i], controlPoints[i + 1]).DistanceToPoint(position); float dist = new Line(HitObject.Path.ControlPoints[i].Position.Value, HitObject.Path.ControlPoints[i + 1].Position.Value).DistanceToPoint(position);
if (dist < minDistance) if (dist < minDistance)
{ {
@ -115,20 +107,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
} }
// Move the control points from the insertion index onwards to make room for the insertion // Move the control points from the insertion index onwards to make room for the insertion
Array.Copy(controlPoints, insertionIndex, controlPoints, insertionIndex + 1, controlPoints.Length - insertionIndex - 1); HitObject.Path.ControlPoints.Insert(insertionIndex, new PathControlPoint { Position = { Value = position } });
controlPoints[insertionIndex] = position;
onNewControlPoints(controlPoints);
return insertionIndex; return insertionIndex;
} }
private void onNewControlPoints(Vector2[] controlPoints) private void onNewControlPoints(Vector2[] controlPoints)
{ {
var unsnappedPath = new SliderPath(controlPoints.Length > 2 ? PathType.Bezier : PathType.Linear, controlPoints); HitObject.Path.ExpectedDistance.Value = null;
var snappedDistance = composer?.GetSnappedDistanceFromDistance(HitObject.StartTime, (float)unsnappedPath.Distance) ?? (float)unsnappedPath.Distance; HitObject.Path.ExpectedDistance.Value = composer?.GetSnappedDistanceFromDistance(HitObject.StartTime, (float)HitObject.Path.Distance) ?? (float)HitObject.Path.Distance;
HitObject.Path = new SliderPath(unsnappedPath.Type, controlPoints, snappedDistance);
UpdateHitObject(); UpdateHitObject();
} }

View File

@ -28,11 +28,8 @@ namespace osu.Game.Rulesets.Osu.Mods
slider.NestedHitObjects.OfType<SliderTick>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); slider.NestedHitObjects.OfType<SliderTick>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
slider.NestedHitObjects.OfType<RepeatPoint>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); slider.NestedHitObjects.OfType<RepeatPoint>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
var newControlPoints = new Vector2[slider.Path.ControlPoints.Length]; foreach (var point in slider.Path.ControlPoints)
for (int i = 0; i < slider.Path.ControlPoints.Length; i++) point.Position.Value = new Vector2(point.Position.Value.X, -point.Position.Value.Y);
newControlPoints[i] = new Vector2(slider.Path.ControlPoints[i].X, -slider.Path.ControlPoints[i].Y);
slider.Path = new SliderPath(slider.Path.Type, newControlPoints, slider.Path.ExpectedDistance);
} }
} }
} }

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>(); private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
private readonly IBindable<int> stackHeightBindable = new Bindable<int>(); private readonly IBindable<int> stackHeightBindable = new Bindable<int>();
private readonly IBindable<float> scaleBindable = new Bindable<float>(); private readonly IBindable<float> scaleBindable = new Bindable<float>();
private readonly IBindable<SliderPath> pathBindable = new Bindable<SliderPath>(); private readonly IBindable<int> pathVersion = new Bindable<int>();
[Resolved(CanBeNull = true)] [Resolved(CanBeNull = true)]
private OsuRulesetConfigManager config { get; set; } private OsuRulesetConfigManager config { get; set; }
@ -84,9 +84,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
positionBindable.BindTo(HitObject.PositionBindable); positionBindable.BindTo(HitObject.PositionBindable);
stackHeightBindable.BindTo(HitObject.StackHeightBindable); stackHeightBindable.BindTo(HitObject.StackHeightBindable);
scaleBindable.BindTo(HitObject.ScaleBindable); scaleBindable.BindTo(HitObject.ScaleBindable);
pathBindable.BindTo(slider.PathBindable); pathVersion.BindTo(slider.Path.Version);
pathBindable.BindValueChanged(_ => Body.Refresh()); pathVersion.BindValueChanged(_ => Body.Refresh());
AccentColour.BindValueChanged(colour => AccentColour.BindValueChanged(colour =>
{ {

View File

@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public class DrawableSliderHead : DrawableHitCircle public class DrawableSliderHead : DrawableHitCircle
{ {
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>(); private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
private readonly IBindable<SliderPath> pathBindable = new Bindable<SliderPath>(); private readonly IBindable<int> pathVersion = new Bindable<int>();
private readonly Slider slider; private readonly Slider slider;
@ -27,10 +27,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private void load() private void load()
{ {
positionBindable.BindTo(HitObject.PositionBindable); positionBindable.BindTo(HitObject.PositionBindable);
pathBindable.BindTo(slider.PathBindable); pathVersion.BindTo(slider.Path.Version);
positionBindable.BindValueChanged(_ => updatePosition()); positionBindable.BindValueChanged(_ => updatePosition());
pathBindable.BindValueChanged(_ => updatePosition(), true); pathVersion.BindValueChanged(_ => updatePosition(), true);
} }
protected override void Update() protected override void Update()

View File

@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public bool Tracking { get; set; } public bool Tracking { get; set; }
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>(); private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
private readonly IBindable<SliderPath> pathBindable = new Bindable<SliderPath>(); private readonly IBindable<int> pathVersion = new Bindable<int>();
public DrawableSliderTail(Slider slider, SliderTailCircle hitCircle) public DrawableSliderTail(Slider slider, SliderTailCircle hitCircle)
: base(hitCircle) : base(hitCircle)
@ -36,10 +36,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
AlwaysPresent = true; AlwaysPresent = true;
positionBindable.BindTo(hitCircle.PositionBindable); positionBindable.BindTo(hitCircle.PositionBindable);
pathBindable.BindTo(slider.PathBindable); pathVersion.BindTo(slider.Path.Version);
positionBindable.BindValueChanged(_ => updatePosition()); positionBindable.BindValueChanged(_ => updatePosition());
pathBindable.BindValueChanged(_ => updatePosition(), true); pathVersion.BindValueChanged(_ => updatePosition(), true);
// TODO: This has no drawable content. Support for skins should be added. // TODO: This has no drawable content. Support for skins should be added.
} }

View File

@ -28,19 +28,7 @@ namespace osu.Game.Rulesets.Osu.Objects
public Vector2 StackedPositionAt(double t) => StackedPosition + this.CurvePositionAt(t); public Vector2 StackedPositionAt(double t) => StackedPosition + this.CurvePositionAt(t);
public readonly Bindable<SliderPath> PathBindable = new Bindable<SliderPath>(); public SliderPath Path { get; set; } = new SliderPath(new[] { new PathControlPoint { Type = { Value = PathType.Bezier } } });
public SliderPath Path
{
get => PathBindable.Value;
set
{
PathBindable.Value = value;
endPositionCache.Invalidate();
updateNestedPositions();
}
}
public double Distance => Path.Distance; public double Distance => Path.Distance;

View File

@ -15,12 +15,12 @@ namespace osu.Game.Rulesets.Osu.Objects
/// </summary> /// </summary>
public class SliderTailCircle : SliderCircle public class SliderTailCircle : SliderCircle
{ {
private readonly IBindable<SliderPath> pathBindable = new Bindable<SliderPath>(); private readonly IBindable<int> pathVersion = new Bindable<int>();
public SliderTailCircle(Slider slider) public SliderTailCircle(Slider slider)
{ {
pathBindable.BindTo(slider.PathBindable); pathVersion.BindTo(slider.Path.Version);
pathBindable.BindValueChanged(_ => Position = slider.EndPosition); pathVersion.BindValueChanged(_ => Position = slider.EndPosition);
} }
public override Judgement CreateJudgement() => new OsuSliderTailJudgement(); public override Judgement CreateJudgement() => new OsuSliderTailJudgement();

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
}; };
} }
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount, protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
List<IList<HitSampleInfo>> nodeSamples) List<IList<HitSampleInfo>> nodeSamples)
{ {
newCombo |= forceNewCombo; newCombo |= forceNewCombo;
@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
X = position.X, X = position.X,
NewCombo = FirstObject || newCombo, NewCombo = FirstObject || newCombo,
ComboOffset = comboOffset, ComboOffset = comboOffset,
Path = new SliderPath(pathType, controlPoints, length), Path = new SliderPath(controlPoints, length),
NodeSamples = nodeSamples, NodeSamples = nodeSamples,
RepeatCount = repeatCount RepeatCount = repeatCount
}; };

View File

@ -115,12 +115,6 @@ namespace osu.Game.Rulesets.Objects.Legacy
points[pointIndex++] = new Vector2((int)Parsing.ParseDouble(temp[0], Parsing.MAX_COORDINATE_VALUE), (int)Parsing.ParseDouble(temp[1], Parsing.MAX_COORDINATE_VALUE)) - pos; points[pointIndex++] = new Vector2((int)Parsing.ParseDouble(temp[0], Parsing.MAX_COORDINATE_VALUE), (int)Parsing.ParseDouble(temp[1], Parsing.MAX_COORDINATE_VALUE)) - pos;
} }
// osu-stable special-cased colinear perfect curves to a CurveType.Linear
static bool isLinear(Vector2[] p) => Precision.AlmostEquals(0, (p[1].Y - p[0].Y) * (p[2].X - p[0].X) - (p[1].X - p[0].X) * (p[2].Y - p[0].Y));
if (points.Length == 3 && pathType == PathType.PerfectCurve && isLinear(points))
pathType = PathType.Linear;
int repeatCount = Parsing.ParseInt(split[6]); int repeatCount = Parsing.ParseInt(split[6]);
if (repeatCount > 9000) if (repeatCount > 9000)
@ -187,7 +181,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
for (int i = 0; i < nodes; i++) for (int i = 0; i < nodes; i++)
nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i])); nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i]));
result = CreateSlider(pos, combo, comboOffset, points, length, pathType, repeatCount, nodeSamples); result = CreateSlider(pos, combo, comboOffset, convertControlPoints(points, pathType), length, repeatCount, nodeSamples);
// The samples are played when the slider ends, which is the last node // The samples are played when the slider ends, which is the last node
result.Samples = nodeSamples[nodeSamples.Count - 1]; result.Samples = nodeSamples[nodeSamples.Count - 1];
@ -259,6 +253,45 @@ namespace osu.Game.Rulesets.Objects.Legacy
bankInfo.Filename = split.Length > 4 ? split[4] : null; bankInfo.Filename = split.Length > 4 ? split[4] : null;
} }
private PathControlPoint[] convertControlPoints(Vector2[] vertices, PathType type)
{
if (type == PathType.PerfectCurve)
{
if (vertices.Length == 3)
{
// osu-stable special-cased colinear perfect curves to a linear path
if (isLinear(vertices))
type = PathType.Linear;
}
else
type = PathType.Bezier;
}
var points = new List<PathControlPoint>(vertices.Length)
{
new PathControlPoint
{
Position = { Value = vertices[0] },
Type = { Value = type }
}
};
for (int i = 1; i < vertices.Length; i++)
{
if (vertices[i] == vertices[i - 1])
{
points[points.Count - 1].Type.Value = type;
continue;
}
points.Add(new PathControlPoint { Position = { Value = vertices[i] } });
}
return points.ToArray();
static bool isLinear(Vector2[] p) => Precision.AlmostEquals(0, (p[1].Y - p[0].Y) * (p[2].X - p[0].X) - (p[1].X - p[0].X) * (p[2].Y - p[0].Y));
}
/// <summary> /// <summary>
/// Creates a legacy Hit-type hit object. /// Creates a legacy Hit-type hit object.
/// </summary> /// </summary>
@ -276,11 +309,10 @@ namespace osu.Game.Rulesets.Objects.Legacy
/// <param name="comboOffset">When starting a new combo, the offset of the new combo relative to the current one.</param> /// <param name="comboOffset">When starting a new combo, the offset of the new combo relative to the current one.</param>
/// <param name="controlPoints">The slider control points.</param> /// <param name="controlPoints">The slider control points.</param>
/// <param name="length">The slider length.</param> /// <param name="length">The slider length.</param>
/// <param name="pathType">The slider curve type.</param>
/// <param name="repeatCount">The slider repeat count.</param> /// <param name="repeatCount">The slider repeat count.</param>
/// <param name="nodeSamples">The samples to be played when the slider nodes are hit. This includes the head and tail of the slider.</param> /// <param name="nodeSamples">The samples to be played when the slider nodes are hit. This includes the head and tail of the slider.</param>
/// <returns>The hit object.</returns> /// <returns>The hit object.</returns>
protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount, protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
List<IList<HitSampleInfo>> nodeSamples); List<IList<HitSampleInfo>> nodeSamples);
/// <summary> /// <summary>

View File

@ -26,13 +26,13 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
}; };
} }
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount, protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
List<IList<HitSampleInfo>> nodeSamples) List<IList<HitSampleInfo>> nodeSamples)
{ {
return new ConvertSlider return new ConvertSlider
{ {
X = position.X, X = position.X,
Path = new SliderPath(pathType, controlPoints, length), Path = new SliderPath(controlPoints, length),
NodeSamples = nodeSamples, NodeSamples = nodeSamples,
RepeatCount = repeatCount RepeatCount = repeatCount
}; };

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
}; };
} }
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount, protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
List<IList<HitSampleInfo>> nodeSamples) List<IList<HitSampleInfo>> nodeSamples)
{ {
newCombo |= forceNewCombo; newCombo |= forceNewCombo;
@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
Position = position, Position = position,
NewCombo = FirstObject || newCombo, NewCombo = FirstObject || newCombo,
ComboOffset = comboOffset, ComboOffset = comboOffset,
Path = new SliderPath(pathType, controlPoints, length), Path = new SliderPath(controlPoints, length),
NodeSamples = nodeSamples, NodeSamples = nodeSamples,
RepeatCount = repeatCount RepeatCount = repeatCount
}; };

View File

@ -23,12 +23,12 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
return new ConvertHit(); return new ConvertHit();
} }
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount, protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
List<IList<HitSampleInfo>> nodeSamples) List<IList<HitSampleInfo>> nodeSamples)
{ {
return new ConvertSlider return new ConvertSlider
{ {
Path = new SliderPath(pathType, controlPoints, length), Path = new SliderPath(controlPoints, length),
NodeSamples = nodeSamples, NodeSamples = nodeSamples,
RepeatCount = repeatCount RepeatCount = repeatCount
}; };