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

Make hitobject pieces able to update dynamically

This commit is contained in:
smoogipoo 2019-09-27 18:45:22 +09:00
parent 4fc37d1137
commit bddaead72e
14 changed files with 125 additions and 95 deletions

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

@ -3,7 +3,6 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
@ -11,17 +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 : CompositeDrawable public class HitCirclePiece : BlueprintPiece<HitCircle>
{ {
private readonly HitCircle hitCircle; public HitCirclePiece()
public HitCirclePiece(HitCircle 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();
@ -33,14 +28,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components
Colour = colours.Yellow; Colour = colours.Yellow;
} }
protected override void Update() public override void UpdateFrom(HitCircle hitObject)
{ {
base.Update(); base.UpdateFrom(hitObject);
UpdatePosition(); Scale = new Vector2(hitObject.Scale);
Scale = new Vector2(hitCircle.Scale); }
}
protected virtual void UpdatePosition() => Position = hitCircle.StackedPosition;
} }
} }

View File

@ -13,10 +13,12 @@ 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 LoadComplete() protected override void LoadComplete()
@ -27,6 +29,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles
HitObject.Position = Parent?.ToLocalSpace(GetContainingInputManager().CurrentState.Mouse.Position) ?? Vector2.Zero; HitObject.Position = Parent?.ToLocalSpace(GetContainingInputManager().CurrentState.Mouse.Position) ?? Vector2.Zero;
} }
protected override void Update()
{
base.Update();
circlePiece.UpdateFrom(HitObject);
}
protected override bool OnClick(ClickEvent e) protected override bool OnClick(ClickEvent e)
{ {
HitObject.StartTime = EditorClock.CurrentTime; HitObject.StartTime = EditorClock.CurrentTime;

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>
{ {
private 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

@ -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

@ -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

@ -3,7 +3,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
@ -12,18 +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 : CompositeDrawable public class SliderBodyPiece : BlueprintPiece<Slider>
{ {
private readonly Slider slider;
private readonly ManualSliderBody body; private readonly ManualSliderBody body;
public SliderBodyPiece(Slider slider) public SliderBodyPiece()
{ {
this.slider = slider;
InternalChild = body = new ManualSliderBody InternalChild = body = new ManualSliderBody
{ {
AccentColour = Color4.Transparent, AccentColour = Color4.Transparent
}; };
} }
@ -33,17 +29,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
body.BorderColour = colours.Yellow; body.BorderColour = colours.Yellow;
} }
private void updatePosition() => Position = slider.StackedPosition; public override void UpdateFrom(Slider hitObject)
protected override void Update()
{ {
base.Update(); base.UpdateFrom(hitObject);
Position = slider.StackedPosition; body.PathRadius = hitObject.Scale * OsuHitObject.OBJECT_RADIUS;
body.PathRadius = slider.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,35 +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.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 Slider slider;
private readonly SliderPosition position;
public SliderCirclePiece(Slider slider, SliderPosition position)
: base(slider.HeadCircle)
{
this.slider = slider;
this.position = position;
}
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,33 @@
// 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) private readonly SliderPosition position;
: base(hitObject) private readonly HitCirclePiece circlePiece;
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),
}; };
@ -130,6 +135,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,8 +9,9 @@ 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 SliderBodyPiece bodyPiece;
private readonly SliderCircleSelectionBlueprint headBlueprint; private readonly SliderCircleSelectionBlueprint headBlueprint;
public SliderSelectionBlueprint(DrawableSlider slider) public SliderSelectionBlueprint(DrawableSlider slider)
@ -20,13 +21,20 @@ 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 = new SliderCircleSelectionBlueprint(slider, SliderPosition.Start),
new SliderCircleSelectionBlueprint(slider.TailCircle, sliderObject, SliderPosition.End), new SliderCircleSelectionBlueprint(slider, SliderPosition.End),
new PathControlPointVisualiser(sliderObject), new PathControlPointVisualiser(sliderObject),
}; };
} }
protected override void Update()
{
base.Update();
bodyPiece.UpdateFrom(HitObject);
}
public override Vector2 SelectionPoint => headBlueprint.SelectionPoint; public override Vector2 SelectionPoint => headBlueprint.SelectionPoint;
} }
} }

View File

@ -12,16 +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 : CompositeDrawable 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()
{ {
this.spinner = spinner;
Origin = Anchor.Centre; Origin = Anchor.Centre;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
@ -43,8 +40,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components
Origin = Anchor.Centre Origin = Anchor.Centre
} }
}; };
ring.Scale = new Vector2(spinner.Scale);
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -53,12 +48,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components
Colour = colours.Yellow; Colour = colours.Yellow;
} }
protected override void Update() public override void UpdateFrom(Spinner hitObject)
{ {
base.Update(); base.UpdateFrom(hitObject);
Position = spinner.Position; ring.Scale = new Vector2(hitObject.Scale);
ring.Scale = new Vector2(spinner.Scale);
} }
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => circle.ReceivePositionalInputAt(screenSpacePos); public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => circle.ReceivePositionalInputAt(screenSpacePos);

View File

@ -21,7 +21,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);