1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-26 16:12:54 +08:00

Merge branch 'master' into fix-ignored-test

This commit is contained in:
Dan Balasescu 2019-10-09 11:39:40 +09:00 committed by GitHub
commit e8276dc562
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 277 additions and 236 deletions

View File

@ -6,7 +6,6 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.Edit.Blueprints;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
@ -39,6 +38,8 @@ namespace osu.Game.Rulesets.Mania.Tests
AccentColour = { Value = OsuColour.Gray(0.3f) } AccentColour = { Value = OsuColour.Gray(0.3f) }
} }
}; };
AddBlueprint(new HoldNoteSelectionBlueprint(drawableObject));
} }
protected override void Update() protected override void Update()
@ -51,7 +52,5 @@ namespace osu.Game.Rulesets.Mania.Tests
nested.Y = (float)(-finalPosition * content.DrawHeight); nested.Y = (float)(-finalPosition * content.DrawHeight);
} }
} }
protected override SelectionBlueprint CreateBlueprint() => new HoldNoteSelectionBlueprint(drawableObject);
} }
} }

View File

@ -5,7 +5,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.Edit.Blueprints;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
@ -17,8 +16,6 @@ namespace osu.Game.Rulesets.Mania.Tests
{ {
public class TestSceneNoteSelectionBlueprint : ManiaSelectionBlueprintTestScene public class TestSceneNoteSelectionBlueprint : ManiaSelectionBlueprintTestScene
{ {
private readonly DrawableNote drawableObject;
protected override Container<Drawable> Content => content ?? base.Content; protected override Container<Drawable> Content => content ?? base.Content;
private readonly Container content; private readonly Container content;
@ -27,6 +24,8 @@ namespace osu.Game.Rulesets.Mania.Tests
var note = new Note { Column = 0 }; var note = new Note { Column = 0 };
note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
DrawableNote drawableObject;
base.Content.Child = content = new ScrollingTestContainer(ScrollingDirection.Down) base.Content.Child = content = new ScrollingTestContainer(ScrollingDirection.Down)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
@ -34,8 +33,8 @@ namespace osu.Game.Rulesets.Mania.Tests
Size = new Vector2(50, 20), Size = new Vector2(50, 20),
Child = drawableObject = new DrawableNote(note) Child = drawableObject = new DrawableNote(note)
}; };
}
protected override SelectionBlueprint CreateBlueprint() => new NoteSelectionBlueprint(drawableObject); AddBlueprint(new NoteSelectionBlueprint(drawableObject));
}
} }
} }

View File

@ -1,10 +1,11 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles;
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
@ -14,16 +15,51 @@ namespace osu.Game.Rulesets.Osu.Tests
{ {
public class TestSceneHitCircleSelectionBlueprint : SelectionBlueprintTestScene public class TestSceneHitCircleSelectionBlueprint : SelectionBlueprintTestScene
{ {
private readonly DrawableHitCircle drawableObject; private HitCircle hitCircle;
private DrawableHitCircle drawableObject;
private TestBlueprint blueprint;
public TestSceneHitCircleSelectionBlueprint() [SetUp]
public void Setup() => Schedule(() =>
{ {
var hitCircle = new HitCircle { Position = new Vector2(256, 192) }; Clear();
hitCircle = new HitCircle { Position = new Vector2(256, 192) };
hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 });
Add(drawableObject = new DrawableHitCircle(hitCircle)); Add(drawableObject = new DrawableHitCircle(hitCircle));
AddBlueprint(blueprint = new TestBlueprint(drawableObject));
});
[Test]
public void TestInitialState()
{
AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.Position);
} }
protected override SelectionBlueprint CreateBlueprint() => new HitCircleSelectionBlueprint(drawableObject); [Test]
public void TestMoveHitObject()
{
AddStep("move hitobject", () => hitCircle.Position = new Vector2(300, 225));
AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.Position);
}
[Test]
public void TestMoveAfterApplyingDefaults()
{
AddStep("apply defaults", () => hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }));
AddStep("move hitobject", () => hitCircle.Position = new Vector2(300, 225));
AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.Position);
}
private class TestBlueprint : HitCircleSelectionBlueprint
{
public new HitCirclePiece CirclePiece => base.CirclePiece;
public TestBlueprint(DrawableHitCircle hitCircle)
: base(hitCircle)
{
}
}
} }
} }

