Add hitobject overlays to selected hitobjects

This commit is contained in:
smoogipoo 2018-02-20 18:01:45 +09:00
parent 2a5bfdb4b8
commit ad2f556133
12 changed files with 315 additions and 26 deletions

View File

@ -0,0 +1,26 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Edit.Layers.Selection;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays;
using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection
{
public class OsuHitObjectOverlayLayer : HitObjectOverlayLayer
{
protected override HitObjectOverlay CreateOverlayFor(DrawableHitObject hitObject)
{
switch (hitObject)
{
case DrawableHitCircle circle:
return new HitCircleOverlay(circle);
case DrawableSlider slider:
return new SliderOverlay(slider);
}
return base.CreateOverlayFor(hitObject);
}
}
}

View File

@ -0,0 +1,33 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Allocation;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit.Layers.Selection;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays
{
public class HitCircleOverlay : HitObjectOverlay
{
public HitCircleOverlay(DrawableHitCircle hitCircle)
: base(hitCircle)
{
Origin = Anchor.Centre;
Position = hitCircle.Position;
Size = hitCircle.Size;
Scale = hitCircle.Scale;
AddInternal(new RingPiece());
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Colour = colours.Yellow;
}
}
}

View File

@ -0,0 +1,45 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit.Layers.Selection;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using OpenTK;
namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays
{
public class SliderCircleOverlay : HitObjectOverlay
{
public SliderCircleOverlay(DrawableHitCircle sliderHead, DrawableSlider slider)
: this(sliderHead, sliderHead.Position, slider)
{
}
public SliderCircleOverlay(DrawableSliderTail sliderTail, DrawableSlider slider)
: this(sliderTail, ((Slider)slider.HitObject).Curve.PositionAt(1) + slider.HitObject.StackOffset, slider)
{
}
private SliderCircleOverlay(DrawableOsuHitObject hitObject, Vector2 position, DrawableSlider slider)
: base(hitObject)
{
Origin = Anchor.Centre;
Position = position;
Size = slider.HeadCircle.Size;
Scale = slider.HeadCircle.Scale;
AddInternal(new RingPiece());
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Colour = colours.Yellow;
}
}
}

View File

@ -0,0 +1,55 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit.Layers.Selection;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays
{
public class SliderOverlay : HitObjectOverlay
{
private readonly SliderBody body;
private readonly DrawableSlider hitObject;
public SliderOverlay(DrawableSlider slider)
: base(slider)
{
hitObject = slider;
var obj = (Slider)slider.HitObject;
InternalChildren = new Drawable[]
{
body = new SliderBody(obj)
{
AccentColour = Color4.Transparent,
Position = obj.StackedPosition,
PathWidth = obj.Scale * 64
},
new SliderCircleOverlay(slider.HeadCircle, slider),
new SliderCircleOverlay(slider.TailCircle, slider),
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
body.BorderColour = colours.Yellow;
}
protected override void Update()
{
base.Update();
hitObject.GetCurrentProgress(out int span, out double progress);
body.UpdateProgress(progress, span);
}
}
}

View File

@ -5,7 +5,9 @@ using System.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Layers.Selection;
using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Osu.Edit.Layers.Selection;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
@ -29,5 +31,7 @@ namespace osu.Game.Rulesets.Osu.Edit
}; };
protected override ScalableContainer CreateLayerContainer() => new ScalableContainer(OsuPlayfield.BASE_SIZE.X) { RelativeSizeAxes = Axes.Both }; protected override ScalableContainer CreateLayerContainer() => new ScalableContainer(OsuPlayfield.BASE_SIZE.X) { RelativeSizeAxes = Axes.Both };
protected override HitObjectOverlayLayer CreateHitObjectOverlayLayer() => new OsuHitObjectOverlayLayer();
} }
} }

View File

