1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-22 18:03:21 +08:00

Allow toggling SVs in the editor

This commit is contained in:
Dan Balasescu 2023-08-15 20:38:17 +09:00 committed by Dean Herbert
parent ec9e7f14a8
commit a2fd7707a1
13 changed files with 98 additions and 50 deletions

View File

@ -21,8 +21,6 @@ namespace osu.Game.Rulesets.Catch.UI
{ {
public partial class DrawableCatchRuleset : DrawableScrollingRuleset<CatchHitObject> public partial class DrawableCatchRuleset : DrawableScrollingRuleset<CatchHitObject>
{ {
protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Constant;
protected override bool UserScrollSpeedAdjustment => false; protected override bool UserScrollSpeedAdjustment => false;
public DrawableCatchRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod>? mods = null) public DrawableCatchRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod>? mods = null)
@ -30,6 +28,7 @@ namespace osu.Game.Rulesets.Catch.UI
{ {
Direction.Value = ScrollingDirection.Down; Direction.Value = ScrollingDirection.Down;
TimeRange.Value = GetTimeRange(beatmap.Difficulty.ApproachRate); TimeRange.Value = GetTimeRange(beatmap.Difficulty.ApproachRate);
VisualisationMethod = ScrollVisualisationMethod.Constant;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]

View File

@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction; IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction;
IBindable<double> IScrollingInfo.TimeRange { get; } = new Bindable<double>(5000); IBindable<double> IScrollingInfo.TimeRange { get; } = new Bindable<double>(5000);
IScrollAlgorithm IScrollingInfo.Algorithm { get; } = new ConstantScrollAlgorithm(); IBindable<IScrollAlgorithm> IScrollingInfo.Algorithm { get; } = new Bindable<IScrollAlgorithm>(new ConstantScrollAlgorithm());
} }
} }
} }

View File