View File

@ -3,11 +3,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders;
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
@ -29,11 +31,16 @@ namespace osu.Game.Rulesets.Osu.Tests
typeof(PathControlPointPiece) typeof(PathControlPointPiece)
}; };
private readonly DrawableSlider drawableObject; private Slider slider;
private DrawableSlider drawableObject;
private TestSliderBlueprint blueprint;
public TestSceneSliderSelectionBlueprint() [SetUp]
public void Setup() => Schedule(() =>
{ {
var slider = new Slider Clear();
slider = new Slider
{ {
Position = new Vector2(256, 192), Position = new Vector2(256, 192),
Path = new SliderPath(PathType.Bezier, new[] Path = new SliderPath(PathType.Bezier, new[]
@ -47,8 +54,71 @@ namespace osu.Game.Rulesets.Osu.Tests
slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 });
Add(drawableObject = new DrawableSlider(slider)); Add(drawableObject = new DrawableSlider(slider));
AddBlueprint(blueprint = new TestSliderBlueprint(drawableObject));
});
[Test]
public void TestInitialState()
{
checkPositions();
} }
protected override SelectionBlueprint CreateBlueprint() => new SliderSelectionBlueprint(drawableObject); [Test]
public void TestMoveHitObject()
{
moveHitObject();
checkPositions();
}
[Test]
public void TestMoveAfterApplyingDefaults()
{
AddStep("apply defaults", () => slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }));
moveHitObject();
checkPositions();
}
private void moveHitObject()
{
AddStep("move hitobject", () =>
{
slider.Position = new Vector2(300, 225);
});
}
private void checkPositions()
{
AddAssert("body positioned correctly", () => blueprint.BodyPiece.Position == slider.Position);
AddAssert("head positioned correctly",
() => Precision.AlmostEquals(blueprint.HeadBlueprint.CirclePiece.ScreenSpaceDrawQuad.Centre, drawableObject.HeadCircle.ScreenSpaceDrawQuad.Centre));
AddAssert("tail positioned correctly",
() => Precision.AlmostEquals(blueprint.TailBlueprint.CirclePiece.ScreenSpaceDrawQuad.Centre, drawableObject.TailCircle.ScreenSpaceDrawQuad.Centre));
}
private class TestSliderBlueprint : SliderSelectionBlueprint
{
public new SliderBodyPiece BodyPiece => base.BodyPiece;
public new TestSliderCircleBlueprint HeadBlueprint => (TestSliderCircleBlueprint)base.HeadBlueprint;
public new TestSliderCircleBlueprint TailBlueprint => (TestSliderCircleBlueprint)base.TailBlueprint;
public TestSliderBlueprint(DrawableSlider slider)
: base(slider)
{
}
protected override SliderCircleSelectionBlueprint CreateCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) => new TestSliderCircleBlueprint(slider, position);
}
private class TestSliderCircleBlueprint : SliderCircleSelectionBlueprint
{
public new HitCirclePiece CirclePiece => base.CirclePiece;
public TestSliderCircleBlueprint(DrawableSlider slider, SliderPosition position)
: base(slider, position)
{
}
}
} }
} }

View File