@ -21,6 +21,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private readonly List<Drawable> components = new List<Drawable>(); private readonly List<Drawable> components = new List<Drawable>();
public readonly DrawableHitCircle HeadCircle; public readonly DrawableHitCircle HeadCircle;
public readonly DrawableSliderTail TailCircle;
public readonly SliderBody Body; public readonly SliderBody Body;
public readonly SliderBall Ball; public readonly SliderBall Ball;
@ -29,7 +31,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
slider = s; slider = s;
DrawableSliderTail tail;
Container<DrawableSliderTick> ticks; Container<DrawableSliderTick> ticks;
Container<DrawableRepeatPoint> repeatPoints; Container<DrawableRepeatPoint> repeatPoints;
@ -51,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Alpha = 0 Alpha = 0
}, },
HeadCircle = new DrawableHitCircle(s.HeadCircle), HeadCircle = new DrawableHitCircle(s.HeadCircle),
tail = new DrawableSliderTail(s.TailCircle) TailCircle = new DrawableSliderTail(s.TailCircle)
}; };
components.Add(Body); components.Add(Body);
@ -59,8 +60,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
AddNested(HeadCircle); AddNested(HeadCircle);
AddNested(tail); AddNested(TailCircle);
components.Add(tail); components.Add(TailCircle);
foreach (var tick in s.NestedHitObjects.OfType<SliderTick>()) foreach (var tick in s.NestedHitObjects.OfType<SliderTick>())
{ {
@ -96,10 +97,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Tracking = Ball.Tracking; Tracking = Ball.Tracking;
double progress = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1); GetCurrentProgress(out int span, out double progress);
int span = slider.SpanAt(progress);
progress = slider.ProgressAt(progress);
if (span > currentSpan) if (span > currentSpan)
currentSpan = span; currentSpan = span;
@ -155,6 +153,19 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
} }
} }
/// <summary>
/// Finds the progress along the slider at the current time.
/// </summary>
/// <param name="span">The current span.</param>
/// <param name="progress">The current progress in the current span.</param>
public void GetCurrentProgress(out int span, out double progress)
{
double offset = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);
span = slider.SpanAt(offset);
progress = slider.ProgressAt(offset);
}
public Drawable ProxiedLayer => HeadCircle.ApproachCircle; public Drawable ProxiedLayer => HeadCircle.ApproachCircle;
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Body.ReceiveMouseInputAt(screenSpacePos); public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Body.ReceiveMouseInputAt(screenSpacePos);

View File

@ -64,6 +64,10 @@
<ItemGroup> <ItemGroup>
<Compile Include="Beatmaps\OsuBeatmapConverter.cs" /> <Compile Include="Beatmaps\OsuBeatmapConverter.cs" />
<Compile Include="Beatmaps\OsuBeatmapProcessor.cs" /> <Compile Include="Beatmaps\OsuBeatmapProcessor.cs" />
<Compile Include="Edit\Layers\Selection\OsuHitObjectOverlayLayer.cs" />
<Compile Include="Edit\Layers\Selection\Overlays\HitCircleOverlay.cs" />
<Compile Include="Edit\Layers\Selection\Overlays\SliderCircleOverlay.cs" />
<Compile Include="Edit\Layers\Selection\Overlays\SliderOverlay.cs" />
<Compile Include="Edit\OsuEditPlayfield.cs" /> <Compile Include="Edit\OsuEditPlayfield.cs" />
<Compile Include="Edit\OsuEditRulesetContainer.cs" /> <Compile Include="Edit\OsuEditRulesetContainer.cs" />
<Compile Include="Edit\OsuHitObjectComposer.cs" /> <Compile Include="Edit\OsuHitObjectComposer.cs" />

View File