@ -2,10 +2,12 @@
// 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 System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osuTK; using osuTK;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
@ -15,12 +17,25 @@ namespace osu.Game.Rulesets.Mania.Edit
{ {
public partial class DrawableManiaEditorRuleset : DrawableManiaRuleset public partial class DrawableManiaEditorRuleset : DrawableManiaRuleset
{ {
public readonly IBindable<TernaryState> ShowSpeedChanges = new Bindable<TernaryState>();
public new IScrollingInfo ScrollingInfo => base.ScrollingInfo; public new IScrollingInfo ScrollingInfo => base.ScrollingInfo;
public DrawableManiaEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod>? mods) public DrawableManiaEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod>? mods)
: base(ruleset, beatmap, mods) : base(ruleset, beatmap, mods)
{ {
ScrollMethod = ScrollVisualisationMethod.Constant; }
protected override void LoadComplete()
{
base.LoadComplete();
ShowSpeedChanges.BindValueChanged(state =>
{
VisualisationMethod = state.NewValue == TernaryState.True
? ScrollVisualisationMethod.Sequential
: ScrollVisualisationMethod.Constant;
}, true);
} }
protected override Playfield CreatePlayfield() => new ManiaEditorPlayfield(Beatmap.Stages) protected override Playfield CreatePlayfield() => new ManiaEditorPlayfield(Beatmap.Stages)

View File

@ -6,8 +6,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
@ -16,6 +21,7 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Screens.Edit.Components.TernaryButtons;
using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Screens.Edit.Compose.Components;
using osuTK; using osuTK;
@ -23,6 +29,8 @@ namespace osu.Game.Rulesets.Mania.Edit
{ {
public partial class ManiaHitObjectComposer : HitObjectComposer<ManiaHitObject> public partial class ManiaHitObjectComposer : HitObjectComposer<ManiaHitObject>
{ {
private readonly Bindable<TernaryState> showSpeedChanges = new Bindable<TernaryState>();
private DrawableManiaEditorRuleset drawableRuleset; private DrawableManiaEditorRuleset drawableRuleset;
private ManiaBeatSnapGrid beatSnapGrid; private ManiaBeatSnapGrid beatSnapGrid;
private InputManager inputManager; private InputManager inputManager;
@ -36,6 +44,21 @@ namespace osu.Game.Rulesets.Mania.Edit
private void load() private void load()
{ {
AddInternal(beatSnapGrid = new ManiaBeatSnapGrid()); AddInternal(beatSnapGrid = new ManiaBeatSnapGrid());
LeftToolbox.Add(new EditorToolboxGroup("playfield")
{
Child = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 5),
Children = new[]
{
new DrawableTernaryButton(new TernaryButton(showSpeedChanges, "Show speed changes", () => new SpriteIcon { Icon = FontAwesome.Solid.TachometerAlt }))
}
},
});
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -59,7 +82,10 @@ namespace osu.Game.Rulesets.Mania.Edit
protected override DrawableRuleset<ManiaHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null) protected override DrawableRuleset<ManiaHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
{ {
drawableRuleset = new DrawableManiaEditorRuleset(ruleset, beatmap, mods); drawableRuleset = new DrawableManiaEditorRuleset(ruleset, beatmap, mods)
{
ShowSpeedChanges = { BindTarget = showSpeedChanges }
};
// This is the earliest we can cache the scrolling info to ourselves, before masks are added to the hierarchy and inject it // This is the earliest we can cache the scrolling info to ourselves, before masks are added to the hierarchy and inject it
dependencies.CacheAs(drawableRuleset.ScrollingInfo); dependencies.CacheAs(drawableRuleset.ScrollingInfo);

View File

@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public void ApplyToDrawableRuleset(DrawableRuleset<ManiaHitObject> drawableRuleset) public void ApplyToDrawableRuleset(DrawableRuleset<ManiaHitObject> drawableRuleset)
{ {
var maniaRuleset = (DrawableManiaRuleset)drawableRuleset; var maniaRuleset = (DrawableManiaRuleset)drawableRuleset;
maniaRuleset.ScrollMethod = ScrollVisualisationMethod.Constant; maniaRuleset.VisualisationMethod = ScrollVisualisationMethod.Constant;
} }
} }
} }

View File

@ -3,7 +3,6 @@
#nullable disable #nullable disable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -52,22 +51,12 @@ namespace osu.Game.Rulesets.Mania.UI
protected new ManiaRulesetConfigManager Config => (ManiaRulesetConfigManager)base.Config; protected new ManiaRulesetConfigManager Config => (ManiaRulesetConfigManager)base.Config;
public ScrollVisualisationMethod ScrollMethod public new ScrollVisualisationMethod VisualisationMethod
{ {
get => scrollMethod; get => base.VisualisationMethod;
set set => base.VisualisationMethod = value;
{
if (IsLoaded)
throw new InvalidOperationException($"Can't alter {nameof(ScrollMethod)} after ruleset is already loaded");
scrollMethod = value;
}
} }
private ScrollVisualisationMethod scrollMethod = ScrollVisualisationMethod.Sequential;
protected override ScrollVisualisationMethod VisualisationMethod => scrollMethod;
private readonly Bindable<ManiaScrollingDirection> configDirection = new Bindable<ManiaScrollingDirection>(); private readonly Bindable<ManiaScrollingDirection> configDirection = new Bindable<ManiaScrollingDirection>();
private readonly BindableInt configScrollSpeed = new BindableInt(); private readonly BindableInt configScrollSpeed = new BindableInt();
private double smoothTimeRange; private double smoothTimeRange;

View File

@ -35,8 +35,6 @@ namespace osu.Game.Rulesets.Taiko.UI
public new TaikoInputManager KeyBindingInputManager => (TaikoInputManager)base.KeyBindingInputManager; public new TaikoInputManager KeyBindingInputManager => (TaikoInputManager)base.KeyBindingInputManager;
protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping;
protected override bool UserScrollSpeedAdjustment => false; protected override bool UserScrollSpeedAdjustment => false;
private SkinnableDrawable scroller; private SkinnableDrawable scroller;
@ -45,6 +43,7 @@ namespace osu.Game.Rulesets.Taiko.UI
: base(ruleset, beatmap, mods) : base(ruleset, beatmap, mods)
{ {
Direction.Value = ScrollingDirection.Left; Direction.Value = ScrollingDirection.Left;
VisualisationMethod = ScrollVisualisationMethod.Overlapping;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]

View File

@ -311,14 +311,13 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override bool RelativeScaleBeatLengths => RelativeScaleBeatLengthsOverride; protected override bool RelativeScaleBeatLengths => RelativeScaleBeatLengthsOverride;
protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping;
public new Bindable<double> TimeRange => base.TimeRange; public new Bindable<double> TimeRange => base.TimeRange;
public TestDrawableScrollingRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null) public TestDrawableScrollingRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
: base(ruleset, beatmap, mods) : base(ruleset, beatmap, mods)
{ {
TimeRange.Value = time_range; TimeRange.Value = time_range;
VisualisationMethod = ScrollVisualisationMethod.Overlapping;
} }
public override DrawableHitObject<TestHitObject> CreateDrawableRepresentation(TestHitObject h) public override DrawableHitObject<TestHitObject> CreateDrawableRepresentation(TestHitObject h)

View File

@ -64,8 +64,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
MaxValue = time_span_max MaxValue = time_span_max
}; };
protected virtual ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Sequential;
ScrollVisualisationMethod IDrawableScrollingRuleset.VisualisationMethod => VisualisationMethod; ScrollVisualisationMethod IDrawableScrollingRuleset.VisualisationMethod => VisualisationMethod;
/// <summary> /// <summary>
@ -99,20 +97,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
switch (VisualisationMethod) updateScrollAlgorithm();
{
case ScrollVisualisationMethod.Sequential:
scrollingInfo.Algorithm = new SequentialScrollAlgorithm(ControlPoints);
break;
case ScrollVisualisationMethod.Overlapping:
scrollingInfo.Algorithm = new OverlappingScrollAlgorithm(ControlPoints);
break;
case ScrollVisualisationMethod.Constant:
scrollingInfo.Algorithm = new ConstantScrollAlgorithm();
break;
}
double lastObjectTime = Beatmap.HitObjects.Any() ? Beatmap.GetLastObjectTime() : double.MaxValue; double lastObjectTime = Beatmap.HitObjects.Any() ? Beatmap.GetLastObjectTime() : double.MaxValue;
double baseBeatLength = TimingControlPoint.DEFAULT_BEAT_LENGTH; double baseBeatLength = TimingControlPoint.DEFAULT_BEAT_LENGTH;
@ -178,6 +163,36 @@ namespace osu.Game.Rulesets.UI.Scrolling
throw new ArgumentException($"{nameof(Playfield)} must be a {nameof(ScrollingPlayfield)} when using {nameof(DrawableScrollingRuleset<TObject>)}."); throw new ArgumentException($"{nameof(Playfield)} must be a {nameof(ScrollingPlayfield)} when using {nameof(DrawableScrollingRuleset<TObject>)}.");
} }
private ScrollVisualisationMethod visualisationMethod = ScrollVisualisationMethod.Sequential;
protected ScrollVisualisationMethod VisualisationMethod
{
get => visualisationMethod;
set
{
visualisationMethod = value;
updateScrollAlgorithm();
}
}
private void updateScrollAlgorithm()
{
switch (VisualisationMethod)
{
case ScrollVisualisationMethod.Sequential:
scrollingInfo.Algorithm.Value = new SequentialScrollAlgorithm(ControlPoints);
break;
case ScrollVisualisationMethod.Overlapping:
scrollingInfo.Algorithm.Value = new OverlappingScrollAlgorithm(ControlPoints);
break;
case ScrollVisualisationMethod.Constant:
scrollingInfo.Algorithm.Value = new ConstantScrollAlgorithm();
break;
}
}
/// <summary> /// <summary>
/// Adjusts the scroll speed of <see cref="HitObject"/>s. /// Adjusts the scroll speed of <see cref="HitObject"/>s.
/// </summary> /// </summary>
@ -217,7 +232,9 @@ namespace osu.Game.Rulesets.UI.Scrolling
public IBindable<double> TimeRange { get; } = new BindableDouble(); public IBindable<double> TimeRange { get; } = new BindableDouble();
public IScrollAlgorithm Algorithm { get; set; } public readonly Bindable<IScrollAlgorithm> Algorithm = new Bindable<IScrollAlgorithm>(new ConstantScrollAlgorithm());
IBindable<IScrollAlgorithm> IScrollingInfo.Algorithm => Algorithm;
} }
} }
} }