@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners; using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners;
using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components; using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
@ -25,8 +24,6 @@ namespace osu.Game.Rulesets.Osu.Tests
typeof(SpinnerPiece) typeof(SpinnerPiece)
}; };
private readonly DrawableSpinner drawableSpinner;
public TestSceneSpinnerSelectionBlueprint() public TestSceneSpinnerSelectionBlueprint()
{ {
var spinner = new Spinner var spinner = new Spinner
@ -35,16 +32,19 @@ namespace osu.Game.Rulesets.Osu.Tests
StartTime = -1000, StartTime = -1000,
EndTime = 2000 EndTime = 2000
}; };
spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 });
DrawableSpinner drawableSpinner;
Add(new Container Add(new Container
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.5f), Size = new Vector2(0.5f),
Child = drawableSpinner = new DrawableSpinner(spinner) Child = drawableSpinner = new DrawableSpinner(spinner)
}); });
}
protected override SelectionBlueprint CreateBlueprint() => new SpinnerSelectionBlueprint(drawableSpinner) { Size = new Vector2(0.5f) }; AddBlueprint(new SpinnerSelectionBlueprint(drawableSpinner) { Size = new Vector2(0.5f) });
}
} }
} }

View File

@ -0,0 +1,25 @@
// 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 osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints
{
/// <summary>
/// A piece of a selection or placement blueprint which visualises an <see cref="OsuHitObject"/>.
/// </summary>
/// <typeparam name="T">The type of <see cref="OsuHitObject"/> which this <see cref="BlueprintPiece{T}"/> visualises.</typeparam>
public abstract class BlueprintPiece<T> : CompositeDrawable
where T : OsuHitObject
{
/// <summary>
/// Updates this <see cref="BlueprintPiece{T}"/> using the properties of a <see cref="OsuHitObject"/>.
/// </summary>
/// <param name="hitObject">The <see cref="OsuHitObject"/> to reference properties from.</param>
public virtual void UpdateFrom(T hitObject)
{
Position = hitObject.Position;
}
}
}

View File

@ -10,18 +10,13 @@ using osuTK;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components
{ {
public class HitCirclePiece : HitObjectPiece public class HitCirclePiece : BlueprintPiece<HitCircle>
{ {
private readonly HitCircle hitCircle; public HitCirclePiece()
public HitCirclePiece(HitCircle hitCircle)
: base(hitCircle)
{ {
this.hitCircle = hitCircle;
Origin = Anchor.Centre; Origin = Anchor.Centre;
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Scale = new Vector2(hitCircle.Scale);
CornerRadius = Size.X / 2; CornerRadius = Size.X / 2;
InternalChild = new RingPiece(); InternalChild = new RingPiece();
@ -31,12 +26,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
Colour = colours.Yellow; Colour = colours.Yellow;
PositionBindable.BindValueChanged(_ => UpdatePosition(), true);
StackHeightBindable.BindValueChanged(_ => UpdatePosition());
ScaleBindable.BindValueChanged(scale => Scale = new Vector2(scale.NewValue), true);
} }
protected virtual void UpdatePosition() => Position = hitCircle.StackedPosition; public override void UpdateFrom(HitCircle hitObject)
{
base.UpdateFrom(hitObject);
Scale = new Vector2(hitObject.Scale);
}
} }
} }

View File

