-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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 delayed resume for taiko/catch/mania #27079
Conversation
The lack of any visual cue here is bothering me. It's almost like a second pause, I find myself struggling to anticipate the moment where gameplay resumes. Maybe we could do something super simple like this even at least? (very rough) diff --git a/osu.Game/Screens/Play/DelayedResumeOverlay.cs b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
index ef39c8eb76..5dfbb681c9 100644
--- a/osu.Game/Screens/Play/DelayedResumeOverlay.cs
+++ b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
@@ -1,6 +1,9 @@
// 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 osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
using osu.Framework.Threading;
@@ -14,10 +17,24 @@ public partial class DelayedResumeOverlay : ResumeOverlay
protected override LocalisableString Message => string.Empty;
private ScheduledDelegate? scheduledResume;
+ private Box background = null!;
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Add(background = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Colour4.Black,
+ Alpha = 0.75f,
+ });
+ }
protected override void PopIn()
{
- base.PopIn();
+ this.FadeIn();
+ background.FadeIn()
+ .Then().FadeOut(800, Easing.OutSine);
scheduledResume?.Cancel();
scheduledResume = Scheduler.AddDelayed(Resume, 800);
@@ -25,7 +42,8 @@ protected override void PopIn()
protected override void PopOut()
{
- base.PopOut();
+ this.FadeOut();
+
scheduledResume?.Cancel();
}
}
|
I didn't really like the fading overlay because it doesn't work well with the classic taiko skin. I tried to add a countdown instead: https://drive.google.com/file/d/1wAnOjFAirLGd7cn2jULz0A7sl0jD2q0q/view?usp=sharing |
AutoSizeAxes = Axes.Both, | ||
Masking = true, | ||
BorderColour = colours.Yellow, | ||
BorderThickness = 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the animation in general - it's obviously going to be subjective but I find myself wanting to apply a few improvements to it, namely:
- It zooms in too fast for my liking, I'd increase the countdown interval
- The fade-in is concurrent with the counting, I'd like it not to be
Something like the following feels better to me personally, so open to thoughts on that:
diff --git a/osu.Game/Screens/Play/DelayedResumeOverlay.cs b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
index 08d00f8ac2..9c23bf5cfa 100644
--- a/osu.Game/Screens/Play/DelayedResumeOverlay.cs
+++ b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
@@ -21,7 +21,7 @@ namespace osu.Game.Screens.Play
/// </summary>
public partial class DelayedResumeOverlay : ResumeOverlay
{
- private const double countdown_time = 800;
+ private const double countdown_time = 1000;
protected override LocalisableString Message => string.Empty;
@@ -97,7 +97,7 @@ protected override void PopIn()
content.ScaleTo(new Vector2(1.5f, 1)).Then().ScaleTo(1, 150, Easing.OutElasticQuarter);
countdownCount = 3;
- countdownStartTime = Time.Current;
+ countdownStartTime = content.LatestTransformEndTime;
scheduledResume?.Cancel();
scheduledResume = Scheduler.AddDelayed(Resume, countdown_time);
@@ -114,7 +114,7 @@ private void updateCountdown()
double amountTimePassed = Math.Min(countdown_time, Time.Current - countdownStartTime) / countdown_time;
int newCount = 3 - (int)Math.Floor(amountTimePassed * 3);
- if (newCount > 0)
+ if (newCount > 0 && newCount <= 3)
{
countdown.Alpha = 1;
countdown.Text = newCount.ToString();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kind of don't really like the delay, because it feels empty for the first little bit and then it jumps. I have this other idea in mind, which might fit better?
diff --git a/osu.Game/Screens/Play/DelayedResumeOverlay.cs b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
index ba49810b2b..ca4a421bd4 100644
--- a/osu.Game/Screens/Play/DelayedResumeOverlay.cs
+++ b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
@@ -4,8 +4,6 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Framework.Threading;
@@ -21,7 +19,7 @@ namespace osu.Game.Screens.Play
/// </summary>
public partial class DelayedResumeOverlay : ResumeOverlay
{
- private const double countdown_time = 800;
+ private const double countdown_time = 1000;
protected override LocalisableString Message => string.Empty;
@@ -32,7 +30,6 @@ public partial class DelayedResumeOverlay : ResumeOverlay
private int countdownCount = 3;
private double countdownStartTime;
- private Drawable content = null!;
private SpriteText countdown = null!;
public DelayedResumeOverlay()
@@ -44,48 +41,16 @@ public DelayedResumeOverlay()
[BackgroundDependencyLoader]
private void load()
{
- Add(content = new CircularContainer
+ Add(countdown = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- AutoSizeAxes = Axes.Both,
- Masking = true,
- BorderColour = colours.Yellow,
- BorderThickness = 2,
- Children = new Drawable[]
- {
- new Box
- {
- Size = new Vector2(250, 40),
- Colour = Color4.Black,
- Alpha = 0.8f
- },
- new Container
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- AutoSizeAxes = Axes.Both,
- Children = new Drawable[]
- {
- new FillFlowContainer
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- AutoSizeAxes = Axes.Both,
- Spacing = new Vector2(5),
- Colour = colours.Yellow,
- Child = countdown = new OsuSpriteText
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- UseFullGlyphHeight = false,
- AlwaysPresent = true,
- Font = OsuFont.Numeric.With(size: 20, fixedWidth: true)
- },
- }
- }
- }
- }
+ UseFullGlyphHeight = false,
+ Colour = colours.Yellow,
+ Font = OsuFont.Numeric.With(size: 40, fixedWidth: true),
+ // Harsh shadow to make this visible on top of a wide range of backgrounds.
+ Shadow = true,
+ ShadowColour = Color4.Black
});
}
@@ -93,10 +58,7 @@ protected override void PopIn()
{
this.FadeIn();
- content.FadeInFromZero(150, Easing.OutQuint);
- content.ScaleTo(new Vector2(1.5f, 1)).Then().ScaleTo(1, 150, Easing.OutElasticQuarter);
-
- countdownCount = 3;
+ countdownCount = -1;
countdownStartTime = Time.Current;
scheduledResume?.Cancel();
@@ -111,23 +73,17 @@ protected override void Update()
private void updateCountdown()
{
- double amountTimePassed = Math.Min(countdown_time, Time.Current - countdownStartTime) / countdown_time;
+ double amountTimePassed = Math.Clamp(Time.Current - countdownStartTime, 0, countdown_time) / countdown_time;
int newCount = 3 - (int)Math.Floor(amountTimePassed * 3);
- if (newCount > 0)
- {
- countdown.Alpha = 1;
- countdown.Text = newCount.ToString();
- }
- else
- countdown.Alpha = 0;
+ countdown.Text = newCount > 0 ? newCount.ToString() : "GO";
if (newCount != countdownCount)
{
if (newCount == 0)
- content.ScaleTo(new Vector2(1.5f, 1), 150, Easing.OutQuint);
+ countdown.ScaleTo(new Vector2(1.25f, 1), 150, Easing.OutQuint);
else
- content.ScaleTo(new Vector2(1.05f, 1), 50, Easing.OutQuint).Then().ScaleTo(1, 50, Easing.Out);
+ countdown.ScaleTo(1.5f, 50, Easing.OutQuint).Then().ScaleTo(1, 50, Easing.Out);
}
countdownCount = newCount;
@@ -135,10 +91,7 @@ private void updateCountdown()
protected override void PopOut()
{
- this.Delay(150).FadeOut();
-
- content.FadeOut(150, Easing.OutQuint);
-
+ this.FadeOut(150, Easing.Out);
scheduledResume?.Cancel();
}
}
In the future this should probably use the countdown display from gameplay, which more closely matches this, but that isn't implemented yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kind of don't really like the delay, because it feels empty for the first little bit and then it jumps.
I'm not gonna insist on that too much, just bumping the interval is enough as far as I'm concerned.
I have this other idea in mind, which might fit better?
Can't say I like this other proposal too much :/ The background is important, it ensures that the count-in is actually seen. While a plain counter sometimes just isn't doing enough visually to cut through everything else for me:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's why I added the background in the first place, and tried to make it look "good"... :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dunno, why are we dev-designing this when we have a full time designer? None of the above seem any good to me. The animations and presence are off.
@arflyte please advise by end of week so we can get this in the game, just need anything that looks better than these proposals. including animation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a little bit of my own flavour to it because the countdown felt a little bit empty, but how does this look?
https://drive.google.com/file/d/1wesAUY891v9PphMWxXutfYs5aAIiiRf7/view?usp=sharing
https://drive.google.com/file/d/1wg8NUfX9E7rM6vMIrCt1AVU6cVTC-0HO/view?usp=sharing
(videos are 120fps if downloaded)
One thing I'm not sure about is it looks like this was intended to be centred to the screen whereas this is currently centred to the playfield. I thought it'd look worse than it does but still need opinions.
@arflyte please advise further.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How it looks with a reduced timer (videos above are 3s, old was 800ms, this is 1sec):
https://drive.google.com/file/d/1wlNhXZoWD8p0OmcnYXlNdn1Jya8juf03/view?usp=sharing
And without the outer bounce:
https://drive.google.com/file/d/1wmJ3srApVAoKKZRDeT8xSEunwEFzZ126/view?usp=sharing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is okay as a starting point, I'll apply some changes of my own on top of this though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not flyte, but I think the counter needs a different background colour with possibly a drop shadow below it, it's conflicting badly with the background colour of the taiko playfield.
The hue is probably going to be different from the argon HUD, but using B5
/B6
of OverlayColourScheme.Blue
would look somewhat better:
CleanShot.2024-03-14.at.06.49.35.mp4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was part of the change I was going to make – it had zero definition.
What you propose looks better, so feel free to commit that ahead of me making further changes to animation.
@@ -52,5 +54,7 @@ private void load() | |||
protected override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo); | |||
|
|||
public override DrawableHitObject<CatchHitObject>? CreateDrawableRepresentation(CatchHitObject h) => null; | |||
|
|||
protected override ResumeOverlay CreateResumeOverlay() => new DelayedResumeOverlay { Scale = new Vector2(0.65f) }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was 0.65f
derived from something or is that a throwaway figure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forgot to comment on this, but it's an eyeballed value that brings the size of it in line with other rulesets. Looks like the playfield adjustment container is scaling things up here.
I'll either comment on it, or remove it if my above proposal is accepted (because it doesn't look too bad there).
This needs sound effects added of any kind. Also I dunno, it still feels super out of place and awkward. |
Is that in relation to the design or what? This originally didn't have any design which matches stable. I imagine a world in which every ruleset has a resume overlay that matches gameplay, but that increases the scope of this PR a thousand-fold. It was intended as an early thing that could be agreed to without much discussion... |
I've added what I felt would make it good and got this: CleanShot.2024-03-16.at.06.47.49.mp4Basically made the countdown appear specifically on the center of the screen, and added a dim to indicate that the game is still paused and there's a countdown. patchdiff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs
index adc7bd97ff..2401b044c4 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs
@@ -28,6 +28,22 @@ public partial class OsuResumeOverlay : ResumeOverlay
protected override LocalisableString Message => "Click the orange cursor to resume";
+ private readonly Container content;
+
+ protected override Container<Drawable> Content => content;
+
+ public OsuResumeOverlay()
+ {
+ InternalChild = new OsuPlayfieldAdjustmentContainer
+ {
+ AlignWithStoryboard = true,
+ Child = content = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ };
+ }
+
[BackgroundDependencyLoader]
private void load()
{
@@ -40,7 +56,7 @@ private void load()
protected override void PopIn()
{
// Can't display if the cursor is outside the window.
- if (GameplayCursor.LastFrameState == Visibility.Hidden || !Contains(GameplayCursor.ActiveCursor.ScreenSpaceDrawQuad.Centre))
+ if (GameplayCursor.LastFrameState == Visibility.Hidden || !Content.Contains(GameplayCursor.ActiveCursor.ScreenSpaceDrawQuad.Centre))
{
Resume();
return;
@@ -49,7 +65,7 @@ protected override void PopIn()
base.PopIn();
GameplayCursor.ActiveCursor.Hide();
- cursorScaleContainer.Position = ToLocalSpace(GameplayCursor.ActiveCursor.ScreenSpaceDrawQuad.Centre);
+ cursorScaleContainer.Position = GameplayCursor.ActiveCursor.Position;
clickToResumeCursor.Appear();
if (localCursorContainer == null)
diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs
index a422761800..1f474af10f 100644
--- a/osu.Game/Rulesets/UI/DrawableRuleset.cs
+++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs
@@ -207,8 +207,7 @@ private void load(CancellationToken? cancellationToken)
if ((ResumeOverlay = CreateResumeOverlay()) != null)
{
AddInternal(CreateInputManager()
- .WithChild(CreatePlayfieldAdjustmentContainer()
- .WithChild(ResumeOverlay)));
+ .WithChild(ResumeOverlay));
}
applyRulesetMods(Mods, config);
diff --git a/osu.Game/Screens/Play/DelayedResumeOverlay.cs b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
index fd1ce5d829..392c636cc2 100644
--- a/osu.Game/Screens/Play/DelayedResumeOverlay.cs
+++ b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
@@ -3,6 +3,7 @@
using System;
using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -14,6 +15,8 @@
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays;
using osuTK;
+using osuTK.Graphics;
+using Box = osu.Framework.Graphics.Shapes.Box;
namespace osu.Game.Screens.Play
{
@@ -39,6 +42,7 @@ public partial class DelayedResumeOverlay : ResumeOverlay
private double countdownStartTime;
private bool countdownComplete;
+ private Box dim = null!;
private Drawable outerContent = null!;
private Container innerContent = null!;
@@ -56,6 +60,12 @@ public DelayedResumeOverlay()
[BackgroundDependencyLoader]
private void load()
{
+ Add(dim = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Black.Opacity(0.75f),
+ });
+
Add(outerContent = new Circle
{
Anchor = Anchor.Centre,
@@ -109,6 +119,8 @@ protected override void PopIn()
{
this.FadeIn();
+ dim.FadeIn();
+
// The transition effects.
outerContent.FadeIn().ScaleTo(Vector2.Zero).Then().ScaleTo(Vector2.One, 200, Easing.OutQuint);
innerContent.FadeIn().ScaleTo(Vector2.Zero).Then().ScaleTo(Vector2.One, 400, Easing.OutElasticHalf);
@@ -143,9 +155,13 @@ protected override void PopOut()
{
countdownProgress.ScaleTo(2f, 300, Easing.OutQuint);
countdownProgress.FadeOut(300, Easing.OutQuint);
+ dim.FadeOut(300, Easing.OutQuint);
}
else
+ {
countdownProgress.FadeOut();
+ dim.FadeOut(GameplayMenuOverlay.TRANSITION_DURATION, Easing.InQuint);
+ }
scheduledResume?.Cancel();
}
diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs
index da239d585e..e87c04363d 100644
--- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs
+++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Screens.Play
{
public abstract partial class GameplayMenuOverlay : OverlayContainer, IKeyBindingHandler<GlobalAction>
{
- protected const int TRANSITION_DURATION = 200;
+ public const int TRANSITION_DURATION = 200;
private const int button_height = 70;
private const float background_alpha = 0.75f; |
Dim is too harsh, the idea is to prepare for gameplay so you need to be able to see it. |
@peppy asked me to whip some sound design for this, so here's something I quickly put together: resume2.movFeel free to adjust to taste or whatever. PR for sample: ppy/osu-resources#314 diffdiff --git a/osu.Game/Screens/Play/DelayedResumeOverlay.cs b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
index 8bb3ae8182..9de6f94d59 100644
--- a/osu.Game/Screens/Play/DelayedResumeOverlay.cs
+++ b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
@@ -3,6 +3,8 @@
using System;
using osu.Framework.Allocation;
+using osu.Framework.Audio;
+using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -47,6 +49,8 @@ public partial class DelayedResumeOverlay : ResumeOverlay
private SpriteText countdownText = null!;
private CircularProgress countdownProgress = null!;
+ private Sample sampleCountdown = null!;
+
public DelayedResumeOverlay()
{
Anchor = Anchor.Centre;
@@ -54,7 +58,7 @@ public DelayedResumeOverlay()
}
[BackgroundDependencyLoader]
- private void load()
+ private void load(AudioManager audio)
{
Add(outerContent = new Circle
{
@@ -103,6 +107,8 @@ private void load()
}
}
});
+
+ sampleCountdown = audio.Samples.Get(@"Gameplay/resume-countdown");
}
protected override void PopIn()
@@ -164,13 +170,20 @@ private void updateCountdown()
countdownProgress.Progress = amountTimePassed;
countdownProgress.InnerRadius = progress_stroke_width / progress_size / countdownProgress.Scale.X;
- if (countdownCount != newCount && newCount > 0)
+ if (countdownCount != newCount)
{
- countdownText.Text = Math.Max(1, newCount).ToString();
- countdownText.ScaleTo(0.25f).Then().ScaleTo(1, 200, Easing.OutQuint);
- outerContent.Delay(25).Then().ScaleTo(1.05f, 100).Then().ScaleTo(1f, 200, Easing.Out);
+ if (newCount > 0)
+ {
+ countdownText.Text = Math.Max(1, newCount).ToString();
+ countdownText.ScaleTo(0.25f).Then().ScaleTo(1, 200, Easing.OutQuint);
+ outerContent.Delay(25).Then().ScaleTo(1.05f, 100).Then().ScaleTo(1f, 200, Easing.Out);
+
+ countdownBackground.FlashColour(colourProvider.Background3, 400, Easing.Out);
+ }
- countdownBackground.FlashColour(colourProvider.Background3, 400, Easing.Out);
+ var chan = sampleCountdown.GetChannel();
+ chan.Frequency.Value = newCount == 0 ? 0.5f : 1;
+ chan.Play();
}
countdownCount = newCount;
|
Resolves #10202
Supersedes / closes #26992