From af1de01ed61d258a4d579ec0f7354163e9a24e58 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 29 Oct 2018 18:23:23 +0900 Subject: [PATCH] Add a spinner selection mask --- .../TestCaseSpinnerSelectionMask.cs | 50 ++++++++++++++ .../SpinnerMasks/Components/SpinnerPiece.cs | 65 +++++++++++++++++++ .../SpinnerMasks/SpinnerSelectionMask.cs | 24 +++++++ .../Edit/OsuHitObjectComposer.cs | 3 + .../Objects/Drawables/DrawableSpinner.cs | 4 +- 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs new file mode 100644 index 0000000000..b436ff0e9f --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs @@ -0,0 +1,50 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +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.Masks.SpinnerMasks; +using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Tests.Visual; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestCaseSpinnerSelectionMask : HitObjectSelectionMaskTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(SpinnerSelectionMask), + typeof(SpinnerPiece) + }; + + private readonly DrawableSpinner drawableSpinner; + + public TestCaseSpinnerSelectionMask() + { + var spinner = new Spinner + { + Position = new Vector2(256, 256), + StartTime = -1000, + EndTime = 2000 + }; + spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); + + Add(new Container + { + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.5f), + Child = drawableSpinner = new DrawableSpinner(spinner) + }); + } + + protected override SelectionMask CreateMask() => new SpinnerSelectionMask(drawableSpinner) { Size = new Vector2(0.5f) }; + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs new file mode 100644 index 0000000000..ce2b5cd1d6 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs @@ -0,0 +1,65 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components +{ + public class SpinnerPiece : CompositeDrawable + { + private readonly Spinner spinner; + private readonly CircularContainer circle; + + public SpinnerPiece(Spinner spinner) + { + this.spinner = spinner; + + Origin = Anchor.Centre; + + RelativeSizeAxes = Axes.Both; + FillMode = FillMode.Fit; + Size = new Vector2(1.3f); + + RingPiece ring; + InternalChildren = new Drawable[] + { + circle = new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Alpha = 0.5f, + Child = new Box { RelativeSizeAxes = Axes.Both } + }, + ring = new RingPiece + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + } + }; + + ring.Scale = new Vector2(spinner.Scale); + + spinner.PositionChanged += _ => updatePosition(); + spinner.StackHeightChanged += _ => updatePosition(); + + updatePosition(); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Colour = colours.Yellow; + } + + private void updatePosition() => Position = spinner.Position; + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => circle.ReceivePositionalInputAt(screenSpacePos); + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs new file mode 100644 index 0000000000..0e47bd2a8b --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks +{ + public class SpinnerSelectionMask : SelectionMask + { + private readonly SpinnerPiece piece; + + public SpinnerSelectionMask(DrawableSpinner spinner) + : base(spinner) + { + InternalChild = piece = new SpinnerPiece((Spinner)spinner.HitObject); + } + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => piece.ReceivePositionalInputAt(screenSpacePos); + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index ac41d6ef27..386665ab7c 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -10,6 +10,7 @@ using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks; +using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; @@ -42,6 +43,8 @@ namespace osu.Game.Rulesets.Osu.Edit return new HitCircleSelectionMask(circle); case DrawableSlider slider: return new SliderSelectionMask(slider); + case DrawableSpinner spinner: + return new SpinnerSelectionMask(spinner); } return base.CreateMaskFor(hitObject); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 51b1990a21..f3846bd52f 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -112,6 +112,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Alpha = 0 } }; + + s.PositionChanged += _ => Position = s.Position; } public float Progress => MathHelper.Clamp(Disc.RotationAbsolute / 360 / Spinner.SpinsRequired, 0, 1); @@ -167,7 +169,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void Update() { - Disc.Tracking = OsuActionInputManager.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton); + Disc.Tracking = OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false; if (!spmCounter.IsPresent && Disc.Tracking) spmCounter.FadeIn(HitObject.TimeFadeIn);