make SongProgress abstract

- move unrelated logic to `DefaultSongProgress`
- make `LegacySongProgress` inherit `SongProgress`
This commit is contained in:
Nitrous 2022-07-27 15:19:21 +08:00
parent a12676c25d
commit 37e642b0bd
No known key found for this signature in database
GPG Key ID: 85EC4A6AE8F69D64
8 changed files with 126 additions and 91 deletions

View File

@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual.Gameplay
[TestFixture] [TestFixture]
public class TestSceneSongProgress : OsuTestScene public class TestSceneSongProgress : OsuTestScene
{ {
private SongProgress progress; private DefaultSongProgress progress;
private TestSongProgressGraph graph; private TestSongProgressGraph graph;
private readonly Container progressContainer; private readonly Container progressContainer;
@ -62,7 +62,7 @@ namespace osu.Game.Tests.Visual.Gameplay
progress = null; progress = null;
} }
progressContainer.Add(progress = new SongProgress progressContainer.Add(progress = new DefaultSongProgress
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Anchor = Anchor.BottomLeft, Anchor = Anchor.BottomLeft,

View File

@ -5,12 +5,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Timing;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
@ -18,9 +15,9 @@ using osu.Game.Rulesets.UI;
using osu.Game.Skinning; using osu.Game.Skinning;
using osuTK; using osuTK;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play.HUD
{ {
public class SongProgress : OverlayContainer, ISkinnableDrawable public class DefaultSongProgress : SongProgress
{ {
public const float MAX_HEIGHT = info_height + bottom_bar_height + graph_height + handle_height; public const float MAX_HEIGHT = info_height + bottom_bar_height + graph_height + handle_height;
@ -52,41 +49,13 @@ namespace osu.Game.Screens.Play
protected override bool BlockScrollInput => false; protected override bool BlockScrollInput => false;
private double firstHitTime => objects.First().StartTime;
//TODO: this isn't always correct (consider mania where a non-last object may last for longer than the last in the list).
private double lastHitTime => objects.Last().GetEndTime() + 1;
private IEnumerable<HitObject> objects;
public IEnumerable<HitObject> Objects
{
set
{
graph.Objects = objects = value;
info.StartTime = firstHitTime;
info.EndTime = lastHitTime;
bar.StartTime = firstHitTime;
bar.EndTime = lastHitTime;
}
}
[Resolved(canBeNull: true)] [Resolved(canBeNull: true)]
private Player player { get; set; } private Player player { get; set; }
[Resolved]
private GameplayClock gameplayClock { get; set; }
[Resolved(canBeNull: true)] [Resolved(canBeNull: true)]
private DrawableRuleset drawableRuleset { get; set; } private DrawableRuleset drawableRuleset { get; set; }
private IClock referenceClock; public DefaultSongProgress()
public bool UsesFixedAnchor { get; set; }
public SongProgress()
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Anchor = Anchor.BottomRight; Anchor = Anchor.BottomRight;
@ -127,9 +96,6 @@ namespace osu.Game.Screens.Play
{ {
if (player?.Configuration.AllowUserInteraction == true) if (player?.Configuration.AllowUserInteraction == true)
((IBindable<bool>)AllowSeeking).BindTo(drawableRuleset.HasReplayLoaded); ((IBindable<bool>)AllowSeeking).BindTo(drawableRuleset.HasReplayLoaded);
referenceClock = drawableRuleset.FrameStableClock;
Objects = drawableRuleset.Objects;
} }
graph.FillColour = bar.FillColour = colours.BlueLighter; graph.FillColour = bar.FillColour = colours.BlueLighter;
@ -203,21 +169,24 @@ namespace osu.Game.Screens.Play
this.FadeOut(100); this.FadeOut(100);
} }
protected override void UpdateObjects(IEnumerable<HitObject> objects)
{
graph.Objects = objects;
info.StartTime = FirstHitTime;
info.EndTime = LastHitTime;
bar.StartTime = FirstHitTime;
bar.EndTime = LastHitTime;
}
protected override void UpdateProgress(double progress, double time, bool isIntro)
{
bar.CurrentTime = time;
graph.Progress = (int)(graph.ColumnCount * progress);
}
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
if (objects == null)
return;
double gameplayTime = gameplayClock?.CurrentTime ?? Time.Current;
double frameStableTime = referenceClock?.CurrentTime ?? gameplayTime;
double progress = Math.Min(1, (frameStableTime - firstHitTime) / (lastHitTime - firstHitTime));
bar.CurrentTime = gameplayTime;
graph.Progress = (int)(graph.ColumnCount * progress);
Height = bottom_bar_height + graph_height + handle_size.Y + info_height - graph.Y; Height = bottom_bar_height + graph_height + handle_size.Y + info_height - graph.Y;
} }

View File

@ -0,0 +1,85 @@
// 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.
#nullable disable
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.UI;
using osu.Game.Skinning;
namespace osu.Game.Screens.Play.HUD
{
public abstract class SongProgress : OverlayContainer, ISkinnableDrawable
{
public bool UsesFixedAnchor { get; set; }
[Resolved]
private GameplayClock gameplayClock { get; set; }
[Resolved(canBeNull: true)]
private DrawableRuleset drawableRuleset { get; set; }
[Resolved(canBeNull: true)]
private IBindable<WorkingBeatmap> beatmap { get; set; }
private IClock referenceClock;
private IEnumerable<HitObject> objects;
public IEnumerable<HitObject> Objects
{
set => UpdateObjects(objects = value);
}
protected double FirstHitTime => objects.FirstOrDefault()?.StartTime ?? 0;
//TODO: this isn't always correct (consider mania where a non-last object may last for longer than the last in the list).
protected double LastHitTime => objects.LastOrDefault()?.GetEndTime() ?? 0;
protected double FirstEventTime { get; private set; }
protected abstract void UpdateProgress(double progress, double time, bool isIntro);
protected abstract void UpdateObjects(IEnumerable<HitObject> objects);
[BackgroundDependencyLoader]
private void load()
{
if (drawableRuleset != null)
{
Objects = drawableRuleset.Objects;
referenceClock = drawableRuleset.FrameStableClock;
}
if (beatmap != null)
{
FirstEventTime = beatmap.Value.Storyboard.EarliestEventTime ?? 0;
}
}
protected override void Update()
{
base.Update();
if (objects == null)
return;
double gameplayTime = gameplayClock?.CurrentTime ?? Time.Current;
double frameStableTime = referenceClock?.CurrentTime ?? gameplayTime;
if (frameStableTime < FirstHitTime)
{
UpdateProgress((frameStableTime - FirstEventTime) / (FirstHitTime - FirstEventTime), gameplayTime, true);
}
else
{
UpdateProgress((frameStableTime - FirstHitTime) / (LastHitTime - FirstHitTime), gameplayTime, false);
}
}
}
}

View File

@ -13,7 +13,7 @@ using osu.Framework.Graphics.UserInterface;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Framework.Threading; using osu.Framework.Threading;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play.HUD
{ {
public class SongProgressBar : SliderBar<double> public class SongProgressBar : SliderBar<double>
{ {

View File

@ -8,7 +8,7 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play.HUD
{ {
public class SongProgressGraph : SquareGraph public class SongProgressGraph : SquareGraph
{ {

View File

@ -10,7 +10,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using System; using System;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play.HUD
{ {
public class SongProgressInfo : Container public class SongProgressInfo : Container
{ {

View File

@ -147,7 +147,7 @@ namespace osu.Game.Skinning
new DefaultScoreCounter(), new DefaultScoreCounter(),
new DefaultAccuracyCounter(), new DefaultAccuracyCounter(),
new DefaultHealthDisplay(), new DefaultHealthDisplay(),
new SongProgress(), new DefaultSongProgress(),
new BarHitErrorMeter(), new BarHitErrorMeter(),
new BarHitErrorMeter(), new BarHitErrorMeter(),
new PerformancePointsCounter() new PerformancePointsCounter()

View File

@ -3,38 +3,20 @@
#nullable disable #nullable disable
using System; using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.UI; using osu.Game.Screens.Play.HUD;
using osu.Game.Screens.Play;
using osuTK; using osuTK;
namespace osu.Game.Skinning namespace osu.Game.Skinning
{ {
public class LegacySongProgress : CompositeDrawable, ISkinnableDrawable public class LegacySongProgress : SongProgress
{ {
public bool UsesFixedAnchor { get; set; }
[Resolved]
private GameplayClock gameplayClock { get; set; }
[Resolved(canBeNull: true)]
private DrawableRuleset drawableRuleset { get; set; }
[Resolved(canBeNull: true)]
private IBindable<WorkingBeatmap> beatmap { get; set; }
private double lastHitTime;
private double firstHitTime;
private double firstEventTime;
private CircularProgress pie; private CircularProgress pie;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -76,36 +58,35 @@ namespace osu.Game.Skinning
Size = new Vector2(3), Size = new Vector2(3),
} }
}; };
firstEventTime = beatmap?.Value.Storyboard.EarliestEventTime ?? 0;
if (drawableRuleset != null)
{
firstHitTime = drawableRuleset.Objects.First().StartTime;
//TODO: this isn't always correct (consider mania where a non-last object may last for longer than the last in the list).
lastHitTime = drawableRuleset.Objects.Last().GetEndTime() + 1;
}
} }
protected override void Update() protected override void PopIn()
{ {
base.Update(); }
double gameplayTime = gameplayClock?.CurrentTime ?? Time.Current; protected override void PopOut()
{
}
if (gameplayTime < firstHitTime) protected override void UpdateObjects(IEnumerable<HitObject> objects)
{
}
protected override void UpdateProgress(double progress, double time, bool isIntro)
{
if (isIntro)
{ {
pie.Scale = new Vector2(-1, 1); pie.Scale = new Vector2(-1, 1);
pie.Anchor = Anchor.TopRight; pie.Anchor = Anchor.TopRight;
pie.Colour = new Colour4(199, 255, 47, 153); pie.Colour = new Colour4(199, 255, 47, 153);
pie.Current.Value = 1 - Math.Clamp((gameplayTime - firstEventTime) / (firstHitTime - firstEventTime), 0, 1); pie.Current.Value = 1 - progress;
} }
else else
{ {
pie.Scale = new Vector2(1); pie.Scale = new Vector2(1);
pie.Anchor = Anchor.TopLeft; pie.Anchor = Anchor.TopLeft;
pie.Colour = new Colour4(255, 255, 255, 153); pie.Colour = new Colour4(255, 255, 255, 153);
pie.Current.Value = Math.Clamp((gameplayTime - firstHitTime) / (lastHitTime - firstHitTime), 0, 1); pie.Current.Value = progress;
} }
} }
} }