@ -6,10 +6,13 @@ using System.Collections.Generic;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using OpenTK; using OpenTK;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Layers.Selection; using osu.Game.Rulesets.Edit.Layers.Selection;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Edit; using osu.Game.Rulesets.Osu.Edit;
using osu.Game.Rulesets.Osu.Edit.Layers.Selection;
using osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Tests.Beatmaps; using osu.Game.Tests.Beatmaps;
@ -21,7 +24,15 @@ namespace osu.Game.Tests.Visual
{ {
typeof(SelectionBox), typeof(SelectionBox),
typeof(SelectionLayer), typeof(SelectionLayer),
typeof(CaptureBox) typeof(CaptureBox),
typeof(HitObjectComposer),
typeof(OsuHitObjectComposer),
typeof(HitObjectOverlayLayer),
typeof(OsuHitObjectOverlayLayer),
typeof(HitObjectOverlay),
typeof(HitCircleOverlay),
typeof(SliderOverlay),
typeof(SliderCircleOverlay)
}; };
[BackgroundDependencyLoader] [BackgroundDependencyLoader]

View File

@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Edit
protected ICompositionTool CurrentTool { get; private set; } protected ICompositionTool CurrentTool { get; private set; }
private RulesetContainer rulesetContainer; private RulesetContainer rulesetContainer;
private readonly Container[] layerContainers = new Container[2]; private readonly ScalableContainer[] layerContainers = new ScalableContainer[2];
protected HitObjectComposer(Ruleset ruleset) protected HitObjectComposer(Ruleset ruleset)
{ {
@ -49,20 +49,6 @@ namespace osu.Game.Rulesets.Edit
return; return;
} }
layerContainers[0] = CreateLayerContainer();
layerContainers[0].Child = new Container
{
Name = "Border",
RelativeSizeAxes = Axes.Both,
Masking = true,
BorderColour = Color4.White,
BorderThickness = 2,
Child = new Box { RelativeSizeAxes = Axes.Both, Alpha = 0, AlwaysPresent = true }
};
layerContainers[1] = CreateLayerContainer();
layerContainers[1].Child = new SelectionLayer(rulesetContainer.Playfield);
RadioButtonCollection toolboxCollection; RadioButtonCollection toolboxCollection;
InternalChild = new GridContainer InternalChild = new GridContainer
{ {
@ -87,9 +73,9 @@ namespace osu.Game.Rulesets.Edit
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Children = new Drawable[] Children = new Drawable[]
{ {
layerContainers[0], createBottomLayer(),
rulesetContainer, rulesetContainer,
layerContainers[1] createTopLayer()
} }
} }
}, },
@ -112,6 +98,40 @@ namespace osu.Game.Rulesets.Edit
toolboxCollection.Items[0].Select(); toolboxCollection.Items[0].Select();
} }
private ScalableContainer createBottomLayer()
{
layerContainers[0] = CreateLayerContainer();
layerContainers[0].Child = new Container
{
Name = "Border",
RelativeSizeAxes = Axes.Both,
Masking = true,
BorderColour = Color4.White,
BorderThickness = 2,
Child = new Box { RelativeSizeAxes = Axes.Both, Alpha = 0, AlwaysPresent = true }
};
return layerContainers[0];
}
private ScalableContainer createTopLayer()
{
var overlayLayer = CreateHitObjectOverlayLayer();
var selectionLayer = new SelectionLayer(rulesetContainer.Playfield);
selectionLayer.ObjectSelected += overlayLayer.AddOverlay;
selectionLayer.ObjectDeselected += overlayLayer.RemoveOverlay;
layerContainers[1] = CreateLayerContainer();
layerContainers[1].Children = new Drawable[]
{
overlayLayer,
selectionLayer,
};
return layerContainers[1];
}
protected override void UpdateAfterChildren() protected override void UpdateAfterChildren()
{ {
base.UpdateAfterChildren(); base.UpdateAfterChildren();
@ -135,5 +155,10 @@ namespace osu.Game.Rulesets.Edit
/// Creates a <see cref="ScalableContainer"/> which provides a layer above or below the <see cref="Playfield"/>. /// Creates a <see cref="ScalableContainer"/> which provides a layer above or below the <see cref="Playfield"/>.
/// </summary> /// </summary>
protected virtual ScalableContainer CreateLayerContainer() => new ScalableContainer(); protected virtual ScalableContainer CreateLayerContainer() => new ScalableContainer();
/// <summary>
/// Creates the <see cref="HitObjectOverlayLayer"/> which overlays selected <see cref="DrawableHitObject"/>s.
/// </summary>
protected virtual HitObjectOverlayLayer CreateHitObjectOverlayLayer() => new HitObjectOverlayLayer();
} }
} }

