diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs index 622d840a0c..90394f3d1b 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; @@ -39,6 +38,8 @@ namespace osu.Game.Rulesets.Mania.Tests AccentColour = { Value = OsuColour.Gray(0.3f) } } }; + + AddBlueprint(new HoldNoteSelectionBlueprint(drawableObject)); } protected override void Update() @@ -51,7 +52,5 @@ namespace osu.Game.Rulesets.Mania.Tests nested.Y = (float)(-finalPosition * content.DrawHeight); } } - - protected override SelectionBlueprint CreateBlueprint() => new HoldNoteSelectionBlueprint(drawableObject); } } diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs index 6bb344f977..1514bdf0bd 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs @@ -5,7 +5,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; @@ -17,8 +16,6 @@ namespace osu.Game.Rulesets.Mania.Tests { public class TestSceneNoteSelectionBlueprint : ManiaSelectionBlueprintTestScene { - private readonly DrawableNote drawableObject; - protected override Container Content => content ?? base.Content; private readonly Container content; @@ -27,6 +24,8 @@ namespace osu.Game.Rulesets.Mania.Tests var note = new Note { Column = 0 }; note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + DrawableNote drawableObject; + base.Content.Child = content = new ScrollingTestContainer(ScrollingDirection.Down) { Anchor = Anchor.Centre, @@ -34,8 +33,8 @@ namespace osu.Game.Rulesets.Mania.Tests Size = new Vector2(50, 20), Child = drawableObject = new DrawableNote(note) }; - } - protected override SelectionBlueprint CreateBlueprint() => new NoteSelectionBlueprint(drawableObject); + AddBlueprint(new NoteSelectionBlueprint(drawableObject)); + } } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs index 32043bf5d7..d4cdabdb07 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs @@ -1,10 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using NUnit.Framework; using osu.Game.Beatmaps; 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.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; @@ -14,16 +15,51 @@ namespace osu.Game.Rulesets.Osu.Tests { 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 }); 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) + { + } + } } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs index 8cf5a2f33e..ec23ec31b2 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs @@ -3,11 +3,13 @@ using System; using System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; 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.Components; using osu.Game.Rulesets.Osu.Objects; @@ -29,11 +31,16 @@ namespace osu.Game.Rulesets.Osu.Tests 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), Path = new SliderPath(PathType.Bezier, new[] @@ -47,8 +54,71 @@ namespace osu.Game.Rulesets.Osu.Tests slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); 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) + { + } + } } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs index c5cea76b14..d777ca3610 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs @@ -7,7 +7,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; 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.Components; using osu.Game.Rulesets.Osu.Objects; @@ -25,8 +24,6 @@ namespace osu.Game.Rulesets.Osu.Tests typeof(SpinnerPiece) }; - private readonly DrawableSpinner drawableSpinner; - public TestSceneSpinnerSelectionBlueprint() { var spinner = new Spinner @@ -35,16 +32,19 @@ namespace osu.Game.Rulesets.Osu.Tests StartTime = -1000, EndTime = 2000 }; + spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); + DrawableSpinner drawableSpinner; + Add(new Container { RelativeSizeAxes = Axes.Both, Size = new Vector2(0.5f), 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) }); + } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs new file mode 100644 index 0000000000..95e926fdfa --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs @@ -0,0 +1,25 @@ +// Copyright (c) ppy Pty Ltd . 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 +{ + /// + /// A piece of a selection or placement blueprint which visualises an . + /// + /// The type of which this visualises. + public abstract class BlueprintPiece : CompositeDrawable + where T : OsuHitObject + { + /// + /// Updates this using the properties of a . + /// + /// The to reference properties from. + public virtual void UpdateFrom(T hitObject) + { + Position = hitObject.Position; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs index fe11ead94d..2b6b93a590 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs @@ -10,18 +10,13 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components { - public class HitCirclePiece : HitObjectPiece + public class HitCirclePiece : BlueprintPiece { - private readonly HitCircle hitCircle; - - public HitCirclePiece(HitCircle hitCircle) - : base(hitCircle) + public HitCirclePiece() { - this.hitCircle = hitCircle; Origin = Anchor.Centre; Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); - Scale = new Vector2(hitCircle.Scale); CornerRadius = Size.X / 2; InternalChild = new RingPiece(); @@ -31,12 +26,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components private void load(OsuColour colours) { 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); + } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs index 0f6bee19bb..6c08990ad6 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs @@ -13,10 +13,19 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles { public new HitCircle HitObject => (HitCircle)base.HitObject; + private readonly HitCirclePiece circlePiece; + public HitCirclePlacementBlueprint() : 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) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs index 83787e2219..a191dba8ff 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs @@ -7,12 +7,21 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles { - public class HitCircleSelectionBlueprint : OsuSelectionBlueprint + public class HitCircleSelectionBlueprint : OsuSelectionBlueprint { + protected readonly HitCirclePiece CirclePiece; + public HitCircleSelectionBlueprint(DrawableHitCircle hitCircle) : base(hitCircle) { - InternalChild = new HitCirclePiece((HitCircle)hitCircle.HitObject); + InternalChild = CirclePiece = new HitCirclePiece(); + } + + protected override void Update() + { + base.Update(); + + CirclePiece.UpdateFrom(HitObject); } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs deleted file mode 100644 index 315a5a2b9d..0000000000 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) ppy Pty Ltd . 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 -{ - /// - /// A piece of a blueprint which responds to changes in the state of a . - /// - public abstract class HitObjectPiece : CompositeDrawable - { - protected readonly IBindable PositionBindable = new Bindable(); - protected readonly IBindable StackHeightBindable = new Bindable(); - protected readonly IBindable ScaleBindable = new Bindable(); - - 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); - } - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs index dd524252f3..2e4b990db8 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs @@ -7,11 +7,12 @@ using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit.Blueprints { - public class OsuSelectionBlueprint : SelectionBlueprint + public abstract class OsuSelectionBlueprint : 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) { } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs deleted file mode 100644 index 8fd1d6d6f9..0000000000 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) ppy Pty Ltd . 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 -{ - /// - /// A piece of a blueprint which responds to changes in the state of a . - /// - public abstract class SliderPiece : HitObjectPiece - { - protected readonly IBindable PathBindable = new Bindable(); - - private readonly Slider slider; - - protected SliderPiece(Slider slider) - : base(slider) - { - this.slider = slider; - } - - [BackgroundDependencyLoader] - private void load() - { - PathBindable.BindTo(slider.PathBindable); - } - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index e257369ad9..3aec7c2872 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { - public class PathControlPointPiece : CompositeDrawable + public class PathControlPointPiece : BlueprintPiece { private readonly Slider slider; private readonly int index; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index df846b5d5b..24fcc460d1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -1,35 +1,29 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { - public class PathControlPointVisualiser : SliderPiece + public class PathControlPointVisualiser : CompositeDrawable { private readonly Slider slider; private readonly Container pieces; public PathControlPointVisualiser(Slider slider) - : base(slider) { this.slider = slider; InternalChild = pieces = new Container { RelativeSizeAxes = Axes.Both }; } - [BackgroundDependencyLoader] - private void load() + protected override void Update() { - PathBindable.BindValueChanged(_ => updatePathControlPoints(), true); - } + base.Update(); - private void updatePathControlPoints() - { while (slider.Path.ControlPoints.Length > pieces.Count) pieces.Add(new PathControlPointPiece(slider, pieces.Count)); while (slider.Path.ControlPoints.Length < pieces.Count) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index f1f55731b6..d28cf7b492 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -11,19 +11,15 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { - public class SliderBodyPiece : SliderPiece + public class SliderBodyPiece : BlueprintPiece { - private readonly Slider slider; private readonly ManualSliderBody body; - public SliderBodyPiece(Slider slider) - : base(slider) + public SliderBodyPiece() { - this.slider = slider; - 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) { 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; - - protected override void Update() + public override void UpdateFrom(Slider hitObject) { - base.Update(); + base.UpdateFrom(hitObject); + + body.PathRadius = hitObject.Scale * OsuHitObject.OBJECT_RADIUS; var vertices = new List(); - slider.Path.GetPathToProgress(vertices, 0, 1); + hitObject.Path.GetPathToProgress(vertices, 0, 1); body.SetVertices(vertices); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs deleted file mode 100644 index 2ecfea2e3e..0000000000 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) ppy Pty Ltd . 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 pathBindable = new Bindable(); - - 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; - } - } - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs index c9f005495c..f09279ed73 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs @@ -1,22 +1,34 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // 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.Drawables; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { - public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint + public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint { - public SliderCircleSelectionBlueprint(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position) - : base(hitObject) + protected readonly HitCirclePiece CirclePiece; + + 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(); } + 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. public override bool HandlePositionalInput => false; } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index 62c879b05e..fc074ef8af 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -11,6 +11,7 @@ using osu.Game.Graphics; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; 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 osuTK; using osuTK.Input; @@ -21,6 +22,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { public new Objects.Slider HitObject => (Objects.Slider)base.HitObject; + private SliderBodyPiece bodyPiece; + private HitCirclePiece headCirclePiece; + private HitCirclePiece tailCirclePiece; + private readonly List segments = new List(); private Vector2 cursor; @@ -38,9 +43,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { InternalChildren = new Drawable[] { - new SliderBodyPiece(HitObject), - new SliderCirclePiece(HitObject, SliderPosition.Start), - new SliderCirclePiece(HitObject, SliderPosition.End), + bodyPiece = new SliderBodyPiece(), + headCirclePiece = new HitCirclePiece(), + tailCirclePiece = new HitCirclePiece(), 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(); 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) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index fb8c081ff7..fdeffc6f8a 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -9,9 +9,11 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { - public class SliderSelectionBlueprint : OsuSelectionBlueprint + public class SliderSelectionBlueprint : OsuSelectionBlueprint { - private readonly SliderCircleSelectionBlueprint headBlueprint; + protected readonly SliderBodyPiece BodyPiece; + protected readonly SliderCircleSelectionBlueprint HeadBlueprint; + protected readonly SliderCircleSelectionBlueprint TailBlueprint; public SliderSelectionBlueprint(DrawableSlider slider) : base(slider) @@ -20,13 +22,22 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders InternalChildren = new Drawable[] { - new SliderBodyPiece(sliderObject), - headBlueprint = new SliderCircleSelectionBlueprint(slider.HeadCircle, sliderObject, SliderPosition.Start), - new SliderCircleSelectionBlueprint(slider.TailCircle, sliderObject, SliderPosition.End), + BodyPiece = new SliderBodyPiece(), + HeadBlueprint = CreateCircleSelectionBlueprint(slider, SliderPosition.Start), + TailBlueprint = CreateCircleSelectionBlueprint(slider, SliderPosition.End), 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); } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs index ae94848c81..65c8720031 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs @@ -12,17 +12,13 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components { - public class SpinnerPiece : HitObjectPiece + public class SpinnerPiece : BlueprintPiece { - private readonly Spinner spinner; private readonly CircularContainer circle; private readonly RingPiece ring; - public SpinnerPiece(Spinner spinner) - : base(spinner) + public SpinnerPiece() { - this.spinner = spinner; - Origin = Anchor.Centre; RelativeSizeAxes = Axes.Both; @@ -44,21 +40,20 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components Origin = Anchor.Centre } }; - - ring.Scale = new Vector2(spinner.Scale); } [BackgroundDependencyLoader] private void load(OsuColour colours) { 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); } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs index 730b8448de..8319f49cbc 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs @@ -22,7 +22,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners public SpinnerPlacementBlueprint() : 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) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs index 25cef3b251..f05d4f8435 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs @@ -8,14 +8,21 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners { - public class SpinnerSelectionBlueprint : OsuSelectionBlueprint + public class SpinnerSelectionBlueprint : OsuSelectionBlueprint { private readonly SpinnerPiece piece; public SpinnerSelectionBlueprint(DrawableSpinner 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); diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index d8514092bc..3ed1f2cdde 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -54,13 +54,13 @@ namespace osu.Game.Rulesets.Osu.Objects { base.Position = value; + endPositionCache.Invalidate(); + if (HeadCircle != null) HeadCircle.Position = value; if (TailCircle != null) TailCircle.Position = EndPosition; - - endPositionCache.Invalidate(); } } diff --git a/osu.Game.Tests/Visual/Editor/TestSceneWaveContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneWaveContainer.cs similarity index 97% rename from osu.Game.Tests/Visual/Editor/TestSceneWaveContainer.cs rename to osu.Game.Tests/Visual/UserInterface/TestSceneWaveContainer.cs index de19727251..5b130b9224 100644 --- a/osu.Game.Tests/Visual/Editor/TestSceneWaveContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneWaveContainer.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.Sprites; using osuTK; using osuTK.Graphics; -namespace osu.Game.Tests.Visual.Editor +namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] public class TestSceneWaveContainer : OsuTestScene diff --git a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs index df3af2cc43..f53c12b047 100644 --- a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs +++ b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs @@ -1,10 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Input.Events; using osu.Framework.Timing; using osu.Game.Rulesets.Edit; @@ -12,8 +10,6 @@ namespace osu.Game.Tests.Visual { public abstract class SelectionBlueprintTestScene : OsuTestScene { - private SelectionBlueprint blueprint; - protected override Container Content => content ?? base.Content; private readonly Container content; @@ -26,25 +22,13 @@ namespace osu.Game.Tests.Visual }); } - [BackgroundDependencyLoader] - private void load() + protected void AddBlueprint(SelectionBlueprint blueprint) { - blueprint = CreateBlueprint(); - blueprint.Depth = float.MinValue; - blueprint.SelectionRequested += (_, __) => blueprint.Select(); - - Add(blueprint); - - AddStep("Select", () => blueprint.Select()); - AddStep("Deselect", () => blueprint.Deselect()); + Add(blueprint.With(d => + { + d.Depth = float.MinValue; + d.Select(); + })); } - - protected override bool OnClick(ClickEvent e) - { - blueprint.Deselect(); - return true; - } - - protected abstract SelectionBlueprint CreateBlueprint(); } }