@ -13,10 +13,19 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles
{ {
public new HitCircle HitObject => (HitCircle)base.HitObject; public new HitCircle HitObject => (HitCircle)base.HitObject;
private readonly HitCirclePiece circlePiece;
public HitCirclePlacementBlueprint() public HitCirclePlacementBlueprint()
: base(new HitCircle()) : base(new HitCircle())
{ {
InternalChild = new HitCirclePiece(HitObject); InternalChild = circlePiece = new HitCirclePiece();
}
protected override void Update()
{
base.Update();
circlePiece.UpdateFrom(HitObject);
} }
protected override bool OnClick(ClickEvent e) protected override bool OnClick(ClickEvent e)

View File

@ -7,12 +7,21 @@ using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles
{ {
public class HitCircleSelectionBlueprint : OsuSelectionBlueprint public class HitCircleSelectionBlueprint : OsuSelectionBlueprint<HitCircle>
{ {
protected readonly HitCirclePiece CirclePiece;
public HitCircleSelectionBlueprint(DrawableHitCircle hitCircle) public HitCircleSelectionBlueprint(DrawableHitCircle hitCircle)
: base(hitCircle) : base(hitCircle)
{ {
InternalChild = new HitCirclePiece((HitCircle)hitCircle.HitObject); InternalChild = CirclePiece = new HitCirclePiece();
}
protected override void Update()
{
base.Update();
CirclePiece.UpdateFrom(HitObject);
} }
} }
} }

View File

@ -1,36 +0,0 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Osu.Objects;
using osuTK;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints
{
/// <summary>
/// A piece of a blueprint which responds to changes in the state of a <see cref="OsuHitObject"/>.
/// </summary>
public abstract class HitObjectPiece : CompositeDrawable
{
protected readonly IBindable<Vector2> PositionBindable = new Bindable<Vector2>();
protected readonly IBindable<int> StackHeightBindable = new Bindable<int>();
protected readonly IBindable<float> ScaleBindable = new Bindable<float>();
private readonly OsuHitObject hitObject;
protected HitObjectPiece(OsuHitObject hitObject)
{
this.hitObject = hitObject;
}
[BackgroundDependencyLoader]
private void load()
{
PositionBindable.BindTo(hitObject.PositionBindable);
StackHeightBindable.BindTo(hitObject.StackHeightBindable);
ScaleBindable.BindTo(hitObject.ScaleBindable);
}
}
}

View File

@ -7,11 +7,12 @@ using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints namespace osu.Game.Rulesets.Osu.Edit.Blueprints
{ {
public class OsuSelectionBlueprint : SelectionBlueprint public abstract class OsuSelectionBlueprint<T> : SelectionBlueprint
where T : OsuHitObject
{ {
protected OsuHitObject OsuObject => (OsuHitObject)HitObject.HitObject; protected new T HitObject => (T)base.HitObject.HitObject;
public OsuSelectionBlueprint(DrawableHitObject hitObject) protected OsuSelectionBlueprint(DrawableHitObject hitObject)
: base(hitObject) : base(hitObject)
{ {
} }

View File

@ -1,32 +0,0 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints
{
/// <summary>
/// A piece of a blueprint which responds to changes in the state of a <see cref="Slider"/>.
/// </summary>
public abstract class SliderPiece : HitObjectPiece
{
protected readonly IBindable<SliderPath> PathBindable = new Bindable<SliderPath>();
private readonly Slider slider;
protected SliderPiece(Slider slider)
: base(slider)
{
this.slider = slider;
}
[BackgroundDependencyLoader]
private void load()
{
PathBindable.BindTo(slider.PathBindable);
}
}
}

View File

@ -14,7 +14,7 @@ using osuTK;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{ {
public class PathControlPointPiece : CompositeDrawable public class PathControlPointPiece : BlueprintPiece<Slider>
{ {
private readonly Slider slider; private readonly Slider slider;
private readonly int index; private readonly int index;

View File

@ -1,35 +1,29 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{ {
public class PathControlPointVisualiser : SliderPiece public class PathControlPointVisualiser : CompositeDrawable
{ {
private readonly Slider slider; private readonly Slider slider;
private readonly Container<PathControlPointPiece> pieces; private readonly Container<PathControlPointPiece> pieces;
public PathControlPointVisualiser(Slider slider) public PathControlPointVisualiser(Slider slider)
: base(slider)
{ {
this.slider = slider; this.slider = slider;
InternalChild = pieces = new Container<PathControlPointPiece> { RelativeSizeAxes = Axes.Both }; InternalChild = pieces = new Container<PathControlPointPiece> { RelativeSizeAxes = Axes.Both };
} }
[BackgroundDependencyLoader] protected override void Update()
private void load()
{ {
PathBindable.BindValueChanged(_ => updatePathControlPoints(), true); base.Update();
}
private void updatePathControlPoints()
{
while (slider.Path.ControlPoints.Length > pieces.Count) while (slider.Path.ControlPoints.Length > pieces.Count)
pieces.Add(new PathControlPointPiece(slider, pieces.Count)); pieces.Add(new PathControlPointPiece(slider, pieces.Count));
while (slider.Path.ControlPoints.Length < pieces.Count) while (slider.Path.ControlPoints.Length < pieces.Count)

View File

@ -11,19 +11,15 @@ using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{ {
public class SliderBodyPiece : SliderPiece public class SliderBodyPiece : BlueprintPiece<Slider>
{ {
private readonly Slider slider;
private readonly ManualSliderBody body; private readonly ManualSliderBody body;
public SliderBodyPiece(Slider slider) public SliderBodyPiece()
: base(slider)
{ {
this.slider = slider;
InternalChild = body = new ManualSliderBody InternalChild = body = new ManualSliderBody
{ {
AccentColour = Color4.Transparent, AccentColour = Color4.Transparent
}; };
} }
@ -31,19 +27,16 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
body.BorderColour = colours.Yellow; body.BorderColour = colours.Yellow;
PositionBindable.BindValueChanged(_ => updatePosition(), true);
ScaleBindable.BindValueChanged(scale => body.PathRadius = scale.NewValue * OsuHitObject.OBJECT_RADIUS, true);
} }
private void updatePosition() => Position = slider.StackedPosition; public override void UpdateFrom(Slider hitObject)
protected override void Update()
{ {
base.Update(); base.UpdateFrom(hitObject);
body.PathRadius = hitObject.Scale * OsuHitObject.OBJECT_RADIUS;
var vertices = new List<Vector2>(); var vertices = new List<Vector2>();
slider.Path.GetPathToProgress(vertices, 0, 1); hitObject.Path.GetPathToProgress(vertices, 0, 1);
body.SetVertices(vertices); body.SetVertices(vertices);

View File

@ -1,47 +0,0 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{
public class SliderCirclePiece : HitCirclePiece
{
private readonly IBindable<SliderPath> pathBindable = new Bindable<SliderPath>();
private readonly Slider slider;
private readonly SliderPosition position;
public SliderCirclePiece(Slider slider, SliderPosition position)
: base(slider.HeadCircle)
{
this.slider = slider;
this.position = position;
}
[BackgroundDependencyLoader]
private void load()
{
pathBindable.BindTo(slider.PathBindable);
pathBindable.BindValueChanged(_ => UpdatePosition(), true);
}
protected override void UpdatePosition()
{
switch (position)
{
case SliderPosition.Start:
Position = slider.StackedPosition + slider.Path.PositionAt(0);
break;
case SliderPosition.End:
Position = slider.StackedPosition + slider.Path.PositionAt(1);
break;
}
}
}
}

View File

@ -1,22 +1,34 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
{ {
public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint<Slider>
{ {
public SliderCircleSelectionBlueprint(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position) protected readonly HitCirclePiece CirclePiece;
: base(hitObject)
private readonly SliderPosition position;
public SliderCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position)
: base(slider)
{ {
InternalChild = new SliderCirclePiece(slider, position); this.position = position;
InternalChild = CirclePiece = new HitCirclePiece();
Select(); Select();
} }
protected override void Update()
{
base.Update();
CirclePiece.UpdateFrom(position == SliderPosition.Start ? HitObject.HeadCircle : HitObject.TailCircle);
}
// Todo: This is temporary, since the slider circle masks don't do anything special yet. In the future they will handle input. // Todo: This is temporary, since the slider circle masks don't do anything special yet. In the future they will handle input.
public override bool HandlePositionalInput => false; public override bool HandlePositionalInput => false;
} }

View File

@ -11,6 +11,7 @@ using osu.Game.Graphics;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
using osuTK; using osuTK;
using osuTK.Input; using osuTK.Input;
@ -21,6 +22,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
{ {
public new Objects.Slider HitObject => (Objects.Slider)base.HitObject; public new Objects.Slider HitObject => (Objects.Slider)base.HitObject;
private SliderBodyPiece bodyPiece;
private HitCirclePiece headCirclePiece;
private HitCirclePiece tailCirclePiece;
private readonly List<Segment> segments = new List<Segment>(); private readonly List<Segment> segments = new List<Segment>();
private Vector2 cursor; private Vector2 cursor;
@ -38,9 +43,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
{ {
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
new SliderBodyPiece(HitObject), bodyPiece = new SliderBodyPiece(),
new SliderCirclePiece(HitObject, SliderPosition.Start), headCirclePiece = new HitCirclePiece(),
new SliderCirclePiece(HitObject, SliderPosition.End), tailCirclePiece = new HitCirclePiece(),
new PathControlPointVisualiser(HitObject), new PathControlPointVisualiser(HitObject),
}; };
@ -120,6 +125,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
{ {
var newControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToArray(); var newControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToArray();
HitObject.Path = new SliderPath(newControlPoints.Length > 2 ? PathType.Bezier : PathType.Linear, newControlPoints); HitObject.Path = new SliderPath(newControlPoints.Length > 2 ? PathType.Bezier : PathType.Linear, newControlPoints);
bodyPiece.UpdateFrom(HitObject);
headCirclePiece.UpdateFrom(HitObject.HeadCircle);
tailCirclePiece.UpdateFrom(HitObject.TailCircle);
} }
private void setState(PlacementState newState) private void setState(PlacementState newState)

View File

@ -9,9 +9,11 @@ using osuTK;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
{ {
public class SliderSelectionBlueprint : OsuSelectionBlueprint public class SliderSelectionBlueprint : OsuSelectionBlueprint<Slider>
{ {
private readonly SliderCircleSelectionBlueprint headBlueprint; protected readonly SliderBodyPiece BodyPiece;
protected readonly SliderCircleSelectionBlueprint HeadBlueprint;
protected readonly SliderCircleSelectionBlueprint TailBlueprint;
public SliderSelectionBlueprint(DrawableSlider slider) public SliderSelectionBlueprint(DrawableSlider slider)
: base(slider) : base(slider)
@ -20,13 +22,22 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
new SliderBodyPiece(sliderObject), BodyPiece = new SliderBodyPiece(),
headBlueprint = new SliderCircleSelectionBlueprint(slider.HeadCircle, sliderObject, SliderPosition.Start), HeadBlueprint = CreateCircleSelectionBlueprint(slider, SliderPosition.Start),
new SliderCircleSelectionBlueprint(slider.TailCircle, sliderObject, SliderPosition.End), TailBlueprint = CreateCircleSelectionBlueprint(slider, SliderPosition.End),
new PathControlPointVisualiser(sliderObject), new PathControlPointVisualiser(sliderObject),
}; };
} }
public override Vector2 SelectionPoint => headBlueprint.SelectionPoint; protected override void Update()
{
base.Update();
BodyPiece.UpdateFrom(HitObject);
}
public override Vector2 SelectionPoint => HeadBlueprint.SelectionPoint;
protected virtual SliderCircleSelectionBlueprint CreateCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) => new SliderCircleSelectionBlueprint(slider, position);
} }
} }

View File

@ -12,17 +12,13 @@ using osuTK;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components
{ {
public class SpinnerPiece : HitObjectPiece public class SpinnerPiece : BlueprintPiece<Spinner>
{ {
private readonly Spinner spinner;
private readonly CircularContainer circle; private readonly CircularContainer circle;
private readonly RingPiece ring; private readonly RingPiece ring;
public SpinnerPiece(Spinner spinner) public SpinnerPiece()
: base(spinner)
{ {
this.spinner = spinner;
Origin = Anchor.Centre; Origin = Anchor.Centre;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
@ -44,21 +40,20 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components
Origin = Anchor.Centre Origin = Anchor.Centre
} }
}; };
ring.Scale = new Vector2(spinner.Scale);
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
Colour = colours.Yellow; Colour = colours.Yellow;
PositionBindable.BindValueChanged(_ => updatePosition(), true);
StackHeightBindable.BindValueChanged(_ => updatePosition());
ScaleBindable.BindValueChanged(scale => ring.Scale = new Vector2(scale.NewValue), true);
} }
private void updatePosition() => Position = spinner.Position; public override void UpdateFrom(Spinner hitObject)
{
base.UpdateFrom(hitObject);
ring.Scale = new Vector2(hitObject.Scale);
}
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => circle.ReceivePositionalInputAt(screenSpacePos); public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => circle.ReceivePositionalInputAt(screenSpacePos);
} }

View File

@ -22,7 +22,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
public SpinnerPlacementBlueprint() public SpinnerPlacementBlueprint()
: base(new Spinner { Position = OsuPlayfield.BASE_SIZE / 2 }) : base(new Spinner { Position = OsuPlayfield.BASE_SIZE / 2 })
{ {
InternalChild = piece = new SpinnerPiece(HitObject) { Alpha = 0.5f }; InternalChild = piece = new SpinnerPiece { Alpha = 0.5f };
}
protected override void Update()
{
base.Update();
piece.UpdateFrom(HitObject);
} }
protected override bool OnClick(ClickEvent e) protected override bool OnClick(ClickEvent e)

View File

@ -8,14 +8,21 @@ using osuTK;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
{ {
public class SpinnerSelectionBlueprint : OsuSelectionBlueprint public class SpinnerSelectionBlueprint : OsuSelectionBlueprint<Spinner>
{ {
private readonly SpinnerPiece piece; private readonly SpinnerPiece piece;
public SpinnerSelectionBlueprint(DrawableSpinner spinner) public SpinnerSelectionBlueprint(DrawableSpinner spinner)
: base(spinner) : base(spinner)
{ {
InternalChild = piece = new SpinnerPiece((Spinner)spinner.HitObject); InternalChild = piece = new SpinnerPiece();
}
protected override void Update()
{
base.Update();
piece.UpdateFrom(HitObject);
} }
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => piece.ReceivePositionalInputAt(screenSpacePos); public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => piece.ReceivePositionalInputAt(screenSpacePos);

View File

@ -54,13 +54,13 @@ namespace osu.Game.Rulesets.Osu.Objects
{ {
base.Position = value; base.Position = value;
endPositionCache.Invalidate();
if (HeadCircle != null) if (HeadCircle != null)
HeadCircle.Position = value; HeadCircle.Position = value;
if (TailCircle != null) if (TailCircle != null)
TailCircle.Position = EndPosition; TailCircle.Position = EndPosition;
endPositionCache.Invalidate();
} }
} }

View File

@ -12,7 +12,7 @@ using osu.Game.Graphics.Sprites;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Editor namespace osu.Game.Tests.Visual.UserInterface
{ {
[TestFixture] [TestFixture]
public class TestSceneWaveContainer : OsuTestScene public class TestSceneWaveContainer : OsuTestScene

View File

@ -1,10 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
@ -12,8 +10,6 @@ namespace osu.Game.Tests.Visual
{ {
public abstract class SelectionBlueprintTestScene : OsuTestScene public abstract class SelectionBlueprintTestScene : OsuTestScene
{ {
private SelectionBlueprint blueprint;
protected override Container<Drawable> Content => content ?? base.Content; protected override Container<Drawable> Content => content ?? base.Content;
private readonly Container content; private readonly Container content;
@ -26,25 +22,13 @@ namespace osu.Game.Tests.Visual
}); });
} }
[BackgroundDependencyLoader] protected void AddBlueprint(SelectionBlueprint blueprint)
private void load()
{ {
blueprint = CreateBlueprint(); Add(blueprint.With(d =>
blueprint.Depth = float.MinValue; {
blueprint.SelectionRequested += (_, __) => blueprint.Select(); d.Depth = float.MinValue;
d.Select();
Add(blueprint); }));
AddStep("Select", () => blueprint.Select());
AddStep("Deselect", () => blueprint.Deselect());
} }
protected override bool OnClick(ClickEvent e)
{
blueprint.Deselect();
return true;
}
protected abstract SelectionBlueprint CreateBlueprint();
} }
} }