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 "argon" variant of song progress display #22144

Merged
merged 37 commits into from
Jan 18, 2023
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0f1fe1d
refactor(hud/gameplay/SongProgress): Add interface to designate `Song…
ItsShamed Jan 9, 2023
f626519
feat(hud/gameplay): Add Argon variant of `SongProgressBar`
ItsShamed Jan 9, 2023
28d2d76
refactor(hud/gameplay/SongProgressInfo): minor changes to text positi…
ItsShamed Jan 9, 2023
5952cd0
feat(hud/gameplay): implement Argon song progress density graph (Segm…
ItsShamed Jan 9, 2023
91cde5f
feat(hud/gameplay): implement Argon variant of `SongProgress`
ItsShamed Jan 9, 2023
48deef4
test: adapt and create tests to cover new components
ItsShamed Jan 9, 2023
eac8e9f
test: make test not actually test anything
ItsShamed Jan 9, 2023
d2309fe
Merge branch 'master' into skin/argon-song-progress-cleaner
peppy Jan 12, 2023
4439698
Update osu.Game/Screens/Play/HUD/ArgonSongProgress.cs
ItsShamed Jan 12, 2023
65bd2e7
Merge branch 'master' into skin/argon-song-progress-cleaner
peppy Jan 17, 2023
b62b571
Fix `TierColours` assignment
peppy Jan 17, 2023
66441d4
test: remove test for ArgonSongProgressGraph
ItsShamed Jan 17, 2023
d91aa34
refactor(ArgonSongProgress): reorder layering and make density graph …
ItsShamed Jan 17, 2023
f1989ba
quality: remove unused `Darken` bindable boolean
ItsShamed Jan 17, 2023
45c5bd8
Simplify HUD test to not require casting to specific `ProgressBar` type
peppy Jan 18, 2023
afc12e0
Tidy up `ISongProgressBar` interface
peppy Jan 18, 2023
5429979
Combine common code into `SongProgress` base class
peppy Jan 18, 2023
f9dd3f6
Switch test to specifically target the argon verison of the progress bar
peppy Jan 18, 2023
e8770b8
Remove no longer necessary interface type
peppy Jan 18, 2023
742a026
Add comment mentioning why reference clock fallback logic is required
peppy Jan 18, 2023
5a272b4
Merge branch 'master' into skin/argon-song-progress-cleaner
peppy Jan 18, 2023
7266d8e
Move "show difficulty graph" settings back to respective implementati…
peppy Jan 18, 2023
1e5dd91
Adjust `SkinnableTestScene` to give more breathing room to `RelativeS…
peppy Jan 18, 2023
04c0a5d
Update `TestSceneSongProgress` to properly work with new implementation
peppy Jan 18, 2023
bfb7573
Prefix subclasses of `DefaultSongProgress` with `Default`
peppy Jan 18, 2023
8bfd853
Fix missing comment
peppy Jan 18, 2023
8030194
Use actual beatmap's hitobjects in test to better display density
peppy Jan 18, 2023
5ead85f
Limit catch-up speed in test to emulate gameplay
peppy Jan 18, 2023
42e9b2b
Tidy up clock logic in all `SongProgress` classes
peppy Jan 18, 2023
17c35cf
Merge branch 'frame-stable-cache' into skin/argon-song-progress-cleaner
peppy Jan 18, 2023
f3677ab
Simplify depth change logic
peppy Jan 18, 2023
01558a9
Tidy up height logic and allow hovering above bar for easier interaction
peppy Jan 18, 2023
67b40dd
Adjust the seek effect to feel better
peppy Jan 18, 2023
4cfb059
Merge branch 'frame-stable-cache' into skin/argon-song-progress-cleaner
peppy Jan 18, 2023
d4f2cd2
Fix broken test step
peppy Jan 18, 2023
b8b7442
Make `SongProgressInfo.ShowProgress` init-only (and remove duplicate …
bdach Jan 18, 2023
b62ff8d
Merge branch 'master' into skin/argon-song-progress-cleaner
bdach Jan 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
2 changes: 2 additions & 0 deletions osu.Game.Tests/Skins/SkinDeserialisationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ public class SkinDeserialisationTest
"Archives/modified-default-20220818.osk",
// Covers longest combo counter
"Archives/modified-default-20221012.osk",
// Covers Argon variant of song progress bar
"Archives/modified-argon-20221024.osk",
// Covers TextElement and BeatmapInfoDrawable
"Archives/modified-default-20221102.osk",
// Covers BPM counter.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ public void SetUp() => Schedule(() =>
{
var implementation = skin is LegacySkin
? CreateLegacyImplementation()
: CreateDefaultImplementation();
: skin is ArgonSkin
? CreateArgonImplementation()
: CreateDefaultImplementation();

implementation.Anchor = Anchor.Centre;
implementation.Origin = Anchor.Centre;
Expand All @@ -29,6 +31,7 @@ public void SetUp() => Schedule(() =>
});

protected abstract Drawable CreateDefaultImplementation();
protected virtual Drawable CreateArgonImplementation() => CreateDefaultImplementation();
protected abstract Drawable CreateLegacyImplementation();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
namespace osu.Game.Tests.Visual.Gameplay
{
[TestFixture]
public partial class TestSceneSongProgressGraph : OsuTestScene
public partial class TestSceneDefaultSongProgressGraph : OsuTestScene
{
private TestSongProgressGraph graph;

Expand Down Expand Up @@ -59,7 +59,7 @@ private void displayRandomValues()
graph.Objects = objects;
}

private partial class TestSongProgressGraph : SongProgressGraph
private partial class TestSongProgressGraph : DefaultSongProgressGraph
{
public int CreationCount { get; private set; }

Expand Down
6 changes: 3 additions & 3 deletions osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ public void TestHoldForMenuDoesWorkWhenHidden()
[Test]
public void TestInputDoesntWorkWhenHUDHidden()
{
SongProgressBar? getSongProgress() => hudOverlay.ChildrenOfType<SongProgressBar>().SingleOrDefault();
ArgonSongProgress? getSongProgress() => hudOverlay.ChildrenOfType<ArgonSongProgress>().SingleOrDefault();

bool seeked = false;

Expand All @@ -204,8 +204,8 @@ public void TestInputDoesntWorkWhenHUDHidden()

Debug.Assert(progress != null);

progress.ShowHandle = true;
progress.OnSeek += _ => seeked = true;
progress.Interactive.Value = true;
progress.ChildrenOfType<ArgonSongProgressBar>().Single().OnSeek += _ => seeked = true;
});

AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false);
Expand Down
66 changes: 39 additions & 27 deletions osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.HUD;
using osu.Game.Skinning;
Expand All @@ -28,50 +28,62 @@ private void load()
{
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);

Add(gameplayClockContainer = new MasterGameplayClockContainer(Beatmap.Value, skip_target_time));
FrameStabilityContainer frameStabilityContainer;

Add(gameplayClockContainer = new MasterGameplayClockContainer(Beatmap.Value, skip_target_time)
{
Child = frameStabilityContainer = new FrameStabilityContainer
{
MaxCatchUpFrames = 1
}
});

Dependencies.CacheAs<IGameplayClock>(gameplayClockContainer);
Dependencies.CacheAs<IFrameStableClock>(frameStabilityContainer);
}