View File

@ -0,0 +1,20 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Edit.Layers.Selection
{
public class HitObjectOverlay : CompositeDrawable
{
// ReSharper disable once NotAccessedField.Local
// This will be used later to handle drag movement, etc
private readonly DrawableHitObject hitObject;
public HitObjectOverlay(DrawableHitObject hitObject)
{
this.hitObject = hitObject;
}
}
}

View File

@ -0,0 +1,53 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Edit.Layers.Selection
{
public class HitObjectOverlayLayer : CompositeDrawable
{
private readonly Dictionary<DrawableHitObject, HitObjectOverlay> existingOverlays = new Dictionary<DrawableHitObject, HitObjectOverlay>();
public HitObjectOverlayLayer()
{
RelativeSizeAxes = Axes.Both;
}
/// <summary>
/// Adds an overlay for a <see cref="DrawableHitObject"/> which adds movement support.
/// </summary>
/// <param name="hitObject">The <see cref="DrawableHitObject"/> to create an overlay for.</param>
public void AddOverlay(DrawableHitObject hitObject)
{
var overlay = CreateOverlayFor(hitObject);
if (overlay == null)
return;
existingOverlays[hitObject] = overlay;
AddInternal(overlay);
}
/// <summary>
/// Removes the overlay for a <see cref="DrawableHitObject"/>.
/// </summary>
/// <param name="hitObject">The <see cref="DrawableHitObject"/> to remove the overlay for.</param>
public void RemoveOverlay(DrawableHitObject hitObject)
{
if (!existingOverlays.TryGetValue(hitObject, out var existing))
return;
existing.Hide();
existing.Expire();
}
/// <summary>
/// Creates a <see cref="HitObjectOverlay"/> for a specific <see cref="DrawableHitObject"/>.
/// </summary>
/// <param name="hitObject">The <see cref="DrawableHitObject"/> to create the overlay for.</param>
protected virtual HitObjectOverlay CreateOverlayFor(DrawableHitObject hitObject) => null;
}
}

View File

@ -347,6 +347,8 @@
<Compile Include="Rulesets\Configuration\IRulesetConfigManager.cs" /> <Compile Include="Rulesets\Configuration\IRulesetConfigManager.cs" />
<Compile Include="Rulesets\Configuration\RulesetConfigManager.cs" /> <Compile Include="Rulesets\Configuration\RulesetConfigManager.cs" />
<Compile Include="Rulesets\Edit\Layers\Selection\CaptureBox.cs" /> <Compile Include="Rulesets\Edit\Layers\Selection\CaptureBox.cs" />
<Compile Include="Rulesets\Edit\Layers\Selection\HitObjectOverlay.cs" />
<Compile Include="Rulesets\Edit\Layers\Selection\HitObjectOverlayLayer.cs" />
<Compile Include="Rulesets\Mods\IApplicableFailOverride.cs" /> <Compile Include="Rulesets\Mods\IApplicableFailOverride.cs" />
<Compile Include="Rulesets\Mods\IApplicableMod.cs" /> <Compile Include="Rulesets\Mods\IApplicableMod.cs" />
<Compile Include="Rulesets\Mods\IApplicableToBeatmapConverter.cs" /> <Compile Include="Rulesets\Mods\IApplicableToBeatmapConverter.cs" />