Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add first pieces of editor timing UI #18339

Merged
merged 21 commits into from May 23, 2022
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs
Expand Up @@ -22,7 +22,7 @@ public class TestSceneOsuModMuted : OsuModTestScene
MuteComboCount = { Value = 0 },
},
PassCondition = () => Beatmap.Value.Track.AggregateVolume.Value == 0.0 &&
Player.ChildrenOfType<Metronome>().SingleOrDefault()?.AggregateVolume.Value == 1.0,
Player.ChildrenOfType<MetronomeBeat>().SingleOrDefault()?.AggregateVolume.Value == 1.0,
});

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs
Expand Up @@ -339,7 +339,7 @@ private void randomizeCirclePos(IReadOnlyList<OsuHitObject> hitObjects)

public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
{
drawableRuleset.Overlays.Add(new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime));
drawableRuleset.Overlays.Add(new MetronomeBeat(drawableRuleset.Beatmap.HitObjects.First().StartTime));
}

#endregion
Expand Down
116 changes: 116 additions & 0 deletions osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs
@@ -0,0 +1,116 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System.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<ControlPointGroup> selectedGroup = new Bindable<ControlPointGroup>();

private TapTimingControl control;

public TestSceneTapTimingControl()
{
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()
{
AddStep("click tap button", () =>
{
control.ChildrenOfType<RoundedButton>()
.Last()
.TriggerClick();
});

AddUntilStep("wait for track playing", () => Clock.IsRunning);

AddStep("click reset button", () =>
{
control.ChildrenOfType<RoundedButton>()
.First()
.TriggerClick();
});

AddUntilStep("wait for track stopped", () => !Clock.IsRunning);
}

[Test]
public void TestBasic()
{
AddStep("set low bpm", () =>
{
editorBeatmap.ControlPointInfo.TimingPoints.First().BeatLength = 1000;
});

AddStep("click tap button", () =>
{
control.ChildrenOfType<RoundedButton>()
.Last()
.TriggerClick();
});

AddSliderStep("BPM", 30, 400, 60, bpm => editorBeatmap.ControlPointInfo.TimingPoints.First().BeatLength = 60000f / bpm);
}

protected override void Dispose(bool isDisposing)
{
Beatmap.Disabled = false;
base.Dispose(isDisposing);
}
}
}
Expand Up @@ -258,24 +258,7 @@ public TestBeatSyncedContainer()
};
}

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<TimingControlPoint> timingPoints => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.ToList();
private List<TimingControlPoint> timingPoints => Beatmap.ControlPointInfo.TimingPoints.ToList();

private TimingControlPoint getNextTimingPoint(TimingControlPoint current)
{
Expand Down
28 changes: 19 additions & 9 deletions osu.Game/Graphics/Containers/BeatSyncedContainer.cs
Expand Up @@ -10,6 +10,7 @@
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
Expand Down Expand Up @@ -79,20 +80,31 @@ protected virtual void OnNewBeat(int beatIndex, TimingControlPoint timingPoint,
}

[Resolved]
protected IBindable<WorkingBeatmap> Beatmap { get; private set; }
private IBindable<WorkingBeatmap> 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; }
bdach marked this conversation as resolved.
Show resolved Hide resolved

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;
}
Expand All @@ -101,7 +113,6 @@ protected IClock BeatSyncClock
protected override void Update()
{
ITrack track = null;
IBeatmap beatmap = null;

TimingControlPoint timingPoint;
EffectControlPoint effectPoint;
Expand All @@ -113,10 +124,9 @@ protected override void Update()

double currentTrackTime = clock.CurrentTime + EarlyActivationMilliseconds;

if (Beatmap.Value.TrackLoaded && Beatmap.Value.BeatmapLoaded)
if (beatmap.Value.TrackLoaded && beatmap.Value.BeatmapLoaded)
{
track = Beatmap.Value.Track;
beatmap = Beatmap.Value.Beatmap;
track = beatmap.Value.Track;
}

IsBeatSyncedWithTrack = beatmap != null && clock.IsRunning && track?.Length > 0;
Expand All @@ -125,8 +135,8 @@ protected override void Update()
{
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
{
Expand Down
3 changes: 2 additions & 1 deletion osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs
Expand Up @@ -41,7 +41,8 @@ public abstract class LabelledDrawable<T> : CompositeDrawable

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;

/// <summary>
/// The component that is being displayed.
Expand Down
Expand Up @@ -11,14 +11,14 @@

namespace osu.Game.Rulesets.Mods
{
public class Metronome : BeatSyncedContainer, IAdjustableAudioComponent
public class MetronomeBeat : BeatSyncedContainer, IAdjustableAudioComponent
{
private readonly double firstHitTime;

private readonly PausableSkinnableSound sample;

/// <param name="firstHitTime">Start time of the first hit object, used for providing a count down.</param>
public Metronome(double firstHitTime)
public MetronomeBeat(double firstHitTime)
{
this.firstHitTime = firstHitTime;
AllowMistimedEventFiring = false;
Expand Down
6 changes: 3 additions & 3 deletions osu.Game/Rulesets/Mods/ModMuted.cs
Expand Up @@ -79,11 +79,11 @@ public void ApplyToDrawableRuleset(DrawableRuleset<TObject> drawableRuleset)
{
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)
Expand Down