diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index 975b7f9f5a..18f0cd1f80 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -71,7 +71,7 @@ namespace osu.Desktop switch (newScreen) { - case Intro _: + case IntroScreen _: case MainMenu _: versionManager?.Show(); break; diff --git a/osu.Game.Tests/Visual/Menus/IntroTestScene.cs b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs new file mode 100644 index 0000000000..d03d341ee4 --- /dev/null +++ b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs @@ -0,0 +1,69 @@ +// 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 System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Screens; +using osu.Game.Screens; +using osu.Game.Screens.Menu; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual.Menus +{ + [TestFixture] + public abstract class IntroTestScene : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(StartupScreen), + typeof(IntroScreen), + typeof(OsuScreen), + typeof(IntroTestScene), + }; + + [Cached] + private OsuLogo logo; + + protected IntroTestScene() + { + Drawable introStack = null; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Depth = float.MaxValue, + Colour = Color4.Black, + }, + logo = new OsuLogo + { + Alpha = 0, + RelativePositionAxes = Axes.Both, + Depth = float.MinValue, + Position = new Vector2(0.5f), + } + }; + + AddStep("restart sequence", () => + { + logo.FinishTransforms(); + logo.IsTracking = false; + + introStack?.Expire(); + + Add(introStack = new OsuScreenStack(CreateScreen()) + { + RelativeSizeAxes = Axes.Both, + }); + }); + } + + protected abstract IScreen CreateScreen(); + } +} diff --git a/osu.Game.Tests/Visual/Menus/TestSceneIntroCircles.cs b/osu.Game.Tests/Visual/Menus/TestSceneIntroCircles.cs new file mode 100644 index 0000000000..107734cc8d --- /dev/null +++ b/osu.Game.Tests/Visual/Menus/TestSceneIntroCircles.cs @@ -0,0 +1,15 @@ +// 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.Screens; +using osu.Game.Screens.Menu; + +namespace osu.Game.Tests.Visual.Menus +{ + [TestFixture] + public class TestSceneIntroCircles : IntroTestScene + { + protected override IScreen CreateScreen() => new IntroCircles(); + } +} diff --git a/osu.Game.Tests/Visual/Menus/TestSceneIntroSequence.cs b/osu.Game.Tests/Visual/Menus/TestSceneIntroSequence.cs deleted file mode 100644 index b59fb18428..0000000000 --- a/osu.Game.Tests/Visual/Menus/TestSceneIntroSequence.cs +++ /dev/null @@ -1,54 +0,0 @@ -// 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 System.Collections.Generic; -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Timing; -using osu.Game.Screens.Menu; -using osuTK.Graphics; - -namespace osu.Game.Tests.Visual.Menus -{ - [TestFixture] - public class TestSceneIntroSequence : OsuTestScene - { - public override IReadOnlyList RequiredTypes => new[] - { - typeof(OsuLogo), - }; - - public TestSceneIntroSequence() - { - OsuLogo logo; - - var rateAdjustClock = new StopwatchClock(true); - var framedClock = new FramedClock(rateAdjustClock); - framedClock.ProcessFrame(); - - Add(new Container - { - RelativeSizeAxes = Axes.Both, - Clock = framedClock, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - logo = new OsuLogo - { - Anchor = Anchor.Centre, - } - } - }); - - AddStep(@"Restart", logo.PlayIntro); - AddSliderStep("Playback speed", 0.0, 2.0, 1, v => rateAdjustClock.Rate = v); - } - } -} diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index ceaf0c3d5e..9358a412d9 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -87,7 +87,8 @@ namespace osu.Game private BackButton backButton; private MainMenu menuScreen; - private Intro introScreen; + + private IntroScreen introScreen; private Bindable configRuleset; @@ -761,7 +762,7 @@ namespace osu.Game if (introScreen == null) return true; - if (!introScreen.DidLoadMenu || !(screenStack.CurrentScreen is Intro)) + if (!introScreen.DidLoadMenu || !(screenStack.CurrentScreen is IntroScreen)) { Scheduler.Add(introScreen.MakeCurrent); return true; @@ -796,7 +797,7 @@ namespace osu.Game { switch (newScreen) { - case Intro intro: + case IntroScreen intro: introScreen = intro; break; diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index 8add730c4e..de00ba2e9f 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -45,7 +45,15 @@ namespace osu.Game.Screens private OsuScreen loadableScreen; private ShaderPrecompiler precompiler; - protected virtual OsuScreen CreateLoadableScreen() => showDisclaimer ? (OsuScreen)new Disclaimer() : new Intro(); + protected virtual OsuScreen CreateLoadableScreen() + { + if (showDisclaimer) + return new Disclaimer(getIntroSequence()); + + return getIntroSequence(); + } + + private IntroScreen getIntroSequence() => new IntroCircles(); protected virtual ShaderPrecompiler CreateShaderPrecompiler() => new ShaderPrecompiler(); diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 97231a1331..073ab639e3 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -21,7 +21,6 @@ namespace osu.Game.Screens.Menu { public class Disclaimer : StartupScreen { - private Intro intro; private SpriteIcon icon; private Color4 iconColour; private LinkFlowContainer textFlow; @@ -32,10 +31,13 @@ namespace osu.Game.Screens.Menu private const float icon_y = -85; private const float icon_size = 30; + private readonly OsuScreen nextScreen; + private readonly Bindable currentUser = new Bindable(); - public Disclaimer() + public Disclaimer(OsuScreen nextScreen = null) { + this.nextScreen = nextScreen; ValidForResume = false; } @@ -146,7 +148,8 @@ namespace osu.Game.Screens.Menu protected override void LoadComplete() { base.LoadComplete(); - LoadComponentAsync(intro = new Intro()); + if (nextScreen != null) + LoadComponentAsync(nextScreen); } public override void OnEntering(IScreen last) @@ -170,7 +173,7 @@ namespace osu.Game.Screens.Menu .Then(5500) .FadeOut(250) .ScaleTo(0.9f, 250, Easing.InQuint) - .Finally(d => this.Push(intro)); + .Finally(d => this.Push(nextScreen)); } } } diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/IntroCircles.cs similarity index 51% rename from osu.Game/Screens/Menu/Intro.cs rename to osu.Game/Screens/Menu/IntroCircles.cs index f6fbcf6498..4fa1a81123 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/IntroCircles.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Audio.Track; using osu.Framework.Bindables; @@ -12,41 +11,24 @@ using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.IO.Archives; -using osu.Game.Screens.Backgrounds; -using osuTK; -using osuTK.Graphics; namespace osu.Game.Screens.Menu { - public class Intro : StartupScreen + public class IntroCircles : IntroScreen { private const string menu_music_beatmap_hash = "3c8b1fcc9434dbb29e2fb613d3b9eada9d7bb6c125ceb32396c3b53437280c83"; - /// - /// Whether we have loaded the menu previously. - /// - public bool DidLoadMenu; - - private MainMenu mainMenu; private SampleChannel welcome; - private SampleChannel seeya; - protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack(); - - private readonly BindableDouble exitingVolumeFade = new BindableDouble(1); - - [Resolved] - private AudioManager audio { get; set; } - - private Bindable menuVoice; private Bindable menuMusic; + private Track track; + private WorkingBeatmap introBeatmap; [BackgroundDependencyLoader] - private void load(OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game) + private void load(OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game, ISampleStore samples) { - menuVoice = config.GetBindable(OsuSetting.MenuVoice); menuMusic = config.GetBindable(OsuSetting.MenuMusic); BeatmapSetInfo setInfo = null; @@ -75,15 +57,13 @@ namespace osu.Game.Screens.Menu introBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]); track = introBeatmap.Track; - welcome = audio.Samples.Get(@"welcome"); - seeya = audio.Samples.Get(@"seeya"); + if (config.Get(OsuSetting.MenuVoice)) + welcome = samples.Get(@"welcome"); } private const double delay_step_one = 2300; private const double delay_step_two = 600; - public const int EXIT_DELAY = 3000; - protected override void LogoArriving(OsuLogo logo, bool resuming) { base.LogoArriving(logo, resuming); @@ -93,86 +73,34 @@ namespace osu.Game.Screens.Menu Beatmap.Value = introBeatmap; introBeatmap = null; - if (menuVoice.Value) - welcome.Play(); + welcome?.Play(); Scheduler.AddDelayed(delegate { // Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Manu. if (menuMusic.Value) { - track.Start(); + track.Restart(); track = null; } - LoadComponentAsync(mainMenu = new MainMenu()); + PrepareMenuLoad(); - Scheduler.AddDelayed(delegate - { - DidLoadMenu = true; - this.Push(mainMenu); - }, delay_step_one); + Scheduler.AddDelayed(LoadMenu, delay_step_one); }, delay_step_two); - } - logo.Colour = Color4.White; - logo.Ripple = false; - - const int quick_appear = 350; - - int initialMovementTime = logo.Alpha > 0.2f ? quick_appear : 0; - - logo.MoveTo(new Vector2(0.5f), initialMovementTime, Easing.OutQuint); - - if (!resuming) - { logo.ScaleTo(1); logo.FadeIn(); logo.PlayIntro(); } - else - { - logo.Triangles = false; - - logo - .ScaleTo(1, initialMovementTime, Easing.OutQuint) - .FadeIn(quick_appear, Easing.OutQuint) - .Then() - .RotateTo(20, EXIT_DELAY * 1.5f) - .FadeOut(EXIT_DELAY); - } } public override void OnSuspending(IScreen next) { + track = null; + this.FadeOut(300); base.OnSuspending(next); } - - public override bool OnExiting(IScreen next) - { - //cancel exiting if we haven't loaded the menu yet. - return !DidLoadMenu; - } - - public override void OnResuming(IScreen last) - { - this.FadeIn(300); - - double fadeOutTime = EXIT_DELAY; - //we also handle the exit transition. - if (menuVoice.Value) - seeya.Play(); - else - fadeOutTime = 500; - - audio.AddAdjustment(AdjustableProperty.Volume, exitingVolumeFade); - this.TransformBindableTo(exitingVolumeFade, 0, fadeOutTime).OnComplete(_ => this.Exit()); - - //don't want to fade out completely else we will stop running updates. - Game.FadeTo(0.01f, fadeOutTime); - - base.OnResuming(last); - } } } diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs new file mode 100644 index 0000000000..27f3c9a45b --- /dev/null +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -0,0 +1,114 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Screens; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Screens.Backgrounds; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.Menu +{ + public abstract class IntroScreen : StartupScreen + { + private readonly BindableDouble exitingVolumeFade = new BindableDouble(1); + + public const int EXIT_DELAY = 3000; + + [Resolved] + private AudioManager audio { get; set; } + + private SampleChannel seeya; + + private Bindable menuVoice; + + protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack(); + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game) + { + menuVoice = config.GetBindable(OsuSetting.MenuVoice); + seeya = audio.Samples.Get(@"seeya"); + } + + /// + /// Whether we have loaded the menu previously. + /// + public bool DidLoadMenu { get; private set; } + + public override bool OnExiting(IScreen next) + { + //cancel exiting if we haven't loaded the menu yet. + return !DidLoadMenu; + } + + public override void OnResuming(IScreen last) + { + this.FadeIn(300); + + double fadeOutTime = EXIT_DELAY; + //we also handle the exit transition. + if (menuVoice.Value) + seeya.Play(); + else + fadeOutTime = 500; + + audio.AddAdjustment(AdjustableProperty.Volume, exitingVolumeFade); + this.TransformBindableTo(exitingVolumeFade, 0, fadeOutTime).OnComplete(_ => this.Exit()); + + //don't want to fade out completely else we will stop running updates. + Game.FadeTo(0.01f, fadeOutTime); + + base.OnResuming(last); + } + + protected override void LogoArriving(OsuLogo logo, bool resuming) + { + base.LogoArriving(logo, resuming); + + logo.Colour = Color4.White; + logo.Triangles = false; + logo.Ripple = false; + + if (!resuming) + { + logo.MoveTo(new Vector2(0.5f)); + logo.ScaleTo(Vector2.One); + logo.Hide(); + } + else + { + const int quick_appear = 350; + int initialMovementTime = logo.Alpha > 0.2f ? quick_appear : 0; + + logo.MoveTo(new Vector2(0.5f), initialMovementTime, Easing.OutQuint); + + logo + .ScaleTo(1, initialMovementTime, Easing.OutQuint) + .FadeIn(quick_appear, Easing.OutQuint) + .Then() + .RotateTo(20, EXIT_DELAY * 1.5f) + .FadeOut(EXIT_DELAY); + } + } + + private MainMenu mainMenu; + + protected void PrepareMenuLoad() + { + LoadComponentAsync(mainMenu = new MainMenu()); + } + + protected void LoadMenu() + { + DidLoadMenu = true; + this.Push(mainMenu); + } + } +} diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 5999cbdfb5..fc8ddd8bd4 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -123,7 +123,7 @@ namespace osu.Game.Screens.Menu var track = Beatmap.Value.Track; var metadata = Beatmap.Value.Metadata; - if (last is Intro && track != null) + if (last is IntroScreen && track != null) { if (!track.IsRunning) {