From 6635d9be04952b43b41ff8e3f2596999a069ff74 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 4 Mar 2024 16:08:25 +0900 Subject: [PATCH] Add countdown display --- .../UI/DrawableCatchRuleset.cs | 3 +- .../Gameplay/TestSceneDelayedResumeOverlay.cs | 44 ++++++ osu.Game/Screens/Play/DelayedResumeOverlay.cs | 135 +++++++++++++++++- 3 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneDelayedResumeOverlay.cs diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs index 580c90bcb4..32ebdc1159 100644 --- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs @@ -17,6 +17,7 @@ using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Scoring; using osu.Game.Screens.Play; +using osuTK; namespace osu.Game.Rulesets.Catch.UI { @@ -54,6 +55,6 @@ namespace osu.Game.Rulesets.Catch.UI public override DrawableHitObject? CreateDrawableRepresentation(CatchHitObject h) => null; - protected override ResumeOverlay CreateResumeOverlay() => new DelayedResumeOverlay(); + protected override ResumeOverlay CreateResumeOverlay() => new DelayedResumeOverlay { Scale = new Vector2(0.65f) }; } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDelayedResumeOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDelayedResumeOverlay.cs new file mode 100644 index 0000000000..241a78b6b8 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDelayedResumeOverlay.cs @@ -0,0 +1,44 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Play; +using osu.Game.Tests.Gameplay; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public partial class TestSceneDelayedResumeOverlay : OsuTestScene + { + private ResumeOverlay resume = null!; + private bool resumeFired; + + [Cached] + private GameplayState gameplayState; + + public TestSceneDelayedResumeOverlay() + { + gameplayState = TestGameplayState.Create(new OsuRuleset()); + } + + [SetUp] + public void SetUp() => Schedule(loadContent); + + [Test] + public void TestResume() + { + AddStep("show", () => resume.Show()); + AddUntilStep("dismissed", () => resumeFired && resume.State.Value == Visibility.Hidden); + } + + private void loadContent() + { + Child = resume = new DelayedResumeOverlay(); + + resumeFired = false; + resume.ResumeAction = () => resumeFired = true; + } + } +} diff --git a/osu.Game/Screens/Play/DelayedResumeOverlay.cs b/osu.Game/Screens/Play/DelayedResumeOverlay.cs index ef39c8eb76..6f70a914f0 100644 --- a/osu.Game/Screens/Play/DelayedResumeOverlay.cs +++ b/osu.Game/Screens/Play/DelayedResumeOverlay.cs @@ -1,8 +1,18 @@ // 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.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Framework.Threading; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.Play { @@ -11,21 +21,140 @@ namespace osu.Game.Screens.Play /// public partial class DelayedResumeOverlay : ResumeOverlay { + private const double countdown_time = 800; + protected override LocalisableString Message => string.Empty; + [Resolved] + private OsuColour colours { get; set; } = null!; + private ScheduledDelegate? scheduledResume; + private int countdownCount = 3; + private double countdownStartTime; + + private Drawable content = null!; + private Drawable background = null!; + private SpriteText countdown = null!; + + public DelayedResumeOverlay() + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + } + + [BackgroundDependencyLoader] + private void load() + { + Add(content = new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Masking = true, + BorderColour = colours.Yellow, + BorderThickness = 1, + Children = new[] + { + background = 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, + Children = new Drawable[] + { + // new Box + // { + // Anchor = Anchor.Centre, + // Origin = Anchor.Centre, + // Size = new Vector2(40, 3) + // }, + countdown = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + UseFullGlyphHeight = false, + AlwaysPresent = true, + Font = OsuFont.Numeric.With(size: 20, fixedWidth: true) + }, + // new Box + // { + // Anchor = Anchor.Centre, + // Origin = Anchor.Centre, + // Size = new Vector2(40, 3) + // } + } + } + } + } + } + }); + } protected override void PopIn() { - base.PopIn(); + this.FadeIn(); + + content.FadeInFromZero(150, Easing.OutQuint); + content.ScaleTo(new Vector2(1.5f, 1)).Then().ScaleTo(1, 150, Easing.OutElasticQuarter); + + countdownCount = 3; + countdownStartTime = Time.Current; scheduledResume?.Cancel(); - scheduledResume = Scheduler.AddDelayed(Resume, 800); + scheduledResume = Scheduler.AddDelayed(Resume, countdown_time); + } + + protected override void Update() + { + base.Update(); + updateCountdown(); + } + + 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) + { + countdown.Alpha = 1; + countdown.Text = newCount.ToString(); + } + else + countdown.Alpha = 0; + + if (newCount != countdownCount) + { + if (newCount == 0) + content.ScaleTo(new Vector2(1.5f, 1), 150, Easing.OutQuint); + else + content.ScaleTo(new Vector2(1.05f, 1), 50, Easing.OutQuint).Then().ScaleTo(1, 50, Easing.Out); + } + + countdownCount = newCount; } protected override void PopOut() { - base.PopOut(); + this.Delay(150).FadeOut(); + + content.FadeOut(150, Easing.OutQuint); + scheduledResume?.Cancel(); } }