mirror of
https://github.com/ppy/osu.git
synced 2025-02-14 21:23:19 +08:00
Merge pull request #9146 from peppy/taiko-editor
Implement osu!taiko editor
This commit is contained in:
commit
a3e31adbf9
17
osu.Game.Rulesets.Taiko.Tests/TestSceneEditor.cs
Normal file
17
osu.Game.Rulesets.Taiko.Tests/TestSceneEditor.cs
Normal file
@ -0,0 +1,17 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneEditor : EditorTestScene
|
||||
{
|
||||
public TestSceneEditor()
|
||||
: base(new TaikoRuleset())
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Taiko.Beatmaps;
|
||||
using osu.Game.Rulesets.Taiko.Edit;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Tests
|
||||
{
|
||||
public class TestSceneTaikoHitObjectComposer : EditorClockTestScene
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
{
|
||||
BeatDivisor.Value = 8;
|
||||
Clock.Seek(0);
|
||||
|
||||
Child = new TestComposer { RelativeSizeAxes = Axes.Both };
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void BasicTest()
|
||||
{
|
||||
}
|
||||
|
||||
private class TestComposer : CompositeDrawable
|
||||
{
|
||||
[Cached(typeof(EditorBeatmap))]
|
||||
[Cached(typeof(IBeatSnapProvider))]
|
||||
public readonly EditorBeatmap EditorBeatmap;
|
||||
|
||||
public TestComposer()
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
EditorBeatmap = new EditorBeatmap(new TaikoBeatmap())
|
||||
{
|
||||
BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo }
|
||||
},
|
||||
new TaikoHitObjectComposer(new TaikoRuleset())
|
||||
};
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
EditorBeatmap.Add(new Hit { StartTime = 125 * i });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
// 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.Taiko.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Edit.Blueprints
|
||||
{
|
||||
public class DrumRollPlacementBlueprint : TaikoSpanPlacementBlueprint
|
||||
{
|
||||
public DrumRollPlacementBlueprint()
|
||||
: base(new DrumRoll())
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
35
osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPiece.cs
Normal file
35
osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPiece.cs
Normal file
@ -0,0 +1,35 @@
|
||||
// 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;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Edit.Blueprints
|
||||
{
|
||||
public class HitPiece : CompositeDrawable
|
||||
{
|
||||
public HitPiece()
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
InternalChild = new CircularContainer
|
||||
{
|
||||
Masking = true,
|
||||
BorderThickness = 10,
|
||||
BorderColour = Color4.Yellow,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
AlwaysPresent = true,
|
||||
Alpha = 0,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
// 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.Input.Events;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Rulesets.Taiko.UI;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Edit.Blueprints
|
||||
{
|
||||
public class HitPlacementBlueprint : PlacementBlueprint
|
||||
{
|
||||
private readonly HitPiece piece;
|
||||
|
||||
private static Hit hit;
|
||||
|
||||
public HitPlacementBlueprint()
|
||||
: base(hit = new Hit())
|
||||
{
|
||||
InternalChild = piece = new HitPiece
|
||||
{
|
||||
Size = new Vector2(TaikoHitObject.DEFAULT_SIZE * TaikoPlayfield.DEFAULT_HEIGHT)
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
{
|
||||
switch (e.Button)
|
||||
{
|
||||
case MouseButton.Left:
|
||||
hit.Type = HitType.Centre;
|
||||
EndPlacement(true);
|
||||
return true;
|
||||
|
||||
case MouseButton.Right:
|
||||
hit.Type = HitType.Rim;
|
||||
EndPlacement(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void UpdatePosition(SnapResult result)
|
||||
{
|
||||
piece.Position = ToLocalSpace(result.ScreenSpacePosition);
|
||||
base.UpdatePosition(result);
|
||||
}
|
||||
}
|
||||
}
|
40
osu.Game.Rulesets.Taiko/Edit/Blueprints/LengthPiece.cs
Normal file
40
osu.Game.Rulesets.Taiko/Edit/Blueprints/LengthPiece.cs
Normal file
@ -0,0 +1,40 @@
|
||||
// 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;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Edit.Blueprints
|
||||
{
|
||||
public class LengthPiece : CompositeDrawable
|
||||
{
|
||||
public LengthPiece()
|
||||
{
|
||||
Origin = Anchor.CentreLeft;
|
||||
|
||||
InternalChild = new Container
|
||||
{
|
||||
Masking = true,
|
||||
Colour = Color4.Yellow,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 8,
|
||||
},
|
||||
new Box
|
||||
{
|
||||
Origin = Anchor.BottomLeft,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 8,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
// 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.Taiko.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Edit.Blueprints
|
||||
{
|
||||
public class SwellPlacementBlueprint : TaikoSpanPlacementBlueprint
|
||||
{
|
||||
public SwellPlacementBlueprint()
|
||||
: base(new Swell())
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
// 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;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Edit.Blueprints
|
||||
{
|
||||
public class TaikoSelectionBlueprint : OverlaySelectionBlueprint
|
||||
{
|
||||
public TaikoSelectionBlueprint(DrawableHitObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
RelativeSizeAxes = Axes.None;
|
||||
|
||||
AddInternal(new HitPiece
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Origin = Anchor.TopLeft
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
// Move the rectangle to cover the hitobjects
|
||||
var topLeft = new Vector2(float.MaxValue, float.MaxValue);
|
||||
var bottomRight = new Vector2(float.MinValue, float.MinValue);
|
||||
|
||||
topLeft = Vector2.ComponentMin(topLeft, Parent.ToLocalSpace(DrawableObject.ScreenSpaceDrawQuad.TopLeft));
|
||||
bottomRight = Vector2.ComponentMax(bottomRight, Parent.ToLocalSpace(DrawableObject.ScreenSpaceDrawQuad.BottomRight));
|
||||
|
||||
Size = bottomRight - topLeft;
|
||||
Position = topLeft;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
// 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 System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Rulesets.Taiko.UI;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Edit.Blueprints
|
||||
{
|
||||
public class TaikoSpanPlacementBlueprint : PlacementBlueprint
|
||||
{
|
||||
private readonly HitPiece headPiece;
|
||||
private readonly HitPiece tailPiece;
|
||||
|
||||
private readonly LengthPiece lengthPiece;
|
||||
|
||||
private readonly IHasDuration spanPlacementObject;
|
||||
|
||||
public TaikoSpanPlacementBlueprint(HitObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
spanPlacementObject = hitObject as IHasDuration;
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
headPiece = new HitPiece
|
||||
{
|
||||
Size = new Vector2(TaikoHitObject.DEFAULT_SIZE * TaikoPlayfield.DEFAULT_HEIGHT)
|
||||
},
|
||||
lengthPiece = new LengthPiece
|
||||
{
|
||||
Height = TaikoHitObject.DEFAULT_SIZE * TaikoPlayfield.DEFAULT_HEIGHT
|
||||
},
|
||||
tailPiece = new HitPiece
|
||||
{
|
||||
Size = new Vector2(TaikoHitObject.DEFAULT_SIZE * TaikoPlayfield.DEFAULT_HEIGHT)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private double originalStartTime;
|
||||
private Vector2 originalPosition;
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
{
|
||||
if (e.Button != MouseButton.Left)
|
||||
return false;
|
||||
|
||||
BeginPlacement(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(MouseUpEvent e)
|
||||
{
|
||||
if (e.Button != MouseButton.Left)
|
||||
return;
|
||||
|
||||
base.OnMouseUp(e);
|
||||
EndPlacement(true);
|
||||
}
|
||||
|
||||
public override void UpdatePosition(SnapResult result)
|
||||
{
|
||||
base.UpdatePosition(result);
|
||||
|
||||
if (PlacementActive)
|
||||
{
|
||||
if (result.Time is double dragTime)
|
||||
{
|
||||
if (dragTime < originalStartTime)
|
||||
{
|
||||
HitObject.StartTime = dragTime;
|
||||
spanPlacementObject.Duration = Math.Abs(dragTime - originalStartTime);
|
||||
headPiece.Position = ToLocalSpace(result.ScreenSpacePosition);
|
||||
tailPiece.Position = originalPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
HitObject.StartTime = originalStartTime;
|
||||
spanPlacementObject.Duration = Math.Abs(dragTime - originalStartTime);
|
||||
tailPiece.Position = ToLocalSpace(result.ScreenSpacePosition);
|
||||
headPiece.Position = originalPosition;
|
||||
}
|
||||
|
||||
lengthPiece.X = headPiece.X;
|
||||
lengthPiece.Width = tailPiece.X - headPiece.X;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lengthPiece.Position = headPiece.Position = tailPiece.Position = ToLocalSpace(result.ScreenSpacePosition);
|
||||
|
||||
if (result.Time is double startTime)
|
||||
{
|
||||
originalStartTime = HitObject.StartTime = startTime;
|
||||
originalPosition = ToLocalSpace(result.ScreenSpacePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
osu.Game.Rulesets.Taiko/Edit/DrumRollCompositionTool.cs
Normal file
20
osu.Game.Rulesets.Taiko/Edit/DrumRollCompositionTool.cs
Normal file
@ -0,0 +1,20 @@
|
||||
// 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.Edit;
|
||||
using osu.Game.Rulesets.Edit.Tools;
|
||||
using osu.Game.Rulesets.Taiko.Edit.Blueprints;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Edit
|
||||
{
|
||||
public class DrumRollCompositionTool : HitObjectCompositionTool
|
||||
{
|
||||
public DrumRollCompositionTool()
|
||||
: base(nameof(DrumRoll))
|
||||
{
|
||||
}
|
||||
|
||||
public override PlacementBlueprint CreatePlacementBlueprint() => new DrumRollPlacementBlueprint();
|
||||
}
|
||||
}
|
20
osu.Game.Rulesets.Taiko/Edit/HitCompositionTool.cs
Normal file
20
osu.Game.Rulesets.Taiko/Edit/HitCompositionTool.cs
Normal file
@ -0,0 +1,20 @@
|
||||
// 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.Edit;
|
||||
using osu.Game.Rulesets.Edit.Tools;
|
||||
using osu.Game.Rulesets.Taiko.Edit.Blueprints;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Edit
|
||||
{
|
||||
public class HitCompositionTool : HitObjectCompositionTool
|
||||
{
|
||||
public HitCompositionTool()
|
||||
: base(nameof(Hit))
|
||||
{
|
||||
}
|
||||
|
||||
public override PlacementBlueprint CreatePlacementBlueprint() => new HitPlacementBlueprint();
|
||||
}
|
||||
}
|
20
osu.Game.Rulesets.Taiko/Edit/SwellCompositionTool.cs
Normal file
20
osu.Game.Rulesets.Taiko/Edit/SwellCompositionTool.cs
Normal file
@ -0,0 +1,20 @@
|
||||
// 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.Edit;
|
||||
using osu.Game.Rulesets.Edit.Tools;
|
||||
using osu.Game.Rulesets.Taiko.Edit.Blueprints;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Edit
|
||||
{
|
||||
public class SwellCompositionTool : HitObjectCompositionTool
|
||||
{
|
||||
public SwellCompositionTool()
|
||||
: base(nameof(Swell))
|
||||
{
|
||||
}
|
||||
|
||||
public override PlacementBlueprint CreatePlacementBlueprint() => new SwellPlacementBlueprint();
|
||||
}
|
||||
}
|
24
osu.Game.Rulesets.Taiko/Edit/TaikoBlueprintContainer.cs
Normal file
24
osu.Game.Rulesets.Taiko/Edit/TaikoBlueprintContainer.cs
Normal file
@ -0,0 +1,24 @@
|
||||
// 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 System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Edit.Blueprints;
|
||||
using osu.Game.Screens.Edit.Compose.Components;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Edit
|
||||
{
|
||||
public class TaikoBlueprintContainer : ComposeBlueprintContainer
|
||||
{
|
||||
public TaikoBlueprintContainer(IEnumerable<DrawableHitObject> hitObjects)
|
||||
: base(hitObjects)
|
||||
{
|
||||
}
|
||||
|
||||
protected override SelectionHandler CreateSelectionHandler() => new TaikoSelectionHandler();
|
||||
|
||||
public override OverlaySelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject) =>
|
||||
new TaikoSelectionBlueprint(hitObject);
|
||||
}
|
||||
}
|
30
osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs
Normal file
30
osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs
Normal file
@ -0,0 +1,30 @@
|
||||
// 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 System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Edit.Tools;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Screens.Edit.Compose.Components;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Edit
|
||||
{
|
||||
public class TaikoHitObjectComposer : HitObjectComposer<TaikoHitObject>
|
||||
{
|
||||
public TaikoHitObjectComposer(TaikoRuleset ruleset)
|
||||
: base(ruleset)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => new HitObjectCompositionTool[]
|
||||
{
|
||||
new HitCompositionTool(),
|
||||
new DrumRollCompositionTool(),
|
||||
new SwellCompositionTool()
|
||||
};
|
||||
|
||||
protected override ComposeBlueprintContainer CreateBlueprintContainer(IEnumerable<DrawableHitObject> hitObjects)
|
||||
=> new TaikoBlueprintContainer(hitObjects);
|
||||
}
|
||||
}
|
80
osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs
Normal file
80
osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs
Normal file
@ -0,0 +1,80 @@
|
||||
// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Screens.Edit.Compose.Components;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Edit
|
||||
{
|
||||
public class TaikoSelectionHandler : SelectionHandler
|
||||
{
|
||||
protected override IEnumerable<MenuItem> GetContextMenuItemsForSelection(IEnumerable<SelectionBlueprint> selection)
|
||||
{
|
||||
if (selection.All(s => s.HitObject is Hit))
|
||||
{
|
||||
var hits = selection.Select(s => s.HitObject).OfType<Hit>();
|
||||
|
||||
yield return new TernaryStateMenuItem("Rim", action: state =>
|
||||
{
|
||||
foreach (var h in hits)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case TernaryState.True:
|
||||
h.Type = HitType.Rim;
|
||||
break;
|
||||
|
||||
case TernaryState.False:
|
||||
h.Type = HitType.Centre;
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
{
|
||||
State = { Value = getTernaryState(hits, h => h.Type == HitType.Rim) }
|
||||
};
|
||||
}
|
||||
|
||||
if (selection.All(s => s.HitObject is TaikoHitObject))
|
||||
{
|
||||
var hits = selection.Select(s => s.HitObject).OfType<TaikoHitObject>();
|
||||
|
||||
yield return new TernaryStateMenuItem("Strong", action: state =>
|
||||
{
|
||||
foreach (var h in hits)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case TernaryState.True:
|
||||
h.IsStrong = true;
|
||||
break;
|
||||
|
||||
case TernaryState.False:
|
||||
h.IsStrong = false;
|
||||
break;
|
||||
}
|
||||
|
||||
EditorBeatmap?.UpdateHitObject(h);
|
||||
}
|
||||
})
|
||||
{
|
||||
State = { Value = getTernaryState(hits, h => h.IsStrong) }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private TernaryState getTernaryState<T>(IEnumerable<T> selection, Func<T, bool> func)
|
||||
{
|
||||
if (selection.Any(func))
|
||||
return selection.All(func) ? TernaryState.True : TernaryState.Indeterminate;
|
||||
|
||||
return TernaryState.False;
|
||||
}
|
||||
}
|
||||
}
|
@ -48,12 +48,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
colourIdle = colours.YellowDark;
|
||||
colourEngaged = colours.YellowDarker;
|
||||
|
||||
updateColour();
|
||||
|
||||
Content.Add(tickContainer = new Container { RelativeSizeAxes = Axes.Both });
|
||||
|
||||
if (MainPiece.Drawable is IHasAccentColour accentMain)
|
||||
accentMain.AccentColour = colourIdle;
|
||||
Content.Add(tickContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Depth = float.MinValue
|
||||
});
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
@ -63,6 +62,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
OnNewResult += onNewResult;
|
||||
}
|
||||
|
||||
protected override void RecreatePieces()
|
||||
{
|
||||
base.RecreatePieces();
|
||||
updateColour();
|
||||
}
|
||||
|
||||
protected override void AddNestedHitObject(DrawableHitObject hitObject)
|
||||
{
|
||||
base.AddNestedHitObject(hitObject);
|
||||
|
@ -5,6 +5,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
@ -19,7 +21,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
/// <summary>
|
||||
/// A list of keys which can result in hits for this HitObject.
|
||||
/// </summary>
|
||||
public TaikoAction[] HitActions { get; }
|
||||
public TaikoAction[] HitActions { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action that caused this <see cref="DrawableHit"/> to be hit.
|
||||
@ -34,15 +36,35 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
|
||||
private bool pressHandledThisFrame;
|
||||
|
||||
private Bindable<HitType> type;
|
||||
|
||||
public DrawableHit(Hit hit)
|
||||
: base(hit)
|
||||
{
|
||||
FillMode = FillMode.Fit;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
type = HitObject.TypeBindable.GetBoundCopy();
|
||||
type.BindValueChanged(_ =>
|
||||
{
|
||||
updateType();
|
||||
RecreatePieces();
|
||||
});
|
||||
|
||||
updateType();
|
||||
}
|
||||
|
||||
private void updateType()
|
||||
{
|
||||
HitActions =
|
||||
HitObject.Type == HitType.Centre
|
||||
? new[] { TaikoAction.LeftCentre, TaikoAction.RightCentre }
|
||||
: new[] { TaikoAction.LeftRim, TaikoAction.RightRim };
|
||||
|
||||
RecreatePieces();
|
||||
}
|
||||
|
||||
protected override SkinnableDrawable CreateMainPiece() => HitObject.Type == HitType.Centre
|
||||
|
@ -8,6 +8,8 @@ using osuTK;
|
||||
using System.Linq;
|
||||
using osu.Game.Audio;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -115,8 +117,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
|
||||
public new TObject HitObject;
|
||||
|
||||
protected readonly Vector2 BaseSize;
|
||||
protected readonly SkinnableDrawable MainPiece;
|
||||
protected Vector2 BaseSize;
|
||||
protected SkinnableDrawable MainPiece;
|
||||
|
||||
private Bindable<bool> isStrong;
|
||||
|
||||
private readonly Container<DrawableStrongNestedHit> strongHitContainer;
|
||||
|
||||
@ -129,13 +133,25 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
Origin = Anchor.Custom;
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Size = BaseSize = new Vector2(HitObject.IsStrong ? TaikoHitObject.DEFAULT_STRONG_SIZE : TaikoHitObject.DEFAULT_SIZE);
|
||||
|
||||
Content.Add(MainPiece = CreateMainPiece());
|
||||
|
||||
AddInternal(strongHitContainer = new Container<DrawableStrongNestedHit>());
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
isStrong = HitObject.IsStrongBindable.GetBoundCopy();
|
||||
isStrong.BindValueChanged(_ => RecreatePieces(), true);
|
||||
}
|
||||
|
||||
protected virtual void RecreatePieces()
|
||||
{
|
||||
Size = BaseSize = new Vector2(HitObject.IsStrong ? TaikoHitObject.DEFAULT_STRONG_SIZE : TaikoHitObject.DEFAULT_SIZE);
|
||||
|
||||
MainPiece?.Expire();
|
||||
Content.Add(MainPiece = CreateMainPiece());
|
||||
}
|
||||
|
||||
protected override void AddNestedHitObject(DrawableHitObject hitObject)
|
||||
{
|
||||
base.AddNestedHitObject(hitObject);
|
||||
|
@ -1,13 +1,21 @@
|
||||
// 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.Bindables;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects
|
||||
{
|
||||
public class Hit : TaikoHitObject
|
||||
{
|
||||
public readonly Bindable<HitType> TypeBindable = new Bindable<HitType>();
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="HitType"/> that actuates this <see cref="Hit"/>.
|
||||
/// </summary>
|
||||
public HitType Type { get; set; }
|
||||
public HitType Type
|
||||
{
|
||||
get => TypeBindable.Value;
|
||||
set => TypeBindable.Value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
// 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 System;
|
||||
using System.Threading;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
@ -25,11 +24,6 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
/// </summary>
|
||||
public int RequiredHits = 10;
|
||||
|
||||
public override bool IsStrong
|
||||
{
|
||||
set => throw new NotSupportedException($"{nameof(Swell)} cannot be a strong hitobject.");
|
||||
}
|
||||
|
||||
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
|
||||
{
|
||||
base.CreateNestedHitObjects(cancellationToken);
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Threading;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -27,11 +28,17 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
/// </summary>
|
||||
public const float DEFAULT_STRONG_SIZE = DEFAULT_SIZE * STRONG_SCALE;
|
||||
|
||||
public readonly Bindable<bool> IsStrongBindable = new BindableBool();
|
||||
|
||||
/// <summary>
|
||||
/// Whether this HitObject is a "strong" type.
|
||||
/// Strong hit objects give more points for hitting the hit object with both keys.
|
||||
/// </summary>
|
||||
public virtual bool IsStrong { get; set; }
|
||||
public bool IsStrong
|
||||
{
|
||||
get => IsStrongBindable.Value;
|
||||
set => IsStrongBindable.Value = value;
|
||||
}
|
||||
|
||||
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
|
||||
{
|
||||
|
@ -21,6 +21,8 @@ using osu.Game.Rulesets.Taiko.Difficulty;
|
||||
using osu.Game.Rulesets.Taiko.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using System;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Taiko.Edit;
|
||||
using osu.Game.Rulesets.Taiko.Skinning;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
@ -144,6 +146,8 @@ namespace osu.Game.Rulesets.Taiko
|
||||
|
||||
public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetTaiko };
|
||||
|
||||
public override HitObjectComposer CreateHitObjectComposer() => new TaikoHitObjectComposer(this);
|
||||
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(this, beatmap);
|
||||
|
||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new TaikoPerformanceCalculator(this, beatmap, score);
|
||||
|
@ -11,23 +11,13 @@ namespace osu.Game.Graphics.UserInterface
|
||||
/// </summary>
|
||||
public class TernaryStateMenuItem : StatefulMenuItem<TernaryState>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="TernaryStateMenuItem"/>.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to display.</param>
|
||||
/// <param name="type">The type of action which this <see cref="TernaryStateMenuItem"/> performs.</param>
|
||||
public TernaryStateMenuItem(string text, MenuItemType type = MenuItemType.Standard)
|
||||
: this(text, type, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="TernaryStateMenuItem"/>.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to display.</param>
|
||||
/// <param name="type">The type of action which this <see cref="TernaryStateMenuItem"/> performs.</param>
|
||||
/// <param name="action">A delegate to be invoked when this <see cref="TernaryStateMenuItem"/> is pressed.</param>
|
||||
public TernaryStateMenuItem(string text, MenuItemType type, Action<TernaryState> action)
|
||||
public TernaryStateMenuItem(string text, MenuItemType type = MenuItemType.Standard, Action<TernaryState> action = null)
|
||||
: this(text, getNextState, type, action)
|
||||
{
|
||||
}
|
||||
|
@ -87,11 +87,11 @@ namespace osu.Game.Rulesets.Edit
|
||||
/// <summary>
|
||||
/// Updates the position of this <see cref="PlacementBlueprint"/> to a new screen-space position.
|
||||
/// </summary>
|
||||
/// <param name="snapResult">The snap result information.</param>
|
||||
public virtual void UpdatePosition(SnapResult snapResult)
|
||||
/// <param name="result">The snap result information.</param>
|
||||
public virtual void UpdatePosition(SnapResult result)
|
||||
{
|
||||
if (!PlacementActive)
|
||||
HitObject.StartTime = snapResult.Time ?? EditorClock?.CurrentTime ?? Time.Current;
|
||||
HitObject.StartTime = result.Time ?? EditorClock?.CurrentTime ?? Time.Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
private Drawable outline;
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private EditorBeatmap editorBeatmap { get; set; }
|
||||
protected EditorBeatmap EditorBeatmap { get; private set; }
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IEditorChangeHandler changeHandler { get; set; }
|
||||
@ -117,7 +117,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
internal void HandleSelected(SelectionBlueprint blueprint)
|
||||
{
|
||||
selectedBlueprints.Add(blueprint);
|
||||
editorBeatmap.SelectedHitObjects.Add(blueprint.HitObject);
|
||||
EditorBeatmap.SelectedHitObjects.Add(blueprint.HitObject);
|
||||
|
||||
UpdateVisibility();
|
||||
}
|
||||
@ -129,7 +129,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
internal void HandleDeselected(SelectionBlueprint blueprint)
|
||||
{
|
||||
selectedBlueprints.Remove(blueprint);
|
||||
editorBeatmap.SelectedHitObjects.Remove(blueprint.HitObject);
|
||||
EditorBeatmap.SelectedHitObjects.Remove(blueprint.HitObject);
|
||||
|
||||
// We don't want to update visibility if > 0, since we may be deselecting blueprints during drag-selection
|
||||
if (selectedBlueprints.Count == 0)
|
||||
@ -165,7 +165,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
changeHandler?.BeginChange();
|
||||
|
||||
foreach (var h in selectedBlueprints.ToList())
|
||||
editorBeatmap?.Remove(h.HitObject);
|
||||
EditorBeatmap?.Remove(h.HitObject);
|
||||
|
||||
changeHandler?.EndChange();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user