From ce7be940e2dd4f220583318bdf623a63d0f6e4f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 May 2022 14:34:33 +0900 Subject: [PATCH 01/21] Setup basics for control and test --- .../Editing/TestSceneTapTimingControl.cs | 94 +++++++++ .../UserInterfaceV2/LabelledDrawable.cs | 3 +- .../Screens/Edit/Timing/TapTimingControl.cs | 189 ++++++++++++++++++ osu.Game/Screens/Edit/Timing/TimingSection.cs | 2 + 4 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs create mode 100644 osu.Game/Screens/Edit/Timing/TapTimingControl.cs diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs new file mode 100644 index 0000000000..c2889b2549 --- /dev/null +++ b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs @@ -0,0 +1,94 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Overlays; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Edit; +using osu.Game.Screens.Edit.Timing; +using osuTK; + +namespace osu.Game.Tests.Visual.Editing +{ + [TestFixture] + public class TestSceneTapTimingControl : EditorClockTestScene + { + [Cached(typeof(EditorBeatmap))] + [Cached(typeof(IBeatSnapProvider))] + private readonly EditorBeatmap editorBeatmap; + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + + [Cached] + private Bindable selectedGroup = new Bindable(); + + private TapTimingControl control; + + public TestSceneTapTimingControl() + { + editorBeatmap = new EditorBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)); + selectedGroup.Value = editorBeatmap.ControlPointInfo.Groups.First(); + } + + [Test] + public void TestTapThenReset() + { + AddStep("click tap button", () => + { + control.ChildrenOfType() + .First(b => b.Text == "Tap to beat") + .TriggerClick(); + }); + + AddUntilStep("wait for track playing", () => Clock.IsRunning); + + AddStep("click reset button", () => + { + control.ChildrenOfType() + .First(b => b.Text == "Reset") + .TriggerClick(); + }); + + AddUntilStep("wait for track stopped", () => !Clock.IsRunning); + } + + [Test] + public void TestBasic() + { + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); + Beatmap.Disabled = true; + + Child = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Y, + Width = 400, + Scale = new Vector2(1.5f), + Child = control = new TapTimingControl(), + }; + } + + protected override void Dispose(bool isDisposing) + { + Beatmap.Disabled = false; + base.Dispose(isDisposing); + } + } +} diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs index 1e6032c1d0..066e1a7978 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs @@ -41,7 +41,8 @@ namespace osu.Game.Graphics.UserInterfaceV2 protected const float CONTENT_PADDING_VERTICAL = 10; protected const float CONTENT_PADDING_HORIZONTAL = 15; - protected const float CORNER_RADIUS = 15; + + public const float CORNER_RADIUS = 15; /// /// The component that is being displayed. diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs new file mode 100644 index 0000000000..3867a4bcec --- /dev/null +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -0,0 +1,189 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +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.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Screens.Edit.Timing +{ + public class TapTimingControl : CompositeDrawable + { + [Resolved] + private EditorClock editorClock { get; set; } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider, OsuColour colours) + { + Height = 200; + RelativeSizeAxes = Axes.X; + + CornerRadius = LabelledDrawable.CORNER_RADIUS; + Masking = true; + + InternalChildren = new Drawable[] + { + new Box + { + Colour = colourProvider.Background4, + RelativeSizeAxes = Axes.Both, + }, + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.Absolute, 60), + }, + Content = new[] + { + new Drawable[] + { + new Metronome() + }, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(10), + Children = new Drawable[] + { + new RoundedButton + { + Text = "Reset", + BackgroundColour = colours.Pink, + RelativeSizeAxes = Axes.X, + Width = 0.3f, + Action = reset, + }, + new RoundedButton + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Text = "Tap to beat", + RelativeSizeAxes = Axes.X, + BackgroundColour = colourProvider.Background1, + Width = 0.68f, + Action = tap, + } + } + }, + } + } + }, + }; + } + + private void tap() + { + if (!editorClock.IsRunning) + { + editorClock.Seek(0); + editorClock.Start(); + } + } + + private void reset() + { + editorClock.Stop(); + } + + private class Metronome : BeatSyncedContainer + { + private Container swing; + private Box weight; + private OsuSpriteText bpm; + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider overlayColourProvider) + { + Margin = new MarginPadding(10); + AutoSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new Triangle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(80, 120), + Colour = overlayColourProvider.Background1, + }, + new Circle + { + Y = -25, + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + Colour = overlayColourProvider.Content2, + Size = new Vector2(10) + }, + bpm = new OsuSpriteText + { + Colour = overlayColourProvider.Content1, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + swing = new Container + { + RelativeSizeAxes = Axes.Both, + Y = -25, + Height = 0.8f, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Children = new Drawable[] + { + new Box + { + Colour = overlayColourProvider.Content2, + RelativeSizeAxes = Axes.Y, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Width = 4, + }, + weight = new Box + { + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + Colour = overlayColourProvider.Content2, + Size = new Vector2(15), + RelativePositionAxes = Axes.Y, + Y = -0.4f, + }, + } + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + swing + .RotateTo(20, 500, Easing.InOutQuad) + .Then() + .RotateTo(-20, 500, Easing.InOutQuad) + .Loop(); + } + + protected override void Update() + { + base.Update(); + + if (CurrentTimingPoint == null) + return; + + weight.Y = Math.Clamp((float)CurrentTimingPoint.BPM / 480, 0, 0.95f); + bpm.Text = $"{CurrentTimingPoint.BPM:F0}"; + } + } + } +} diff --git a/osu.Game/Screens/Edit/Timing/TimingSection.cs b/osu.Game/Screens/Edit/Timing/TimingSection.cs index 13af04cd4b..be719d0cb6 100644 --- a/osu.Game/Screens/Edit/Timing/TimingSection.cs +++ b/osu.Game/Screens/Edit/Timing/TimingSection.cs @@ -19,6 +19,7 @@ namespace osu.Game.Screens.Edit.Timing { Flow.AddRange(new Drawable[] { + new TapTimingControl(), bpmTextEntry = new BPMTextBox(), timeSignature = new LabelledTimeSignature { @@ -96,5 +97,6 @@ namespace osu.Game.Screens.Edit.Timing } private static double beatLengthToBpm(double beatLength) => 60000 / beatLength; + } } From 42179568f3aca7d67c574ae615dcf8c65920eae3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 May 2022 15:56:39 +0900 Subject: [PATCH 02/21] Initial animation pass on metronome --- .../Editing/TestSceneTapTimingControl.cs | 58 +++++++--- .../Screens/Edit/Timing/TapTimingControl.cs | 105 +++++++++++++----- osu.Game/Screens/Edit/Timing/TimingSection.cs | 1 - 3 files changed, 117 insertions(+), 47 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs index c2889b2549..9b2618df5b 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs @@ -36,10 +36,37 @@ namespace osu.Game.Tests.Visual.Editing public TestSceneTapTimingControl() { - editorBeatmap = new EditorBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)); + var playableBeatmap = CreateBeatmap(new OsuRuleset().RulesetInfo); + + // Ensure time doesn't end while testing + playableBeatmap.BeatmapInfo.Length = 1200000; + + editorBeatmap = new EditorBeatmap(playableBeatmap); + selectedGroup.Value = editorBeatmap.ControlPointInfo.Groups.First(); } + protected override void LoadComplete() + { + base.LoadComplete(); + + Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); + Beatmap.Disabled = true; + + Children = new Drawable[] + { + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Y, + Width = 400, + Scale = new Vector2(1.5f), + Child = control = new TapTimingControl(), + } + }; + } + [Test] public void TestTapThenReset() { @@ -65,24 +92,19 @@ namespace osu.Game.Tests.Visual.Editing [Test] public void TestBasic() { - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); - Beatmap.Disabled = true; - - Child = new Container + AddStep("set low bpm", () => { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Y, - Width = 400, - Scale = new Vector2(1.5f), - Child = control = new TapTimingControl(), - }; + editorBeatmap.ControlPointInfo.TimingPoints.First().BeatLength = 1000; + }); + + AddStep("click tap button", () => + { + control.ChildrenOfType() + .First(b => b.Text == "Tap to beat") + .TriggerClick(); + }); + + AddSliderStep("BPM", 30, 400, 60, bpm => editorBeatmap.ControlPointInfo.TimingPoints.First().BeatLength = 60000f / bpm); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index 3867a4bcec..e23982ddc7 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -3,15 +3,19 @@ using System; using osu.Framework.Allocation; +using osu.Framework.Audio.Track; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Utils; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Overlays; using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.Edit.Timing { @@ -103,9 +107,13 @@ namespace osu.Game.Screens.Edit.Timing private Container swing; private Box weight; private OsuSpriteText bpm; + private Box stick; + + [Resolved] + private OverlayColourProvider overlayColourProvider { get; set; } [BackgroundDependencyLoader] - private void load(OverlayColourProvider overlayColourProvider) + private void load() { Margin = new MarginPadding(10); AutoSizeAxes = Axes.Both; @@ -117,21 +125,13 @@ namespace osu.Game.Screens.Edit.Timing Anchor = Anchor.Centre, Origin = Anchor.Centre, Size = new Vector2(80, 120), - Colour = overlayColourProvider.Background1, - }, - new Circle - { - Y = -25, - Anchor = Anchor.BottomCentre, - Origin = Anchor.Centre, - Colour = overlayColourProvider.Content2, - Size = new Vector2(10) + Colour = overlayColourProvider.Background2, }, bpm = new OsuSpriteText { Colour = overlayColourProvider.Content1, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, }, swing = new Container { @@ -142,10 +142,10 @@ namespace osu.Game.Screens.Edit.Timing Origin = Anchor.BottomCentre, Children = new Drawable[] { - new Box + stick = new Box { - Colour = overlayColourProvider.Content2, RelativeSizeAxes = Axes.Y, + Colour = overlayColourProvider.Colour2, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, Width = 4, @@ -154,35 +154,84 @@ namespace osu.Game.Screens.Edit.Timing { Anchor = Anchor.TopCentre, Origin = Anchor.Centre, - Colour = overlayColourProvider.Content2, + Colour = overlayColourProvider.Colour1, Size = new Vector2(15), RelativePositionAxes = Axes.Y, - Y = -0.4f, + Y = 0.4f, }, } }, + new Circle + { + Y = -25, + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + Colour = overlayColourProvider.Colour0, + Size = new Vector2(10) + }, }; } - protected override void LoadComplete() - { - base.LoadComplete(); - swing - .RotateTo(20, 500, Easing.InOutQuad) - .Then() - .RotateTo(-20, 500, Easing.InOutQuad) - .Loop(); - } + private double beatLength; + + private TimingControlPoint timingPoint; + + private float bpmRatio; + private bool isSwinging; protected override void Update() { base.Update(); - if (CurrentTimingPoint == null) + timingPoint = Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(BeatSyncClock.CurrentTime); + + if (beatLength != timingPoint.BeatLength) + { + beatLength = timingPoint.BeatLength; + bpm.Text = $"{timingPoint.BPM:F0}"; + + EarlyActivationMilliseconds = timingPoint.BeatLength / 2; + + bpmRatio = (float)Interpolation.ApplyEasing(Easing.OutQuad, Math.Clamp((timingPoint.BPM - 30) / 480, 0, 1)); + + weight.MoveToY((float)Interpolation.Lerp(0, 0.9f, bpmRatio), 600, Easing.OutQuint); + } + + if (BeatSyncClock?.IsRunning != true && isSwinging) + { + swing.ClearTransforms(true); + + using (swing.BeginDelayedSequence(350)) + { + swing.RotateTo(0, 1000, Easing.OutQuint); + stick.FadeColour(overlayColourProvider.Colour2, 1000, Easing.OutQuint); + } + + isSwinging = false; + } + } + + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + { + base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); + + float angle = (float)Interpolation.Lerp(25, 4, bpmRatio); + + if (!IsBeatSyncedWithTrack) return; - weight.Y = Math.Clamp((float)CurrentTimingPoint.BPM / 480, 0, 0.95f); - bpm.Text = $"{CurrentTimingPoint.BPM:F0}"; + isSwinging = true; + + float currentAngle = swing.Rotation; + float targetAngle = currentAngle > 0 ? -angle : angle; + + swing.RotateTo(targetAngle, beatLength, Easing.InOutQuad); + + if (currentAngle != 0 && Math.Abs(currentAngle - targetAngle) > angle * 1.8f && isSwinging) + { + using (stick.BeginDelayedSequence(beatLength / 2)) + stick.FlashColour(overlayColourProvider.Content1, beatLength, Easing.OutQuint); + } } } } diff --git a/osu.Game/Screens/Edit/Timing/TimingSection.cs b/osu.Game/Screens/Edit/Timing/TimingSection.cs index be719d0cb6..a5abd96d72 100644 --- a/osu.Game/Screens/Edit/Timing/TimingSection.cs +++ b/osu.Game/Screens/Edit/Timing/TimingSection.cs @@ -97,6 +97,5 @@ namespace osu.Game.Screens.Edit.Timing } private static double beatLengthToBpm(double beatLength) => 60000 / beatLength; - } } From cf1ef28f72235a4f5d742e3d404ccfd94d2dcab1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 May 2022 16:22:16 +0900 Subject: [PATCH 03/21] Add taper and more correctly shaped weight --- .../Screens/Edit/Timing/TapTimingControl.cs | 91 ++++++++++++++----- 1 file changed, 70 insertions(+), 21 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index e23982ddc7..7507a7dd35 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -15,7 +15,6 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Overlays; using osuTK; -using osuTK.Graphics; namespace osu.Game.Screens.Edit.Timing { @@ -105,9 +104,11 @@ namespace osu.Game.Screens.Edit.Timing private class Metronome : BeatSyncedContainer { private Container swing; - private Box weight; + private OsuSpriteText bpm; - private Box stick; + + private Drawable weight; + private Drawable stick; [Resolved] private OverlayColourProvider overlayColourProvider { get; set; } @@ -116,33 +117,41 @@ namespace osu.Game.Screens.Edit.Timing private void load() { Margin = new MarginPadding(10); + + const float taper = 10; + + var triangleSize = new Vector2(80, 120); + AutoSizeAxes = Axes.Both; + const float stick_vertical_offset = -23; + InternalChildren = new Drawable[] { - new Triangle + new Container { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(80, 120), - Colour = overlayColourProvider.Background2, - }, - bpm = new OsuSpriteText - { - Colour = overlayColourProvider.Content1, + Masking = true, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, + Size = new Vector2(triangleSize.X * 1.2f, triangleSize.Y - taper), + Child = new Triangle + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Size = triangleSize, + Colour = overlayColourProvider.Background3, + }, }, swing = new Container { RelativeSizeAxes = Axes.Both, - Y = -25, + Y = stick_vertical_offset, Height = 0.8f, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - Children = new Drawable[] + Children = new[] { - stick = new Box + stick = new Circle { RelativeSizeAxes = Axes.Y, Colour = overlayColourProvider.Colour2, @@ -150,24 +159,64 @@ namespace osu.Game.Screens.Edit.Timing Origin = Anchor.BottomCentre, Width = 4, }, - weight = new Box + weight = new Container { Anchor = Anchor.TopCentre, Origin = Anchor.Centre, Colour = overlayColourProvider.Colour1, - Size = new Vector2(15), + Size = new Vector2(10), + Rotation = 180, RelativePositionAxes = Axes.Y, Y = 0.4f, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Shear = new Vector2(0.2f, 0), + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Shear = new Vector2(-0.2f, 0), + }, + } }, } }, new Circle { - Y = -25, + Y = stick_vertical_offset, Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, Colour = overlayColourProvider.Colour0, - Size = new Vector2(10) + Size = new Vector2(8) + }, + new Container + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.Both, + Masking = true, + Height = 0.3f, + Children = new Drawable[] + { + new Triangle + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Size = triangleSize, + Colour = overlayColourProvider.Background2, + Alpha = 0.8f + }, + } + }, + bpm = new OsuSpriteText + { + Colour = overlayColourProvider.Content1, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Y = -3, }, }; } @@ -194,7 +243,7 @@ namespace osu.Game.Screens.Edit.Timing bpmRatio = (float)Interpolation.ApplyEasing(Easing.OutQuad, Math.Clamp((timingPoint.BPM - 30) / 480, 0, 1)); - weight.MoveToY((float)Interpolation.Lerp(0, 0.9f, bpmRatio), 600, Easing.OutQuint); + weight.MoveToY((float)Interpolation.Lerp(0.07f, 0.9f, bpmRatio), 600, Easing.OutQuint); } if (BeatSyncClock?.IsRunning != true && isSwinging) @@ -215,7 +264,7 @@ namespace osu.Game.Screens.Edit.Timing { base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); - float angle = (float)Interpolation.Lerp(25, 4, bpmRatio); + float angle = (float)Interpolation.Lerp(30, 5, bpmRatio); if (!IsBeatSyncedWithTrack) return; From 79878a4ec21cab922d4ed10295fa0f9eac8ecda2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 May 2022 16:25:24 +0900 Subject: [PATCH 04/21] Metrics adjust and labelling --- .../Screens/Edit/Timing/TapTimingControl.cs | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index 7507a7dd35..3aff74d359 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -116,26 +116,27 @@ namespace osu.Game.Screens.Edit.Timing [BackgroundDependencyLoader] private void load() { + const float taper = 30; + const float swing_vertical_offset = -23; + + var triangleSize = new Vector2(90, 120 + taper); + Margin = new MarginPadding(10); - const float taper = 10; - - var triangleSize = new Vector2(80, 120); - AutoSizeAxes = Axes.Both; - const float stick_vertical_offset = -23; - InternalChildren = new Drawable[] { new Container { + Name = @"Taper adjust", Masking = true, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, Size = new Vector2(triangleSize.X * 1.2f, triangleSize.Y - taper), Child = new Triangle { + Name = @"Main body", Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, Size = triangleSize, @@ -144,15 +145,17 @@ namespace osu.Game.Screens.Edit.Timing }, swing = new Container { + Name = @"Swing", RelativeSizeAxes = Axes.Both, - Y = stick_vertical_offset, - Height = 0.8f, + Y = swing_vertical_offset, + Height = 0.80f, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, Children = new[] { stick = new Circle { + Name = @"Stick", RelativeSizeAxes = Axes.Y, Colour = overlayColourProvider.Colour2, Anchor = Anchor.BottomCentre, @@ -161,6 +164,7 @@ namespace osu.Game.Screens.Edit.Timing }, weight = new Container { + Name = @"Weight", Anchor = Anchor.TopCentre, Origin = Anchor.Centre, Colour = overlayColourProvider.Colour1, @@ -186,7 +190,8 @@ namespace osu.Game.Screens.Edit.Timing }, new Circle { - Y = stick_vertical_offset, + Name = @"Swing connection point", + Y = swing_vertical_offset, Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, Colour = overlayColourProvider.Colour0, @@ -194,6 +199,7 @@ namespace osu.Game.Screens.Edit.Timing }, new Container { + Name = @"Lower cover", Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, RelativeSizeAxes = Axes.Both, @@ -213,6 +219,7 @@ namespace osu.Game.Screens.Edit.Timing }, bpm = new OsuSpriteText { + Name = @"BPM display", Colour = overlayColourProvider.Content1, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, From 21072a26ef30547bbbee7b802bcd918caac4296c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 May 2022 16:33:27 +0900 Subject: [PATCH 05/21] Add locking wedge --- .../Screens/Edit/Timing/TapTimingControl.cs | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index 3aff74d359..323561f0a8 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -133,14 +133,17 @@ namespace osu.Game.Screens.Edit.Timing Masking = true, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - Size = new Vector2(triangleSize.X * 1.2f, triangleSize.Y - taper), - Child = new Triangle + Size = new Vector2(triangleSize.X, triangleSize.Y - taper), + Children = new Drawable[] { - Name = @"Main body", - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Size = triangleSize, - Colour = overlayColourProvider.Background3, + new Triangle + { + Name = @"Main body", + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Size = triangleSize, + Colour = overlayColourProvider.Background3, + }, }, }, swing = new Container @@ -188,6 +191,25 @@ namespace osu.Game.Screens.Edit.Timing }, } }, + new Container + { + Name = @"Taper adjust", + Masking = true, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Size = new Vector2(triangleSize.X, triangleSize.Y - taper), + Children = new Drawable[] + { + new Circle + { + Name = @"Locking wedge", + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + Colour = overlayColourProvider.Background1, + Size = new Vector2(8), + } + }, + }, new Circle { Name = @"Swing connection point", From 8487d2c48a41010245ba0b1a527ab821935520ac Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 May 2022 16:45:01 +0900 Subject: [PATCH 06/21] Interpolate bpm label and fix incorrect angle logic --- .../Screens/Edit/Timing/TapTimingControl.cs | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index 323561f0a8..4ab731c897 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Allocation; using osu.Framework.Audio.Track; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -105,7 +106,7 @@ namespace osu.Game.Screens.Edit.Timing { private Container swing; - private OsuSpriteText bpm; + private OsuSpriteText bpmText; private Drawable weight; private Drawable stick; @@ -116,7 +117,7 @@ namespace osu.Game.Screens.Edit.Timing [BackgroundDependencyLoader] private void load() { - const float taper = 30; + const float taper = 25; const float swing_vertical_offset = -23; var triangleSize = new Vector2(90, 120 + taper); @@ -226,7 +227,7 @@ namespace osu.Game.Screens.Edit.Timing Origin = Anchor.BottomCentre, RelativeSizeAxes = Axes.Both, Masking = true, - Height = 0.3f, + Height = 0.28f, Children = new Drawable[] { new Triangle @@ -239,7 +240,7 @@ namespace osu.Game.Screens.Edit.Timing }, } }, - bpm = new OsuSpriteText + bpmText = new OsuSpriteText { Name = @"BPM display", Colour = overlayColourProvider.Content1, @@ -254,9 +255,17 @@ namespace osu.Game.Screens.Edit.Timing private TimingControlPoint timingPoint; - private float bpmRatio; private bool isSwinging; + private readonly BindableInt interpolatedBpm = new BindableInt(); + + protected override void LoadComplete() + { + base.LoadComplete(); + + interpolatedBpm.BindValueChanged(bpm => bpmText.Text = bpm.NewValue.ToString()); + } + protected override void Update() { base.Update(); @@ -266,13 +275,13 @@ namespace osu.Game.Screens.Edit.Timing if (beatLength != timingPoint.BeatLength) { beatLength = timingPoint.BeatLength; - bpm.Text = $"{timingPoint.BPM:F0}"; EarlyActivationMilliseconds = timingPoint.BeatLength / 2; - bpmRatio = (float)Interpolation.ApplyEasing(Easing.OutQuad, Math.Clamp((timingPoint.BPM - 30) / 480, 0, 1)); + float bpmRatio = (float)Interpolation.ApplyEasing(Easing.OutQuad, Math.Clamp((timingPoint.BPM - 30) / 480, 0, 1)); - weight.MoveToY((float)Interpolation.Lerp(0.07f, 0.9f, bpmRatio), 600, Easing.OutQuint); + weight.MoveToY((float)Interpolation.Lerp(0.1f, 0.83f, bpmRatio), 600, Easing.OutQuint); + this.TransformBindableTo(interpolatedBpm, (int)timingPoint.BPM, 600, Easing.OutQuint); } if (BeatSyncClock?.IsRunning != true && isSwinging) @@ -293,7 +302,7 @@ namespace osu.Game.Screens.Edit.Timing { base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); - float angle = (float)Interpolation.Lerp(30, 5, bpmRatio); + const float angle = 27.5f; if (!IsBeatSyncedWithTrack) return; From 4712e512d71810e0be81428275382372eca91fac Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 May 2022 16:48:07 +0900 Subject: [PATCH 07/21] Apply edge smoothness and make weight more accented --- osu.Game/Screens/Edit/Timing/TapTimingControl.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index 4ab731c897..bdab427c58 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -140,6 +140,7 @@ namespace osu.Game.Screens.Edit.Timing new Triangle { Name = @"Main body", + EdgeSmoothness = new Vector2(1), Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, Size = triangleSize, @@ -171,7 +172,7 @@ namespace osu.Game.Screens.Edit.Timing Name = @"Weight", Anchor = Anchor.TopCentre, Origin = Anchor.Centre, - Colour = overlayColourProvider.Colour1, + Colour = overlayColourProvider.Colour0, Size = new Vector2(10), Rotation = 180, RelativePositionAxes = Axes.Y, @@ -182,11 +183,13 @@ namespace osu.Game.Screens.Edit.Timing { RelativeSizeAxes = Axes.Both, Shear = new Vector2(0.2f, 0), + EdgeSmoothness = new Vector2(1), }, new Box { RelativeSizeAxes = Axes.Both, Shear = new Vector2(-0.2f, 0), + EdgeSmoothness = new Vector2(1), }, } }, @@ -236,6 +239,7 @@ namespace osu.Game.Screens.Edit.Timing Origin = Anchor.BottomCentre, Size = triangleSize, Colour = overlayColourProvider.Background2, + EdgeSmoothness = new Vector2(1), Alpha = 0.8f }, } From cf97f4e409aa57e7883b0a36d037ae588c4683b7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 May 2022 16:55:07 +0900 Subject: [PATCH 08/21] Add centre marker --- osu.Game/Screens/Edit/Timing/TapTimingControl.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index bdab427c58..a99468fbff 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -119,6 +119,7 @@ namespace osu.Game.Screens.Edit.Timing { const float taper = 25; const float swing_vertical_offset = -23; + const float lower_cover_height = 32; var triangleSize = new Vector2(90, 120 + taper); @@ -148,6 +149,17 @@ namespace osu.Game.Screens.Edit.Timing }, }, }, + new Circle + { + Name = "Centre marker", + Colour = overlayColourProvider.Background5, + RelativeSizeAxes = Axes.Y, + Width = 2, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Y = -(lower_cover_height + 3), + Height = 0.65f, + }, swing = new Container { Name = @"Swing", @@ -228,9 +240,9 @@ namespace osu.Game.Screens.Edit.Timing Name = @"Lower cover", Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - RelativeSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.X, Masking = true, - Height = 0.28f, + Height = lower_cover_height, Children = new Drawable[] { new Triangle From 2e21d75b101d4aabb3a2dba05ef2e7306c6976ce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 May 2022 17:12:35 +0900 Subject: [PATCH 09/21] Move metronome into own class and rename to avoid conflict with mod sounds --- .../Mods/TestSceneOsuModMuted.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 2 +- .../Editing/TestSceneTapTimingControl.cs | 6 +- .../Mods/{Metronome.cs => MetronomeBeat.cs} | 4 +- osu.Game/Rulesets/Mods/ModMuted.cs | 6 +- .../Screens/Edit/Timing/MetronomeDisplay.cs | 255 +++++++++++++++++ .../Screens/Edit/Timing/TapTimingControl.cs | 261 +----------------- 7 files changed, 277 insertions(+), 259 deletions(-) rename osu.Game/Rulesets/Mods/{Metronome.cs => MetronomeBeat.cs} (95%) create mode 100644 osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs index c14dc78f38..e08d66fa31 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods MuteComboCount = { Value = 0 }, }, PassCondition = () => Beatmap.Value.Track.AggregateVolume.Value == 0.0 && - Player.ChildrenOfType().SingleOrDefault()?.AggregateVolume.Value == 1.0, + Player.ChildrenOfType().SingleOrDefault()?.AggregateVolume.Value == 1.0, }); /// diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index 5b121f4673..c58c624f5c 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -339,7 +339,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - drawableRuleset.Overlays.Add(new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime)); + drawableRuleset.Overlays.Add(new MetronomeBeat(drawableRuleset.Beatmap.HitObjects.First().StartTime)); } #endregion diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs index 9b2618df5b..de441995b5 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs @@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("click tap button", () => { control.ChildrenOfType() - .First(b => b.Text == "Tap to beat") + .Last() .TriggerClick(); }); @@ -82,7 +82,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("click reset button", () => { control.ChildrenOfType() - .First(b => b.Text == "Reset") + .First() .TriggerClick(); }); @@ -100,7 +100,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("click tap button", () => { control.ChildrenOfType() - .First(b => b.Text == "Tap to beat") + .Last() .TriggerClick(); }); diff --git a/osu.Game/Rulesets/Mods/Metronome.cs b/osu.Game/Rulesets/Mods/MetronomeBeat.cs similarity index 95% rename from osu.Game/Rulesets/Mods/Metronome.cs rename to osu.Game/Rulesets/Mods/MetronomeBeat.cs index b85a341577..c7a8b02130 100644 --- a/osu.Game/Rulesets/Mods/Metronome.cs +++ b/osu.Game/Rulesets/Mods/MetronomeBeat.cs @@ -11,14 +11,14 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mods { - public class Metronome : BeatSyncedContainer, IAdjustableAudioComponent + public class MetronomeBeat : BeatSyncedContainer, IAdjustableAudioComponent { private readonly double firstHitTime; private readonly PausableSkinnableSound sample; /// Start time of the first hit object, used for providing a count down. - public Metronome(double firstHitTime) + public MetronomeBeat(double firstHitTime) { this.firstHitTime = firstHitTime; AllowMistimedEventFiring = false; diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index a7d3114f2b..84341faab7 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -79,11 +79,11 @@ namespace osu.Game.Rulesets.Mods { if (EnableMetronome.Value) { - Metronome metronome; + MetronomeBeat metronomeBeat; - drawableRuleset.Overlays.Add(metronome = new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime)); + drawableRuleset.Overlays.Add(metronomeBeat = new MetronomeBeat(drawableRuleset.Beatmap.HitObjects.First().StartTime)); - metronome.AddAdjustment(AdjustableProperty.Volume, metronomeVolumeAdjust); + metronomeBeat.AddAdjustment(AdjustableProperty.Volume, metronomeVolumeAdjust); } if (AffectsHitSounds.Value) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs new file mode 100644 index 0000000000..fdd5bd1e4e --- /dev/null +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -0,0 +1,255 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Allocation; +using osu.Framework.Audio.Track; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Utils; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Screens.Edit.Timing +{ + public class MetronomeDisplay : BeatSyncedContainer + { + private Container swing; + + private OsuSpriteText bpmText; + + private Drawable weight; + private Drawable stick; + + [Resolved] + private OverlayColourProvider overlayColourProvider { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + const float taper = 25; + const float swing_vertical_offset = -23; + const float lower_cover_height = 32; + + var triangleSize = new Vector2(90, 120 + taper); + + Margin = new MarginPadding(10); + + AutoSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new Container + { + Name = @"Taper adjust", + Masking = true, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Size = new Vector2(triangleSize.X, triangleSize.Y - taper), + Children = new Drawable[] + { + new Triangle + { + Name = @"Main body", + EdgeSmoothness = new Vector2(1), + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Size = triangleSize, + Colour = overlayColourProvider.Background3, + }, + }, + }, + new Circle + { + Name = "Centre marker", + Colour = overlayColourProvider.Background5, + RelativeSizeAxes = Axes.Y, + Width = 2, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Y = -(lower_cover_height + 3), + Height = 0.65f, + }, + swing = new Container + { + Name = @"Swing", + RelativeSizeAxes = Axes.Both, + Y = swing_vertical_offset, + Height = 0.80f, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Children = new[] + { + stick = new Circle + { + Name = @"Stick", + RelativeSizeAxes = Axes.Y, + Colour = overlayColourProvider.Colour2, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Width = 4, + }, + weight = new Container + { + Name = @"Weight", + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + Colour = overlayColourProvider.Colour0, + Size = new Vector2(10), + Rotation = 180, + RelativePositionAxes = Axes.Y, + Y = 0.4f, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Shear = new Vector2(0.2f, 0), + EdgeSmoothness = new Vector2(1), + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Shear = new Vector2(-0.2f, 0), + EdgeSmoothness = new Vector2(1), + }, + } + }, + } + }, + new Container + { + Name = @"Taper adjust", + Masking = true, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Size = new Vector2(triangleSize.X, triangleSize.Y - taper), + Children = new Drawable[] + { + new Circle + { + Name = @"Locking wedge", + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + Colour = overlayColourProvider.Background1, + Size = new Vector2(8), + } + }, + }, + new Circle + { + Name = @"Swing connection point", + Y = swing_vertical_offset, + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + Colour = overlayColourProvider.Colour0, + Size = new Vector2(8) + }, + new Container + { + Name = @"Lower cover", + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Masking = true, + Height = lower_cover_height, + Children = new Drawable[] + { + new Triangle + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Size = triangleSize, + Colour = overlayColourProvider.Background2, + EdgeSmoothness = new Vector2(1), + Alpha = 0.8f + }, + } + }, + bpmText = new OsuSpriteText + { + Name = @"BPM display", + Colour = overlayColourProvider.Content1, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Y = -3, + }, + }; + } + + private double beatLength; + + private TimingControlPoint timingPoint; + + private bool isSwinging; + + private readonly BindableInt interpolatedBpm = new BindableInt(); + + protected override void LoadComplete() + { + base.LoadComplete(); + + interpolatedBpm.BindValueChanged(bpm => bpmText.Text = bpm.NewValue.ToString()); + } + + protected override void Update() + { + base.Update(); + + timingPoint = Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(BeatSyncClock.CurrentTime); + + if (beatLength != timingPoint.BeatLength) + { + beatLength = timingPoint.BeatLength; + + EarlyActivationMilliseconds = timingPoint.BeatLength / 2; + + float bpmRatio = (float)Interpolation.ApplyEasing(Easing.OutQuad, Math.Clamp((timingPoint.BPM - 30) / 480, 0, 1)); + + weight.MoveToY((float)Interpolation.Lerp(0.1f, 0.83f, bpmRatio), 600, Easing.OutQuint); + this.TransformBindableTo(interpolatedBpm, (int)timingPoint.BPM, 600, Easing.OutQuint); + } + + if (BeatSyncClock?.IsRunning != true && isSwinging) + { + swing.ClearTransforms(true); + + using (swing.BeginDelayedSequence(350)) + { + swing.RotateTo(0, 1000, Easing.OutQuint); + stick.FadeColour(overlayColourProvider.Colour2, 1000, Easing.OutQuint); + } + + isSwinging = false; + } + } + + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + { + base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); + + const float angle = 27.5f; + + if (!IsBeatSyncedWithTrack) + return; + + isSwinging = true; + + float currentAngle = swing.Rotation; + float targetAngle = currentAngle > 0 ? -angle : angle; + + swing.RotateTo(targetAngle, beatLength, Easing.InOutQuad); + + if (currentAngle != 0 && Math.Abs(currentAngle - targetAngle) > angle * 1.8f && isSwinging) + { + using (stick.BeginDelayedSequence(beatLength / 2)) + stick.FlashColour(overlayColourProvider.Content1, beatLength, Easing.OutQuint); + } + } + } +} diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index a99468fbff..1b0f0a3f5e 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -1,21 +1,15 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Utils; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Overlays; -using osuTK; namespace osu.Game.Screens.Edit.Timing { @@ -24,6 +18,9 @@ namespace osu.Game.Screens.Edit.Timing [Resolved] private EditorClock editorClock { get; set; } + [Resolved] + private Bindable selectedGroup { get; set; } + [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider, OsuColour colours) { @@ -52,7 +49,11 @@ namespace osu.Game.Screens.Edit.Timing { new Drawable[] { - new Metronome() + new MetronomeDisplay + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } }, new Drawable[] { @@ -74,7 +75,7 @@ namespace osu.Game.Screens.Edit.Timing { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - Text = "Tap to beat", + Text = "Play from start", RelativeSizeAxes = Axes.X, BackgroundColour = colourProvider.Background1, Width = 0.68f, @@ -90,252 +91,14 @@ namespace osu.Game.Screens.Edit.Timing private void tap() { - if (!editorClock.IsRunning) - { - editorClock.Seek(0); - editorClock.Start(); - } + editorClock.Seek(selectedGroup.Value.Time); + editorClock.Start(); } private void reset() { editorClock.Stop(); - } - - private class Metronome : BeatSyncedContainer - { - private Container swing; - - private OsuSpriteText bpmText; - - private Drawable weight; - private Drawable stick; - - [Resolved] - private OverlayColourProvider overlayColourProvider { get; set; } - - [BackgroundDependencyLoader] - private void load() - { - const float taper = 25; - const float swing_vertical_offset = -23; - const float lower_cover_height = 32; - - var triangleSize = new Vector2(90, 120 + taper); - - Margin = new MarginPadding(10); - - AutoSizeAxes = Axes.Both; - - InternalChildren = new Drawable[] - { - new Container - { - Name = @"Taper adjust", - Masking = true, - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Size = new Vector2(triangleSize.X, triangleSize.Y - taper), - Children = new Drawable[] - { - new Triangle - { - Name = @"Main body", - EdgeSmoothness = new Vector2(1), - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Size = triangleSize, - Colour = overlayColourProvider.Background3, - }, - }, - }, - new Circle - { - Name = "Centre marker", - Colour = overlayColourProvider.Background5, - RelativeSizeAxes = Axes.Y, - Width = 2, - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Y = -(lower_cover_height + 3), - Height = 0.65f, - }, - swing = new Container - { - Name = @"Swing", - RelativeSizeAxes = Axes.Both, - Y = swing_vertical_offset, - Height = 0.80f, - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Children = new[] - { - stick = new Circle - { - Name = @"Stick", - RelativeSizeAxes = Axes.Y, - Colour = overlayColourProvider.Colour2, - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Width = 4, - }, - weight = new Container - { - Name = @"Weight", - Anchor = Anchor.TopCentre, - Origin = Anchor.Centre, - Colour = overlayColourProvider.Colour0, - Size = new Vector2(10), - Rotation = 180, - RelativePositionAxes = Axes.Y, - Y = 0.4f, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Shear = new Vector2(0.2f, 0), - EdgeSmoothness = new Vector2(1), - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Shear = new Vector2(-0.2f, 0), - EdgeSmoothness = new Vector2(1), - }, - } - }, - } - }, - new Container - { - Name = @"Taper adjust", - Masking = true, - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Size = new Vector2(triangleSize.X, triangleSize.Y - taper), - Children = new Drawable[] - { - new Circle - { - Name = @"Locking wedge", - Anchor = Anchor.TopCentre, - Origin = Anchor.Centre, - Colour = overlayColourProvider.Background1, - Size = new Vector2(8), - } - }, - }, - new Circle - { - Name = @"Swing connection point", - Y = swing_vertical_offset, - Anchor = Anchor.BottomCentre, - Origin = Anchor.Centre, - Colour = overlayColourProvider.Colour0, - Size = new Vector2(8) - }, - new Container - { - Name = @"Lower cover", - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - RelativeSizeAxes = Axes.X, - Masking = true, - Height = lower_cover_height, - Children = new Drawable[] - { - new Triangle - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Size = triangleSize, - Colour = overlayColourProvider.Background2, - EdgeSmoothness = new Vector2(1), - Alpha = 0.8f - }, - } - }, - bpmText = new OsuSpriteText - { - Name = @"BPM display", - Colour = overlayColourProvider.Content1, - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Y = -3, - }, - }; - } - - private double beatLength; - - private TimingControlPoint timingPoint; - - private bool isSwinging; - - private readonly BindableInt interpolatedBpm = new BindableInt(); - - protected override void LoadComplete() - { - base.LoadComplete(); - - interpolatedBpm.BindValueChanged(bpm => bpmText.Text = bpm.NewValue.ToString()); - } - - protected override void Update() - { - base.Update(); - - timingPoint = Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(BeatSyncClock.CurrentTime); - - if (beatLength != timingPoint.BeatLength) - { - beatLength = timingPoint.BeatLength; - - EarlyActivationMilliseconds = timingPoint.BeatLength / 2; - - float bpmRatio = (float)Interpolation.ApplyEasing(Easing.OutQuad, Math.Clamp((timingPoint.BPM - 30) / 480, 0, 1)); - - weight.MoveToY((float)Interpolation.Lerp(0.1f, 0.83f, bpmRatio), 600, Easing.OutQuint); - this.TransformBindableTo(interpolatedBpm, (int)timingPoint.BPM, 600, Easing.OutQuint); - } - - if (BeatSyncClock?.IsRunning != true && isSwinging) - { - swing.ClearTransforms(true); - - using (swing.BeginDelayedSequence(350)) - { - swing.RotateTo(0, 1000, Easing.OutQuint); - stick.FadeColour(overlayColourProvider.Colour2, 1000, Easing.OutQuint); - } - - isSwinging = false; - } - } - - protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) - { - base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); - - const float angle = 27.5f; - - if (!IsBeatSyncedWithTrack) - return; - - isSwinging = true; - - float currentAngle = swing.Rotation; - float targetAngle = currentAngle > 0 ? -angle : angle; - - swing.RotateTo(targetAngle, beatLength, Easing.InOutQuad); - - if (currentAngle != 0 && Math.Abs(currentAngle - targetAngle) > angle * 1.8f && isSwinging) - { - using (stick.BeginDelayedSequence(beatLength / 2)) - stick.FlashColour(overlayColourProvider.Content1, beatLength, Easing.OutQuint); - } - } + editorClock.Seek(selectedGroup.Value.Time); } } } From 82eb5fd2c9007945d7432e22433ebeded94b7066 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 May 2022 17:21:56 +0900 Subject: [PATCH 10/21] Add centre line on weight --- osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index fdd5bd1e4e..5429165fe0 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Utils; @@ -99,7 +100,6 @@ namespace osu.Game.Screens.Edit.Timing Name = @"Weight", Anchor = Anchor.TopCentre, Origin = Anchor.Centre, - Colour = overlayColourProvider.Colour0, Size = new Vector2(10), Rotation = 180, RelativePositionAxes = Axes.Y, @@ -110,14 +110,25 @@ namespace osu.Game.Screens.Edit.Timing { RelativeSizeAxes = Axes.Both, Shear = new Vector2(0.2f, 0), + Colour = overlayColourProvider.Colour1, EdgeSmoothness = new Vector2(1), }, new Box { RelativeSizeAxes = Axes.Both, Shear = new Vector2(-0.2f, 0), + Colour = overlayColourProvider.Colour1, EdgeSmoothness = new Vector2(1), }, + new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = ColourInfo.GradientVertical(overlayColourProvider.Colour1, overlayColourProvider.Colour0), + RelativeSizeAxes = Axes.Y, + Width = 1, + Height = 0.9f + }, } }, } From c3bfbe888003f733137617e8629725bdadd1c506 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 May 2022 23:23:51 +0900 Subject: [PATCH 11/21] Allow `BeatSyncedContainer` to prefer `EditorBeatmap` when available --- .../TestSceneBeatSyncedContainer.cs | 19 +------------ .../Containers/BeatSyncedContainer.cs | 28 +++++++++++++------ 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs index ede89c6096..1881f6d718 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs @@ -258,24 +258,7 @@ namespace osu.Game.Tests.Visual.UserInterface }; } - protected override void LoadComplete() - { - base.LoadComplete(); - - Beatmap.BindValueChanged(_ => - { - timingPointCount.Value = 0; - currentTimingPoint.Value = 0; - beatCount.Value = 0; - currentBeat.Value = 0; - beatsPerMinute.Value = 0; - adjustedBeatLength.Value = 0; - timeUntilNextBeat.Value = 0; - timeSinceLastBeat.Value = 0; - }, true); - } - - private List timingPoints => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.ToList(); + private List timingPoints => Beatmap.ControlPointInfo.TimingPoints.ToList(); private TimingControlPoint getNextTimingPoint(TimingControlPoint current) { diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 2024d18570..48936f7aa9 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Screens.Edit; using osu.Game.Screens.Play; namespace osu.Game.Graphics.Containers @@ -79,20 +80,31 @@ namespace osu.Game.Graphics.Containers } [Resolved] - protected IBindable Beatmap { get; private set; } + private IBindable beatmap { get; set; } [Resolved(canBeNull: true)] protected GameplayClock GameplayClock { get; private set; } + [Resolved(canBeNull: true)] + protected EditorBeatmap EditorBeatmap { get; private set; } + + [Resolved(canBeNull: true)] + protected EditorClock EditorClock { get; private set; } + + protected IBeatmap Beatmap => EditorBeatmap ?? beatmap?.Value.Beatmap; + protected IClock BeatSyncClock { get { + if (EditorClock != null) + return EditorClock; + if (GameplayClock != null) return GameplayClock; - if (Beatmap.Value.TrackLoaded) - return Beatmap.Value.Track; + if (beatmap.Value.TrackLoaded) + return beatmap.Value.Track; return null; } @@ -101,7 +113,6 @@ namespace osu.Game.Graphics.Containers protected override void Update() { ITrack track = null; - IBeatmap beatmap = null; TimingControlPoint timingPoint; EffectControlPoint effectPoint; @@ -113,10 +124,9 @@ namespace osu.Game.Graphics.Containers double currentTrackTime = clock.CurrentTime + EarlyActivationMilliseconds; - if (Beatmap.Value.TrackLoaded && Beatmap.Value.BeatmapLoaded) + if (this.beatmap.Value.TrackLoaded && this.beatmap.Value.BeatmapLoaded) { - track = Beatmap.Value.Track; - beatmap = Beatmap.Value.Beatmap; + track = this.beatmap.Value.Track; } IsBeatSyncedWithTrack = beatmap != null && clock.IsRunning && track?.Length > 0; @@ -125,8 +135,8 @@ namespace osu.Game.Graphics.Containers { Debug.Assert(beatmap != null); - timingPoint = beatmap.ControlPointInfo.TimingPointAt(currentTrackTime); - effectPoint = beatmap.ControlPointInfo.EffectPointAt(currentTrackTime); + timingPoint = Beatmap.ControlPointInfo.TimingPointAt(currentTrackTime); + effectPoint = Beatmap.ControlPointInfo.EffectPointAt(currentTrackTime); } else { From 8db80b92bb04f642e58e95de70c6309e2be44876 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 May 2022 23:24:21 +0900 Subject: [PATCH 12/21] Fix metronome not using `EditorBeatmap` causing editor updates to not propagate immediately --- osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index 5429165fe0..d51d7b9c58 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Globalization; using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Bindables; @@ -30,6 +31,9 @@ namespace osu.Game.Screens.Edit.Timing [Resolved] private OverlayColourProvider overlayColourProvider { get; set; } + [Resolved] + private EditorBeatmap editorBeatmap { get; set; } + [BackgroundDependencyLoader] private void load() { @@ -205,14 +209,14 @@ namespace osu.Game.Screens.Edit.Timing { base.LoadComplete(); - interpolatedBpm.BindValueChanged(bpm => bpmText.Text = bpm.NewValue.ToString()); + interpolatedBpm.BindValueChanged(bpm => bpmText.Text = bpm.NewValue.ToString(CultureInfo.CurrentCulture)); } protected override void Update() { base.Update(); - timingPoint = Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(BeatSyncClock.CurrentTime); + timingPoint = editorBeatmap.ControlPointInfo.TimingPointAt(BeatSyncClock.CurrentTime); if (beatLength != timingPoint.BeatLength) { @@ -223,7 +227,7 @@ namespace osu.Game.Screens.Edit.Timing float bpmRatio = (float)Interpolation.ApplyEasing(Easing.OutQuad, Math.Clamp((timingPoint.BPM - 30) / 480, 0, 1)); weight.MoveToY((float)Interpolation.Lerp(0.1f, 0.83f, bpmRatio), 600, Easing.OutQuint); - this.TransformBindableTo(interpolatedBpm, (int)timingPoint.BPM, 600, Easing.OutQuint); + this.TransformBindableTo(interpolatedBpm, (int)Math.Round(timingPoint.BPM), 600, Easing.OutQuint); } if (BeatSyncClock?.IsRunning != true && isSwinging) From d3f115bfe2b321a9309be155995d44e6fc0423a4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 21 May 2022 13:53:58 +0900 Subject: [PATCH 13/21] Remove redundant qualifiers --- osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 48936f7aa9..bd46a20434 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -124,9 +124,9 @@ namespace osu.Game.Graphics.Containers double currentTrackTime = clock.CurrentTime + EarlyActivationMilliseconds; - if (this.beatmap.Value.TrackLoaded && this.beatmap.Value.BeatmapLoaded) + if (beatmap.Value.TrackLoaded && beatmap.Value.BeatmapLoaded) { - track = this.beatmap.Value.Track; + track = beatmap.Value.Track; } IsBeatSyncedWithTrack = beatmap != null && clock.IsRunning && track?.Length > 0; From 376549ce09a2570811ff8b7ea1e6ce3b1636b812 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 21 May 2022 21:48:51 +0900 Subject: [PATCH 14/21] Use `ToLocalisableString` instead of `CurrentCulture` --- osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index d51d7b9c58..98ce9f0f46 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -6,6 +6,7 @@ using System.Globalization; using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; @@ -209,7 +210,7 @@ namespace osu.Game.Screens.Edit.Timing { base.LoadComplete(); - interpolatedBpm.BindValueChanged(bpm => bpmText.Text = bpm.NewValue.ToString(CultureInfo.CurrentCulture)); + interpolatedBpm.BindValueChanged(bpm => bpmText.Text = bpm.NewValue.ToLocalisableString()); } protected override void Update() From 9a780bcad3b6e7e4b14fe11f3bc1f2c23c13c6d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 21 May 2022 21:56:05 +0900 Subject: [PATCH 15/21] Remove unused using --- osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index 98ce9f0f46..b59865ac1a 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Globalization; using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Bindables; From eabf57828276ce8ce2b2ad16305e54df271b34ed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 May 2022 22:15:53 +0900 Subject: [PATCH 16/21] Use interface to convey beat sync information --- .../TestSceneBeatSyncedContainer.cs | 22 +++++-- .../Containers/BeatSyncedContainer.cs | 65 ++++--------------- .../Graphics/Containers/IBeatSyncProvider.cs | 26 ++++++++ osu.Game/OsuGameBase.cs | 10 ++- osu.Game/Rulesets/Mods/MetronomeBeat.cs | 2 +- osu.Game/Screens/Edit/Editor.cs | 10 ++- .../Screens/Edit/Timing/MetronomeDisplay.cs | 12 ++-- .../Play/MasterGameplayClockContainer.cs | 8 ++- osu.Game/Screens/Play/Player.cs | 9 ++- 9 files changed, 96 insertions(+), 68 deletions(-) create mode 100644 osu.Game/Graphics/Containers/IBeatSyncProvider.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs index 1881f6d718..3cbb7daf51 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using NUnit.Framework; using osu.Framework.Audio.Track; @@ -82,11 +83,15 @@ namespace osu.Game.Tests.Visual.UserInterface if (!allowMistimed) { - AddAssert("trigger is near beat length", () => lastActuationTime != null && lastBeatIndex != null && Precision.AlmostEquals(lastTimingPoint.Time + lastBeatIndex.Value * lastTimingPoint.BeatLength, lastActuationTime.Value, BeatSyncedContainer.MISTIMED_ALLOWANCE)); + AddAssert("trigger is near beat length", + () => lastActuationTime != null && lastBeatIndex != null && Precision.AlmostEquals(lastTimingPoint.Time + lastBeatIndex.Value * lastTimingPoint.BeatLength, lastActuationTime.Value, + BeatSyncedContainer.MISTIMED_ALLOWANCE)); } else { - AddAssert("trigger is not near beat length", () => lastActuationTime != null && lastBeatIndex != null && !Precision.AlmostEquals(lastTimingPoint.Time + lastBeatIndex.Value * lastTimingPoint.BeatLength, lastActuationTime.Value, BeatSyncedContainer.MISTIMED_ALLOWANCE)); + AddAssert("trigger is not near beat length", + () => lastActuationTime != null && lastBeatIndex != null && !Precision.AlmostEquals(lastTimingPoint.Time + lastBeatIndex.Value * lastTimingPoint.BeatLength, + lastActuationTime.Value, BeatSyncedContainer.MISTIMED_ALLOWANCE)); } } @@ -258,7 +263,7 @@ namespace osu.Game.Tests.Visual.UserInterface }; } - private List timingPoints => Beatmap.ControlPointInfo.TimingPoints.ToList(); + private List timingPoints => BeatSyncSource.ControlPoints?.TimingPoints.ToList(); private TimingControlPoint getNextTimingPoint(TimingControlPoint current) { @@ -275,7 +280,11 @@ namespace osu.Game.Tests.Visual.UserInterface if (timingPoints.Count == 0) return 0; if (timingPoints[^1] == current) - return (int)Math.Ceiling((BeatSyncClock.CurrentTime - current.Time) / current.BeatLength); + { + Debug.Assert(BeatSyncSource.Clock != null); + + return (int)Math.Ceiling((BeatSyncSource.Clock.CurrentTime - current.Time) / current.BeatLength); + } return (int)Math.Ceiling((getNextTimingPoint(current).Time - current.Time) / current.BeatLength); } @@ -283,9 +292,12 @@ namespace osu.Game.Tests.Visual.UserInterface protected override void Update() { base.Update(); + + Debug.Assert(BeatSyncSource.Clock != null); + timeUntilNextBeat.Value = TimeUntilNextBeat; timeSinceLastBeat.Value = TimeSinceLastBeat; - currentTime.Value = BeatSyncClock.CurrentTime; + currentTime.Value = BeatSyncSource.Clock.CurrentTime; } public Action NewBeat; diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index bd46a20434..953731244d 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -5,12 +5,9 @@ using System; using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Audio.Track; -using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; -using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Screens.Edit; using osu.Game.Screens.Play; namespace osu.Game.Graphics.Containers @@ -75,74 +72,38 @@ namespace osu.Game.Graphics.Containers /// protected bool IsBeatSyncedWithTrack { get; private set; } + [Resolved] + protected IBeatSyncProvider BeatSyncSource { get; private set; } + protected virtual void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { } - [Resolved] - private IBindable beatmap { get; set; } - - [Resolved(canBeNull: true)] - protected GameplayClock GameplayClock { get; private set; } - - [Resolved(canBeNull: true)] - protected EditorBeatmap EditorBeatmap { get; private set; } - - [Resolved(canBeNull: true)] - protected EditorClock EditorClock { get; private set; } - - protected IBeatmap Beatmap => EditorBeatmap ?? beatmap?.Value.Beatmap; - - protected IClock BeatSyncClock - { - get - { - if (EditorClock != null) - return EditorClock; - - if (GameplayClock != null) - return GameplayClock; - - if (beatmap.Value.TrackLoaded) - return beatmap.Value.Track; - - return null; - } - } - protected override void Update() { - ITrack track = null; - TimingControlPoint timingPoint; EffectControlPoint effectPoint; - IClock clock = BeatSyncClock; + IsBeatSyncedWithTrack = BeatSyncSource.Clock?.IsRunning == true; - if (clock == null) - return; - - double currentTrackTime = clock.CurrentTime + EarlyActivationMilliseconds; - - if (beatmap.Value.TrackLoaded && beatmap.Value.BeatmapLoaded) - { - track = beatmap.Value.Track; - } - - IsBeatSyncedWithTrack = beatmap != null && clock.IsRunning && track?.Length > 0; + double currentTrackTime; if (IsBeatSyncedWithTrack) { - Debug.Assert(beatmap != null); + Debug.Assert(BeatSyncSource.ControlPoints != null); + Debug.Assert(BeatSyncSource.Clock != null); - timingPoint = Beatmap.ControlPointInfo.TimingPointAt(currentTrackTime); - effectPoint = Beatmap.ControlPointInfo.EffectPointAt(currentTrackTime); + currentTrackTime = BeatSyncSource.Clock.CurrentTime + EarlyActivationMilliseconds; + + timingPoint = BeatSyncSource.ControlPoints.TimingPointAt(currentTrackTime); + effectPoint = BeatSyncSource.ControlPoints.EffectPointAt(currentTrackTime); } else { // this may be the case where the beat syncing clock has been paused. // we still want to show an idle animation, so use this container's time instead. currentTrackTime = Clock.CurrentTime + EarlyActivationMilliseconds; + timingPoint = TimingControlPoint.DEFAULT; effectPoint = EffectControlPoint.DEFAULT; } @@ -172,7 +133,7 @@ namespace osu.Game.Graphics.Containers if (AllowMistimedEventFiring || Math.Abs(TimeSinceLastBeat) < MISTIMED_ALLOWANCE) { using (BeginDelayedSequence(-TimeSinceLastBeat)) - OnNewBeat(beatIndex, timingPoint, effectPoint, track?.CurrentAmplitudes ?? ChannelAmplitudes.Empty); + OnNewBeat(beatIndex, timingPoint, effectPoint, BeatSyncSource.Amplitudes ?? ChannelAmplitudes.Empty); } lastBeat = beatIndex; diff --git a/osu.Game/Graphics/Containers/IBeatSyncProvider.cs b/osu.Game/Graphics/Containers/IBeatSyncProvider.cs new file mode 100644 index 0000000000..d5be50297c --- /dev/null +++ b/osu.Game/Graphics/Containers/IBeatSyncProvider.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using osu.Framework.Allocation; +using osu.Framework.Audio.Track; +using osu.Framework.Timing; +using osu.Game.Beatmaps.ControlPoints; + +namespace osu.Game.Graphics.Containers +{ + /// + /// Provides various data sources which allow for synchronising visuals to a known beat. + /// Primarily intended for use with . + /// + [Cached(typeof(IBeatSyncProvider))] + public interface IBeatSyncProvider + { + ControlPointInfo? ControlPoints { get; } + + IClock? Clock { get; } + + ChannelAmplitudes? Amplitudes { get; } + } +} diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 2e4758a134..52052efd5d 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Development; using osu.Framework.Extensions; @@ -21,12 +22,15 @@ using osu.Framework.Input; using osu.Framework.IO.Stores; using osu.Framework.Logging; using osu.Framework.Platform; +using osu.Framework.Timing; using osu.Game.Audio; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Formats; using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Input; using osu.Game.Input.Bindings; @@ -52,7 +56,7 @@ namespace osu.Game /// Unlike , this class will not load any kind of UI, allowing it to be used /// for provide dependencies to test cases without interfering with them. /// - public partial class OsuGameBase : Framework.Game, ICanAcceptFiles + public partial class OsuGameBase : Framework.Game, ICanAcceptFiles, IBeatSyncProvider { public const string OSU_PROTOCOL = "osu://"; @@ -552,5 +556,9 @@ namespace osu.Game if (Host != null) Host.ExceptionThrown -= onExceptionThrown; } + + ControlPointInfo IBeatSyncProvider.ControlPoints => Beatmap.Value.Beatmap.ControlPointInfo; + IClock IBeatSyncProvider.Clock => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track : (IClock)null; + ChannelAmplitudes? IBeatSyncProvider.Amplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : (ChannelAmplitudes?)null; } } diff --git a/osu.Game/Rulesets/Mods/MetronomeBeat.cs b/osu.Game/Rulesets/Mods/MetronomeBeat.cs index c7a8b02130..149af1e30a 100644 --- a/osu.Game/Rulesets/Mods/MetronomeBeat.cs +++ b/osu.Game/Rulesets/Mods/MetronomeBeat.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Mods int timeSignature = timingPoint.TimeSignature.Numerator; // play metronome from one measure before the first object. - if (BeatSyncClock.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature) + if (BeatSyncSource.Clock?.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature) return; sample.Frequency.Value = beatIndex % timeSignature == 0 ? 1 : 0.5f; diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 3a2b195eed..a50a70374b 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -8,6 +8,7 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework; using osu.Framework.Allocation; +using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -19,11 +20,14 @@ using osu.Framework.Input.Events; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Screens; +using osu.Framework.Timing; using osu.Game.Audio; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; @@ -53,7 +57,7 @@ namespace osu.Game.Screens.Edit { [Cached(typeof(IBeatSnapProvider))] [Cached] - public class Editor : ScreenWithBeatmapBackground, IKeyBindingHandler, IKeyBindingHandler, IBeatSnapProvider, ISamplePlaybackDisabler + public class Editor : ScreenWithBeatmapBackground, IKeyBindingHandler, IKeyBindingHandler, IBeatSnapProvider, ISamplePlaybackDisabler, IBeatSyncProvider { public override float BackgroundParallaxAmount => 0.1f; @@ -954,5 +958,9 @@ namespace osu.Game.Screens.Edit public double GetBeatLengthAtTime(double referenceTime) => editorBeatmap.GetBeatLengthAtTime(referenceTime); public int BeatDivisor => beatDivisor.Value; + + ControlPointInfo IBeatSyncProvider.ControlPoints => editorBeatmap.ControlPointInfo; + IClock IBeatSyncProvider.Clock => clock; + ChannelAmplitudes? IBeatSyncProvider.Amplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : (ChannelAmplitudes?)null; } } diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index b59865ac1a..7b0b8440e6 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -31,9 +31,6 @@ namespace osu.Game.Screens.Edit.Timing [Resolved] private OverlayColourProvider overlayColourProvider { get; set; } - [Resolved] - private EditorBeatmap editorBeatmap { get; set; } - [BackgroundDependencyLoader] private void load() { @@ -216,7 +213,10 @@ namespace osu.Game.Screens.Edit.Timing { base.Update(); - timingPoint = editorBeatmap.ControlPointInfo.TimingPointAt(BeatSyncClock.CurrentTime); + if (BeatSyncSource.ControlPoints == null || BeatSyncSource.Clock == null) + return; + + timingPoint = BeatSyncSource.ControlPoints.TimingPointAt(BeatSyncSource.Clock.CurrentTime); if (beatLength != timingPoint.BeatLength) { @@ -230,7 +230,7 @@ namespace osu.Game.Screens.Edit.Timing this.TransformBindableTo(interpolatedBpm, (int)Math.Round(timingPoint.BPM), 600, Easing.OutQuint); } - if (BeatSyncClock?.IsRunning != true && isSwinging) + if (BeatSyncSource.Clock?.IsRunning != true && isSwinging) { swing.ClearTransforms(true); @@ -258,7 +258,7 @@ namespace osu.Game.Screens.Edit.Timing float currentAngle = swing.Rotation; float targetAngle = currentAngle > 0 ? -angle : angle; - swing.RotateTo(targetAngle, beatLength, Easing.InOutQuad); + swing.RotateTo(targetAngle, beatLength, Easing.InOutSine); if (currentAngle != 0 && Math.Abs(currentAngle - targetAngle) > angle * 1.8f && isSwinging) { diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index ea43fb1546..4ca5541362 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -12,8 +12,10 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Timing; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Configuration; using osu.Game.Database; +using osu.Game.Graphics.Containers; namespace osu.Game.Screens.Play { @@ -27,7 +29,7 @@ namespace osu.Game.Screens.Play /// /// This is intended to be used as a single controller for gameplay, or as a reference source for other s. /// - public class MasterGameplayClockContainer : GameplayClockContainer + public class MasterGameplayClockContainer : GameplayClockContainer, IBeatSyncProvider { /// /// Duration before gameplay start time required before skip button displays. @@ -250,6 +252,10 @@ namespace osu.Game.Screens.Play removeSourceClockAdjustments(); } + ControlPointInfo IBeatSyncProvider.ControlPoints => beatmap.Beatmap.ControlPointInfo; + IClock IBeatSyncProvider.Clock => GameplayClock; + ChannelAmplitudes? IBeatSyncProvider.Amplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : (ChannelAmplitudes?)null; + private class HardwareCorrectionOffsetClock : FramedOffsetClock { private readonly BindableDouble pauseRateAdjust; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 51c1e6b43b..cbd9b03c32 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; +using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; @@ -16,8 +17,10 @@ using osu.Framework.Input.Events; using osu.Framework.Logging; using osu.Framework.Screens; using osu.Framework.Threading; +using osu.Framework.Timing; using osu.Game.Audio; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.IO.Archives; @@ -38,7 +41,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play { [Cached] - public abstract class Player : ScreenWithBeatmapBackground, ISamplePlaybackDisabler, ILocalUserPlayInfo + public abstract class Player : ScreenWithBeatmapBackground, ISamplePlaybackDisabler, ILocalUserPlayInfo, IBeatSyncProvider { /// /// The delay upon completion of the beatmap before displaying the results screen. @@ -1108,5 +1111,9 @@ namespace osu.Game.Screens.Play IBindable ISamplePlaybackDisabler.SamplePlaybackDisabled => samplePlaybackDisabled; IBindable ILocalUserPlayInfo.IsPlaying => LocalUserPlaying; + + ControlPointInfo IBeatSyncProvider.ControlPoints => Beatmap.Value.Beatmap.ControlPointInfo; + IClock IBeatSyncProvider.Clock => GameplayClockContainer.GameplayClock; + ChannelAmplitudes? IBeatSyncProvider.Amplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : (ChannelAmplitudes?)null; } } From 3a7233bd6ed5e2a3784de1825ac58ea1ec7ae840 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 May 2022 22:49:24 +0900 Subject: [PATCH 17/21] Move interface to more appropriate namespace --- .../{Graphics/Containers => Beatmaps}/IBeatSyncProvider.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename osu.Game/{Graphics/Containers => Beatmaps}/IBeatSyncProvider.cs (91%) diff --git a/osu.Game/Graphics/Containers/IBeatSyncProvider.cs b/osu.Game/Beatmaps/IBeatSyncProvider.cs similarity index 91% rename from osu.Game/Graphics/Containers/IBeatSyncProvider.cs rename to osu.Game/Beatmaps/IBeatSyncProvider.cs index d5be50297c..573f06ef9f 100644 --- a/osu.Game/Graphics/Containers/IBeatSyncProvider.cs +++ b/osu.Game/Beatmaps/IBeatSyncProvider.cs @@ -7,8 +7,9 @@ using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Timing; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics.Containers; -namespace osu.Game.Graphics.Containers +namespace osu.Game.Beatmaps { /// /// Provides various data sources which allow for synchronising visuals to a known beat. From 007582afb9082782b1c18a61401a673198fe3370 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 May 2022 23:55:33 +0900 Subject: [PATCH 18/21] Remove unused usings resulting from namespace move --- osu.Game/OsuGameBase.cs | 1 - osu.Game/Screens/Edit/Editor.cs | 1 - osu.Game/Screens/Play/MasterGameplayClockContainer.cs | 1 - 3 files changed, 3 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 52052efd5d..ed2bfbc6e3 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -30,7 +30,6 @@ using osu.Game.Beatmaps.Formats; using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Input; using osu.Game.Input.Bindings; diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index a50a70374b..0bb3f51903 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -27,7 +27,6 @@ using osu.Game.Beatmaps.ControlPoints; using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 4ca5541362..d87d57ec49 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -15,7 +15,6 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Configuration; using osu.Game.Database; -using osu.Game.Graphics.Containers; namespace osu.Game.Screens.Play { From c9ea87e6be1885fdb18bcc4e93bf21b5d0ad11e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 May 2022 00:03:42 +0900 Subject: [PATCH 19/21] Revert easing for now --- osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index 7b0b8440e6..4dd7a75d4a 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -258,7 +258,7 @@ namespace osu.Game.Screens.Edit.Timing float currentAngle = swing.Rotation; float targetAngle = currentAngle > 0 ? -angle : angle; - swing.RotateTo(targetAngle, beatLength, Easing.InOutSine); + swing.RotateTo(targetAngle, beatLength, Easing.InOutQuad); if (currentAngle != 0 && Math.Abs(currentAngle - targetAngle) > angle * 1.8f && isSwinging) { From 267bef959fd7049dcf80557196cd211e3f81686f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 May 2022 02:00:04 +0900 Subject: [PATCH 20/21] Remove unnecessary cache type specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Beatmaps/IBeatSyncProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/IBeatSyncProvider.cs b/osu.Game/Beatmaps/IBeatSyncProvider.cs index 573f06ef9f..cc1cfc3cb5 100644 --- a/osu.Game/Beatmaps/IBeatSyncProvider.cs +++ b/osu.Game/Beatmaps/IBeatSyncProvider.cs @@ -15,7 +15,7 @@ namespace osu.Game.Beatmaps /// Provides various data sources which allow for synchronising visuals to a known beat. /// Primarily intended for use with . /// - [Cached(typeof(IBeatSyncProvider))] + [Cached] public interface IBeatSyncProvider { ControlPointInfo? ControlPoints { get; } From 9c3d0dafbdba852857197bf13dbc2879328dceb3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 May 2022 02:00:20 +0900 Subject: [PATCH 21/21] Remove implementation at `Player` level Turns out this isn't required in the end due to implementation at `MasterGameplayClockContainer`. --- osu.Game/Screens/Play/Player.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index cbd9b03c32..51c1e6b43b 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -8,7 +8,6 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; -using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; @@ -17,10 +16,8 @@ using osu.Framework.Input.Events; using osu.Framework.Logging; using osu.Framework.Screens; using osu.Framework.Threading; -using osu.Framework.Timing; using osu.Game.Audio; using osu.Game.Beatmaps; -using osu.Game.Beatmaps.ControlPoints; using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.IO.Archives; @@ -41,7 +38,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play { [Cached] - public abstract class Player : ScreenWithBeatmapBackground, ISamplePlaybackDisabler, ILocalUserPlayInfo, IBeatSyncProvider + public abstract class Player : ScreenWithBeatmapBackground, ISamplePlaybackDisabler, ILocalUserPlayInfo { /// /// The delay upon completion of the beatmap before displaying the results screen. @@ -1111,9 +1108,5 @@ namespace osu.Game.Screens.Play IBindable ISamplePlaybackDisabler.SamplePlaybackDisabled => samplePlaybackDisabled; IBindable ILocalUserPlayInfo.IsPlaying => LocalUserPlaying; - - ControlPointInfo IBeatSyncProvider.ControlPoints => Beatmap.Value.Beatmap.ControlPointInfo; - IClock IBeatSyncProvider.Clock => GameplayClockContainer.GameplayClock; - ChannelAmplitudes? IBeatSyncProvider.Amplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : (ChannelAmplitudes?)null; } }