Implement slider control point visualisation

This commit is contained in:
smoogipoo 2018-10-29 14:07:06 +09:00
parent 9b19050faf
commit b0f5ace0e8
5 changed files with 149 additions and 2 deletions

View File

@ -1,11 +1,14 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks;
using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Tests.Visual;
@ -15,6 +18,16 @@ namespace osu.Game.Rulesets.Osu.Tests
{
public class TestCaseSliderSelectionMask : HitObjectSelectionMaskTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new Type[]
{
typeof(SliderSelectionMask),
typeof(SliderCircleSelectionMask),
typeof(SliderBodyPiece),
typeof(SliderCircle),
typeof(ControlPointVisualiser),
typeof(ControlPointPiece)
};
private readonly DrawableSlider drawableObject;
public TestCaseSliderSelectionMask()

View File

@ -0,0 +1,90 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Lines;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Rulesets.Osu.Objects;
using OpenTK;
namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components
{
public class ControlPointPiece : CompositeDrawable
{
private readonly Slider slider;
private readonly int index;
private readonly Path path;
private readonly CircularContainer marker;
[Resolved]
private OsuColour colours { get; set; }
public ControlPointPiece(Slider slider, int index)
{
this.slider = slider;
this.index = index;
Origin = Anchor.Centre;
Size = new Vector2(10);
InternalChildren = new Drawable[]
{
path = new SmoothPath
{
BypassAutoSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
PathWidth = 1
},
marker = new CircularContainer
{
RelativeSizeAxes = Axes.Both,
Masking = true,
Child = new Box { RelativeSizeAxes = Axes.Both }
}
};
}
protected override void Update()
{
base.Update();
Position = slider.StackedPosition + slider.ControlPoints[index];
marker.Colour = segmentSeparator ? colours.Red : colours.Yellow;
path.ClearVertices();
if (index != slider.ControlPoints.Length - 1)
{
path.AddVertex(Vector2.Zero);
path.AddVertex(slider.ControlPoints[index + 1] - slider.ControlPoints[index]);
}
path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero);
}
protected override bool OnDragStart(DragStartEvent e) => true;
protected override bool OnDrag(DragEvent e)
{
var newControlPoints = slider.ControlPoints.ToArray();
newControlPoints[index] += e.Delta;
slider.ControlPoints = newControlPoints;
return true;
}
protected override bool OnDragEnd(DragEndEvent e) => true;
private bool segmentSeparator => index != 0 && index != slider.ControlPoints.Length - 1
&& slider.ControlPoints[index - 1] != slider.ControlPoints[index]
&& slider.ControlPoints[index + 1] != slider.ControlPoints[index];
}
}

View File

@ -0,0 +1,34 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components
{
public class ControlPointVisualiser : CompositeDrawable
{
private readonly Slider slider;
private readonly Container<ControlPointPiece> pieces;
public ControlPointVisualiser(Slider slider)
{
this.slider = slider;
InternalChild = pieces = new Container<ControlPointPiece> { RelativeSizeAxes = Axes.Both };
slider.ControlPointsChanged += _ => updateControlPoints();
updateControlPoints();
}
private void updateControlPoints()
{
while (slider.ControlPoints.Length > pieces.Count)
pieces.Add(new ControlPointPiece(slider, pieces.Count));
while (slider.ControlPoints.Length < pieces.Count)
pieces.Remove(pieces[pieces.Count - 1]);
}
}
}

View File

@ -24,6 +24,7 @@ public SliderSelectionMask(DrawableSlider slider)
new SliderBodyPiece(sliderObject),
headMask = new SliderCircleSelectionMask(slider.HeadCircle, sliderObject, SliderPosition.Start),
new SliderCircleSelectionMask(slider.TailCircle, sliderObject, SliderPosition.End),
new ControlPointVisualiser(sliderObject),
};
}

View File

@ -22,6 +22,8 @@ public class Slider : OsuHitObject, IHasCurve
/// </summary>
private const float base_scoring_distance = 100;
public event Action<Vector2[]> ControlPointsChanged;
public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity;
public double Duration => EndTime - StartTime;
@ -54,8 +56,15 @@ public override int IndexInCurrentCombo
public Vector2[] ControlPoints
{
get { return Curve.ControlPoints; }
set { Curve.ControlPoints = value; }
get => Curve.ControlPoints;
set
{
if (Curve.ControlPoints == value)
return;
Curve.ControlPoints = value;
ControlPointsChanged?.Invoke(value);
}
}
public CurveType CurveType