1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-15 12:02:55 +08:00

Merge pull request #8737 from smoogipoo/fix-overlapping-controlpoints

Fix connections hidden due to overlapping controlpoints
This commit is contained in:
Dean Herbert 2020-04-13 20:06:24 +09:00 committed by GitHub
commit d56b6900ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 103 additions and 34 deletions

View File

@ -0,0 +1,64 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Linq;
using Humanizer;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Tests.Visual;
using osuTK;
namespace osu.Game.Rulesets.Osu.Tests
{
public class TestScenePathControlPointVisualiser : OsuTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(StringHumanizeExtensions),
typeof(PathControlPointPiece),
typeof(PathControlPointConnectionPiece)
};
private Slider slider;
private PathControlPointVisualiser visualiser;
[SetUp]
public void Setup() => Schedule(() =>
{
slider = new Slider();
slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
});
[Test]
public void TestAddOverlappingControlPoints()
{
createVisualiser(true);
addControlPointStep(new Vector2(200));
addControlPointStep(new Vector2(300));
addControlPointStep(new Vector2(300));
addControlPointStep(new Vector2(500, 300));
AddAssert("last connection displayed", () =>
{
var lastConnection = visualiser.Connections.Last(c => c.ControlPoint.Position.Value == new Vector2(300));
return lastConnection.DrawWidth > 50;
});
}
private void createVisualiser(bool allowSelection) => AddStep("create visualiser", () => Child = visualiser = new PathControlPointVisualiser(slider, allowSelection)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
});
private void addControlPointStep(Vector2 position) => AddStep($"add control point {position}", () => slider.Path.ControlPoints.Add(new PathControlPoint(position)));
}
}

View File

@ -16,22 +16,25 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
/// </summary>
public class PathControlPointConnectionPiece : CompositeDrawable
{
public PathControlPoint ControlPoint;
public readonly PathControlPoint ControlPoint;
private readonly Path path;
private readonly Slider slider;
private readonly int controlPointIndex;
private IBindable<Vector2> sliderPosition;
private IBindable<int> pathVersion;
public PathControlPointConnectionPiece(Slider slider, PathControlPoint controlPoint)
public PathControlPointConnectionPiece(Slider slider, int controlPointIndex)
{
this.slider = slider;
ControlPoint = controlPoint;
this.controlPointIndex = controlPointIndex;
Origin = Anchor.Centre;
AutoSizeAxes = Axes.Both;
ControlPoint = slider.Path.ControlPoints[controlPointIndex];
InternalChild = path = new SmoothPath
{
Anchor = Anchor.Centre,
@ -61,13 +64,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
path.ClearVertices();
int index = slider.Path.ControlPoints.IndexOf(ControlPoint) + 1;
if (index == 0 || index == slider.Path.ControlPoints.Count)
int nextIndex = controlPointIndex + 1;
if (nextIndex == 0 || nextIndex == slider.Path.ControlPoints.Count)
return;
path.AddVertex(Vector2.Zero);
path.AddVertex(slider.Path.ControlPoints[index].Position.Value - ControlPoint.Position.Value);
path.AddVertex(slider.Path.ControlPoints[nextIndex].Position.Value - ControlPoint.Position.Value);
path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero);
}

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using Humanizer;
using osu.Framework.Bindables;
@ -24,17 +25,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
public class PathControlPointVisualiser : CompositeDrawable, IKeyBindingHandler<PlatformAction>, IHasContextMenu
{
internal readonly Container<PathControlPointPiece> Pieces;
internal readonly Container<PathControlPointConnectionPiece> Connections;
private readonly Container<PathControlPointConnectionPiece> connections;
private readonly IBindableList<PathControlPoint> controlPoints = new BindableList<PathControlPoint>();
private readonly Slider slider;
private readonly bool allowSelection;
private InputManager inputManager;
private IBindableList<PathControlPoint> controlPoints;
public Action<List<PathControlPoint>> RemoveControlPointsRequested;
public PathControlPointVisualiser(Slider slider, bool allowSelection)
@ -46,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
InternalChildren = new Drawable[]
{
connections = new Container<PathControlPointConnectionPiece> { RelativeSizeAxes = Axes.Both },
Connections = new Container<PathControlPointConnectionPiece> { RelativeSizeAxes = Axes.Both },
Pieces = new Container<PathControlPointPiece> { RelativeSizeAxes = Axes.Both }
};
}
@ -57,33 +55,38 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
inputManager = GetContainingInputManager();
controlPoints = slider.Path.ControlPoints.GetBoundCopy();
controlPoints.ItemsAdded += addControlPoints;
controlPoints.ItemsRemoved += removeControlPoints;
addControlPoints(controlPoints);
controlPoints.CollectionChanged += onControlPointsChanged;
controlPoints.BindTo(slider.Path.ControlPoints);
}
private void addControlPoints(IEnumerable<PathControlPoint> controlPoints)
private void onControlPointsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
foreach (var point in controlPoints)
switch (e.Action)
{
Pieces.Add(new PathControlPointPiece(slider, point).With(d =>
{
if (allowSelection)
d.RequestSelection = selectPiece;
}));
case NotifyCollectionChangedAction.Add:
for (int i = 0; i < e.NewItems.Count; i++)
{
var point = (PathControlPoint)e.NewItems[i];
connections.Add(new PathControlPointConnectionPiece(slider, point));
}
}
Pieces.Add(new PathControlPointPiece(slider, point).With(d =>
{
if (allowSelection)
d.RequestSelection = selectPiece;
}));
private void removeControlPoints(IEnumerable<PathControlPoint> controlPoints)
{
foreach (var point in controlPoints)
{
Pieces.RemoveAll(p => p.ControlPoint == point);
connections.RemoveAll(c => c.ControlPoint == point);
Connections.Add(new PathControlPointConnectionPiece(slider, e.NewStartingIndex + i));
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (var point in e.OldItems.Cast<PathControlPoint>())
{
Pieces.RemoveAll(p => p.ControlPoint == point);
Connections.RemoveAll(c => c.ControlPoint == point);
}
break;
}
}