[SetUpSteps]
public void SetupSteps()
{
AddStep("reset clock", () => gameplayClockContainer.Reset());
AddStep("set hit objects", setHitObjects);
}

[Test]
public void TestDisplay()
{
AddStep("set hit objects", () => this.ChildrenOfType<SongProgress>().ForEach(progress => progress.Objects = Beatmap.Value.Beatmap.HitObjects));
AddStep("hook seeking", () =>
{
applyToDefaultProgress(d => d.ChildrenOfType<DefaultSongProgressBar>().Single().OnSeek += t => gameplayClockContainer.Seek(t));
applyToArgonProgress(d => d.ChildrenOfType<ArgonSongProgressBar>().Single().OnSeek += t => gameplayClockContainer.Seek(t));
});
AddStep("seek to intro", () => gameplayClockContainer.Seek(skip_target_time));
AddStep("start", gameplayClockContainer.Start);
AddStep("stop", gameplayClockContainer.Stop);
AddStep("start", () => gameplayClockContainer.Start());
}

[Test]
public void TestToggleSeeking()
public void TestBasic()
{
void applyToDefaultProgress(Action<DefaultSongProgress> action) =>
this.ChildrenOfType<DefaultSongProgress>().ForEach(action);

AddStep("allow seeking", () => applyToDefaultProgress(s => s.AllowSeeking.Value = true));
AddStep("hide graph", () => applyToDefaultProgress(s => s.ShowGraph.Value = false));
AddStep("disallow seeking", () => applyToDefaultProgress(s => s.AllowSeeking.Value = false));
AddStep("allow seeking", () => applyToDefaultProgress(s => s.AllowSeeking.Value = true));
AddStep("show graph", () => applyToDefaultProgress(s => s.ShowGraph.Value = true));
}
AddToggleStep("toggle seeking", b =>
{
applyToDefaultProgress(s => s.Interactive.Value = b);
applyToArgonProgress(s => s.Interactive.Value = b);
});

private void setHitObjects()
{
var objects = new List<HitObject>();
for (double i = 0; i < 5000; i++)
objects.Add(new HitObject { StartTime = i });
AddToggleStep("toggle graph", b =>
{
applyToDefaultProgress(s => s.ShowGraph.Value = b);
applyToArgonProgress(s => s.ShowGraph.Value = b);
});

this.ChildrenOfType<SongProgress>().ForEach(progress => progress.Objects = objects);
AddStep("stop", gameplayClockContainer.Stop);
}

