1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-06 06:57:39 +08:00

Re-implement composition tools + implement placement masks

This commit is contained in:
smoogipoo 2018-10-03 16:27:26 +09:00
parent 540a010fbb
commit 3420e0c7eb
9 changed files with 171 additions and 38 deletions

View File

@ -1,10 +1,10 @@
// 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;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Objects.Drawables;
using System.Collections.Generic;
@ -33,11 +33,7 @@ namespace osu.Game.Rulesets.Mania.Edit
protected override EditRulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new ManiaEditRulesetContainer(ruleset, beatmap);
protected override IReadOnlyList<ICompositionTool> CompositionTools => new ICompositionTool[]
{
new HitObjectCompositionTool<Note>("Note"),
new HitObjectCompositionTool<HoldNote>("Hold"),
};
protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => Array.Empty<HitObjectCompositionTool>();
public override SelectionMask CreateMaskFor(DrawableHitObject hitObject)
{

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.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Osu.Edit.Masks;
using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Edit
{
public class HitCircleCompositionTool : HitObjectCompositionTool
{
public HitCircleCompositionTool()
: base(nameof(HitCircle))
{
}
public override PlacementMask CreatePlacementMask() => new HitCirclePlacementMask();
}
}

View File

@ -13,13 +13,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks
{
public class HitCircleMask : CompositeDrawable
{
private readonly HitCircle hitCircle;
public HitCircleMask(HitCircle hitCircle)
{
this.hitCircle = hitCircle;
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Size = new Vector2((float)OsuHitObject.OBJECT_RADIUS * 2);
Scale = new Vector2(hitCircle.Scale);
CornerRadius = Size.X / 2;
@ -31,5 +33,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks
{
Colour = colours.Yellow;
}
protected override void Update()
{
base.Update();
Scale = new Vector2(hitCircle.Scale);
}
}
}

View File

@ -0,0 +1,36 @@
// 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.Input.Events;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Edit.Masks
{
public class HitCirclePlacementMask : PlacementMask
{
public new HitCircle HitObject => (HitCircle)base.HitObject;
public HitCirclePlacementMask()
: base(new HitCircle())
{
Origin = Anchor.Centre;
AutoSizeAxes = Axes.Both;
InternalChild = new HitCircleMask(HitObject);
}
protected override bool OnClick(ClickEvent e)
{
Finish();
return true;
}
protected override bool OnMouseMove(MouseMoveEvent e)
{
HitObject.Position = e.MousePosition;
return base.OnMouseMove(e);
}
}
}

View File

@ -3,13 +3,11 @@
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Input.Events;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Edit.Masks;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.UI;
@ -25,11 +23,9 @@ namespace osu.Game.Rulesets.Osu.Edit
protected override EditRulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new OsuEditRulesetContainer(ruleset, beatmap);
protected override IReadOnlyList<ICompositionTool> CompositionTools => new ICompositionTool[]
protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => new[]
{
new HitObjectCompositionTool<HitCircle>(),
new HitObjectCompositionTool<Slider>(),
new HitObjectCompositionTool<Spinner>()
new HitCircleCompositionTool(),
};
protected override ScalableContainer CreateLayerContainer() => new ScalableContainer(OsuPlayfield.BASE_SIZE.X) { RelativeSizeAxes = Axes.Both };

View File

@ -26,12 +26,12 @@ namespace osu.Game.Rulesets.Edit
public IEnumerable<DrawableHitObject> HitObjects => rulesetContainer.Playfield.AllHitObjects;
protected ICompositionTool CurrentTool { get; private set; }
protected IRulesetConfigManager Config { get; private set; }
private readonly List<Container> layerContainers = new List<Container>();
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
private Container placementContainer;
private EditRulesetContainer rulesetContainer;
protected HitObjectComposer(Ruleset ruleset)
@ -64,7 +64,11 @@ namespace osu.Game.Rulesets.Edit
};
var layerAboveRuleset = CreateLayerContainer();
layerAboveRuleset.Child = new HitObjectMaskLayer();
layerAboveRuleset.Children = new Drawable[]
{
new HitObjectMaskLayer(),
placementContainer = new Container { RelativeSizeAxes = Axes.Both }
};
layerContainers.Add(layerBelowRuleset);
layerContainers.Add(layerAboveRuleset);
@ -144,11 +148,28 @@ namespace osu.Game.Rulesets.Edit
});
}
private void setCompositionTool(ICompositionTool tool) => CurrentTool = tool;
private void setCompositionTool(HitObjectCompositionTool tool)
{
placementContainer.Clear(true);
if (tool != null)
{
var mask = tool.CreatePlacementMask();
mask.PlacementFinished += h =>
{
rulesetContainer.AddHitObject(h);
// Re-construct the mask
setCompositionTool(tool);
};
placementContainer.Child = mask;
}
}
protected abstract EditRulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap);
protected abstract IReadOnlyList<ICompositionTool> CompositionTools { get; }
protected abstract IReadOnlyList<HitObjectCompositionTool> CompositionTools { get; }
/// <summary>
/// Creates a <see cref="SelectionMask"/> for a specific <see cref="DrawableHitObject"/>.

View File

@ -0,0 +1,71 @@
// 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;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Framework.Input.Events;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects;
using OpenTK;
namespace osu.Game.Rulesets.Edit
{
public class PlacementMask : CompositeDrawable, IRequireHighFrequencyMousePosition
{
/// <summary>
/// Invoked when the placement of <see cref="HitObject"/> has finished.
/// </summary>
public event Action<HitObject> PlacementFinished;
/// <summary>
/// The <see cref="HitObject"/> that is being placed.
/// </summary>
protected readonly HitObject HitObject;
public PlacementMask(HitObject hitObject)
{
HitObject = hitObject;
}
[BackgroundDependencyLoader]
private void load(IBindableBeatmap workingBeatmap)
{
HitObject.ApplyDefaults(workingBeatmap.Value.Beatmap.ControlPointInfo, workingBeatmap.Value.Beatmap.BeatmapInfo.BaseDifficulty);
}
/// <summary>
/// Finishes the placement of <see cref="HitObject"/>.
/// </summary>
public void Finish() => PlacementFinished?.Invoke(HitObject);
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent?.ReceivePositionalInputAt(screenSpacePos) ?? false;
protected override bool Handle(UIEvent e)
{
base.Handle(e);
switch (e)
{
case MouseEvent _:
return true;
default:
return false;
}
}
protected override bool OnMouseMove(MouseMoveEvent e)
{
Position = e.MousePosition;
return true;
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
PlacementFinished = null;
}
}
}

View File

@ -1,23 +1,17 @@
// 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.Objects;
namespace osu.Game.Rulesets.Edit.Tools
{
public class HitObjectCompositionTool<T> : ICompositionTool
where T : HitObject
public abstract class HitObjectCompositionTool
{
public string Name { get; }
public readonly string Name;
public HitObjectCompositionTool()
: this(typeof(T).Name)
{
}
public HitObjectCompositionTool(string name)
protected HitObjectCompositionTool(string name)
{
Name = name;
}
public abstract PlacementMask CreatePlacementMask();
}
}

View File

@ -1,10 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Edit.Tools
{
public interface ICompositionTool
{
string Name { get; }
}
}