View File

@ -15,13 +15,13 @@ namespace osu.Game.Rulesets.UI.Scrolling
IBindable<ScrollingDirection> Direction { get; } IBindable<ScrollingDirection> Direction { get; }
/// <summary> /// <summary>
/// /// The span of time that is visible by the length of the scrolling axes.
/// </summary> /// </summary>
IBindable<double> TimeRange { get; } IBindable<double> TimeRange { get; }
/// <summary> /// <summary>
/// The algorithm which controls <see cref="HitObject"/> positions and sizes. /// The algorithm which controls <see cref="HitObject"/> positions and sizes.
/// </summary> /// </summary>
IScrollAlgorithm Algorithm { get; } IBindable<IScrollAlgorithm> Algorithm { get; }
} }
} }

View File

@ -13,6 +13,7 @@ using osu.Framework.Layout;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.UI.Scrolling.Algorithms;
using osuTK; using osuTK;
namespace osu.Game.Rulesets.UI.Scrolling namespace osu.Game.Rulesets.UI.Scrolling
@ -21,6 +22,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
{ {
private readonly IBindable<double> timeRange = new BindableDouble(); private readonly IBindable<double> timeRange = new BindableDouble();
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>(); private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
private readonly IBindable<IScrollAlgorithm> algorithm = new Bindable<IScrollAlgorithm>();
/// <summary> /// <summary>
/// Whether the scrolling direction is horizontal or vertical. /// Whether the scrolling direction is horizontal or vertical.
@ -59,9 +61,11 @@ namespace osu.Game.Rulesets.UI.Scrolling
{ {
direction.BindTo(scrollingInfo.Direction); direction.BindTo(scrollingInfo.Direction);
timeRange.BindTo(scrollingInfo.TimeRange); timeRange.BindTo(scrollingInfo.TimeRange);
algorithm.BindTo(scrollingInfo.Algorithm);
direction.ValueChanged += _ => layoutCache.Invalidate(); direction.ValueChanged += _ => layoutCache.Invalidate();
timeRange.ValueChanged += _ => layoutCache.Invalidate(); timeRange.ValueChanged += _ => layoutCache.Invalidate();
algorithm.ValueChanged += _ => layoutCache.Invalidate();
} }
/// <summary> /// <summary>
@ -73,7 +77,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
public double TimeAtPosition(float localPosition, double currentTime) public double TimeAtPosition(float localPosition, double currentTime)
{ {
float scrollPosition = axisInverted ? -localPosition : localPosition; float scrollPosition = axisInverted ? -localPosition : localPosition;
return scrollingInfo.Algorithm.TimeAt(scrollPosition, currentTime, timeRange.Value, scrollLength); return algorithm.Value.TimeAt(scrollPosition, currentTime, timeRange.Value, scrollLength);
} }
/// <summary> /// <summary>
@ -95,7 +99,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
/// </summary> /// </summary>
public float PositionAtTime(double time, double currentTime, double? originTime = null) public float PositionAtTime(double time, double currentTime, double? originTime = null)
{ {
float scrollPosition = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength, originTime); float scrollPosition = algorithm.Value.PositionAt(time, currentTime, timeRange.Value, scrollLength, originTime);
return axisInverted ? -scrollPosition : scrollPosition; return axisInverted ? -scrollPosition : scrollPosition;
} }
@ -122,7 +126,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
/// </summary> /// </summary>
public float LengthAtTime(double startTime, double endTime) public float LengthAtTime(double startTime, double endTime)
{ {
return scrollingInfo.Algorithm.GetLength(startTime, endTime, timeRange.Value, scrollLength); return algorithm.Value.GetLength(startTime, endTime, timeRange.Value, scrollLength);
} }
private float scrollLength => scrollingAxis == Direction.Horizontal ? DrawWidth : DrawHeight; private float scrollLength => scrollingAxis == Direction.Horizontal ? DrawWidth : DrawHeight;
@ -169,7 +173,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
foreach (var entry in Entries) foreach (var entry in Entries)
setComputedLifetimeStart(entry); setComputedLifetimeStart(entry);
scrollingInfo.Algorithm.Reset(); algorithm.Value.Reset();
layoutCache.Validate(); layoutCache.Validate();
} }
@ -224,7 +228,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
break; break;
} }
return scrollingInfo.Algorithm.GetDisplayStartTime(entry.HitObject.StartTime, startOffset, timeRange.Value, scrollLength); return algorithm.Value.GetDisplayStartTime(entry.HitObject.StartTime, startOffset, timeRange.Value, scrollLength);
} }
private void setComputedLifetimeStart(HitObjectLifetimeEntry entry) private void setComputedLifetimeStart(HitObjectLifetimeEntry entry)

View File

@ -14,7 +14,7 @@ using osuTK.Graphics;
namespace osu.Game.Screens.Edit.Components.TernaryButtons namespace osu.Game.Screens.Edit.Components.TernaryButtons
{ {
internal partial class DrawableTernaryButton : OsuButton public partial class DrawableTernaryButton : OsuButton
{ {
private Color4 defaultBackgroundColour; private Color4 defaultBackgroundColour;
private Color4 defaultIconColour; private Color4 defaultIconColour;

View File

@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual
IBindable<double> IScrollingInfo.TimeRange => TimeRange; IBindable<double> IScrollingInfo.TimeRange => TimeRange;
public readonly TestScrollAlgorithm Algorithm = new TestScrollAlgorithm(); public readonly TestScrollAlgorithm Algorithm = new TestScrollAlgorithm();
IScrollAlgorithm IScrollingInfo.Algorithm => Algorithm; IBindable<IScrollAlgorithm> IScrollingInfo.Algorithm => new Bindable<IScrollAlgorithm>(Algorithm);
} }
public class TestScrollAlgorithm : IScrollAlgorithm public class TestScrollAlgorithm : IScrollAlgorithm