private void applyToArgonProgress(Action<ArgonSongProgress> action) =>
this.ChildrenOfType<ArgonSongProgress>().ForEach(action);

private void applyToDefaultProgress(Action<DefaultSongProgress> action) =>
this.ChildrenOfType<DefaultSongProgress>().ForEach(action);

protected override Drawable CreateDefaultImplementation() => new DefaultSongProgress();

protected override Drawable CreateArgonImplementation() => new ArgonSongProgress();

protected override Drawable CreateLegacyImplementation() => new LegacySongProgress();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public void TestSpectatorPlayerInteractiveElementsHidden()
AddUntilStep("all interactive elements removed", () => this.ChildrenOfType<Player>().All(p =>
!p.ChildrenOfType<PlayerSettingsOverlay>().Any() &&
!p.ChildrenOfType<HoldForMenuButton>().Any() &&
p.ChildrenOfType<SongProgressBar>().SingleOrDefault()?.ShowHandle == false));
p.ChildrenOfType<ArgonSongProgressBar>().SingleOrDefault()?.Interactive == false));

AddStep("restore config hud visibility", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue));
}
Expand Down
9 changes: 3 additions & 6 deletions osu.Game/Graphics/UserInterface/SegmentedGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,14 @@ public T[] Values
}
}

private Colour4[] tierColours;
private IReadOnlyList<Colour4> tierColours;

public Colour4[] TierColours
public IReadOnlyList<Colour4> TierColours
{
get => tierColours;
set
{
if (value.Length == 0 || value == tierColours)
return;

tierCount = value.Length;
tierCount = value.Count;
tierColours = value;

graphNeedsUpdate = true;
Expand Down
118 changes: 118 additions & 0 deletions osu.Game/Screens/Play/HUD/ArgonSongProgress.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Objects;

namespace osu.Game.Screens.Play.HUD
{
public partial class ArgonSongProgress : SongProgress
{
private readonly SongProgressInfo info;
private readonly ArgonSongProgressGraph graph;
private readonly ArgonSongProgressBar bar;
private readonly Container graphContainer;

private const float bar_height = 10;

[SettingSource("Show difficulty graph", "Whether a graph displaying difficulty throughout the beatmap should be shown")]
public Bindable<bool> ShowGraph { get; } = new BindableBool(true);

[Resolved]
private Player? player { get; set; }

public ArgonSongProgress()
{
Anchor = Anchor.BottomCentre;
Origin = Anchor.BottomCentre;
Masking = true;
CornerRadius = 5;
Children = new Drawable[]
{
info = new SongProgressInfo
{
Origin = Anchor.TopLeft,
Name = "Info",
Anchor = Anchor.TopLeft,
RelativeSizeAxes = Axes.X,
ShowProgress = false
},
bar = new ArgonSongProgressBar(bar_height)
{
Name = "Seek bar",
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
OnSeek = time => player?.Seek(time),
},
graphContainer = new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Masking = true,
CornerRadius = 5,
Child = graph = new ArgonSongProgressGraph
{
Name = "Difficulty graph",
RelativeSizeAxes = Axes.Both,
Blending = BlendingParameters.Additive
},
RelativeSizeAxes = Axes.X,
},
};
RelativeSizeAxes = Axes.X;
}

[BackgroundDependencyLoader]
private void load()
{
info.ShowProgress = false;
info.TextColour = Colour4.White;
info.Font = OsuFont.Torus.With(size: 18, weight: FontWeight.Bold);
}

protected override void LoadComplete()
{
base.LoadComplete();

Interactive.BindValueChanged(_ => bar.Interactive = Interactive.Value, true);
ShowGraph.BindValueChanged(_ => updateGraphVisibility(), true);
}

protected override void UpdateObjects(IEnumerable<HitObject> objects)
{
graph.Objects = objects;

info.StartTime = bar.StartTime = FirstHitTime;
info.EndTime = bar.EndTime = LastHitTime;
}

private void updateGraphVisibility()
{
graph.FadeTo(ShowGraph.Value ? 1 : 0, 200, Easing.In);
bar.ShowBackground = !ShowGraph.Value;
}

protected override void Update()
{
base.Update();
Height = bar.Height + bar_height + info.Height;
graphContainer.Height = bar.Height;
}

protected override void UpdateProgress(double progress, bool isIntro)
{
bar.TrackTime = GameplayClock.CurrentTime;

if (isIntro)
bar.CurrentTime = 0;
else
bar.CurrentTime = FrameStableClock.CurrentTime;
}
}
}
Loading