From e93311fdc9e2372e262e5fb9f4cd496ec53f5798 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 22 Mar 2019 19:01:32 +0900 Subject: [PATCH 01/54] DI facade --- .../Graphics/Containers/FacadeContainer.cs | 30 +++++++++++++++++++ osu.Game/Screens/Play/PlayerLoader.cs | 14 ++++++--- 2 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Graphics/Containers/FacadeContainer.cs diff --git a/osu.Game/Graphics/Containers/FacadeContainer.cs b/osu.Game/Graphics/Containers/FacadeContainer.cs new file mode 100644 index 0000000000..7d7a4b0680 --- /dev/null +++ b/osu.Game/Graphics/Containers/FacadeContainer.cs @@ -0,0 +1,30 @@ +// 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.Graphics.Containers; +using osu.Game.Screens.Menu; +using osuTK; + +namespace osu.Game.Graphics.Containers +{ + public class FacadeContainer : Container + { + [Cached] + private Facade facade; + + public FacadeContainer() + { + facade = new Facade(); + } + + public void SetLogo(OsuLogo logo) + { + facade.Size = new Vector2(logo.SizeForFlow); + } + } + + public class Facade : Container + { + } +} diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index e9ee5d3fa8..878c2541e9 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -14,6 +14,7 @@ using osu.Framework.Screens; using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Menu; @@ -32,7 +33,7 @@ namespace osu.Game.Screens.Play private Player player; - private Container content; + private FacadeContainer content; private BeatmapMetadataDisplay info; @@ -59,7 +60,7 @@ namespace osu.Game.Screens.Play [BackgroundDependencyLoader] private void load() { - InternalChild = content = new Container + InternalChild = content = new FacadeContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -153,6 +154,8 @@ namespace osu.Game.Screens.Play logo.FadeIn(350); logo.Delay(resuming ? 0 : 500).MoveToOffset(new Vector2(0, -0.24f), 500, Easing.InOutExpo); + + content.SetLogo(logo); } protected override void LoadComplete() @@ -302,6 +305,8 @@ namespace osu.Game.Screens.Play private LoadingAnimation loading; private Sprite backgroundSprite; private ModDisplay modDisplay; + private FillFlowContainer fillFlowContainer; + private FacadeContainer facadeContainer; public bool Loading { @@ -326,14 +331,14 @@ namespace osu.Game.Screens.Play } [BackgroundDependencyLoader] - private void load() + private void load(Facade facade) { var metadata = beatmap.BeatmapInfo?.Metadata ?? new BeatmapMetadata(); AutoSizeAxes = Axes.Both; Children = new Drawable[] { - new FillFlowContainer + fillFlowContainer = new FillFlowContainer { AutoSizeAxes = Axes.Both, Origin = Anchor.TopCentre, @@ -341,6 +346,7 @@ namespace osu.Game.Screens.Play Direction = FillDirection.Vertical, Children = new Drawable[] { + facade, new OsuSpriteText { Text = new LocalisedString((metadata.TitleUnicode, metadata.Title)), From 6e98a8dd7c15ff372a39ebf9b7785b0c6e16a755 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 22 Mar 2019 20:01:58 +0900 Subject: [PATCH 02/54] Initial implementation --- osu.Game.Tests/Visual/TestCasePlayerLoader.cs | 10 +++- .../Graphics/Containers/FacadeContainer.cs | 53 ++++++++++++++++++- osu.Game/Screens/Play/PlayerLoader.cs | 13 +++-- 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePlayerLoader.cs b/osu.Game.Tests/Visual/TestCasePlayerLoader.cs index 2bc416f7f4..ad0965b4d6 100644 --- a/osu.Game.Tests/Visual/TestCasePlayerLoader.cs +++ b/osu.Game.Tests/Visual/TestCasePlayerLoader.cs @@ -7,7 +7,9 @@ using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Screens; +using osu.Game.Screens.Menu; using osu.Game.Screens.Play; +using osuTK; namespace osu.Game.Tests.Visual { @@ -16,6 +18,9 @@ namespace osu.Game.Tests.Visual private PlayerLoader loader; private readonly ScreenStack stack; + [Cached] + private OsuLogo logo; + [Cached] private BackgroundScreenStack backgroundStack; @@ -23,6 +28,7 @@ namespace osu.Game.Tests.Visual { InputManager.Add(backgroundStack = new BackgroundScreenStack { RelativeSizeAxes = Axes.Both }); InputManager.Add(stack = new ScreenStack { RelativeSizeAxes = Axes.Both }); + InputManager.Add(logo = new OsuLogo()); } [BackgroundDependencyLoader] @@ -30,6 +36,8 @@ namespace osu.Game.Tests.Visual { Beatmap.Value = new DummyWorkingBeatmap(game); + AddStep("Reset logo position", () => logo = new OsuLogo { Position = new Vector2(0, 0) }); + AddStep("load dummy beatmap", () => stack.Push(loader = new PlayerLoader(() => new Player { AllowPause = false, @@ -57,8 +65,6 @@ namespace osu.Game.Tests.Visual AllowLeadIn = false, AllowResults = false, })); - - Scheduler.AddDelayed(() => slow.Ready = true, 5000); }); AddUntilStep("wait for no longer current", () => !loader.IsCurrentScreen()); diff --git a/osu.Game/Graphics/Containers/FacadeContainer.cs b/osu.Game/Graphics/Containers/FacadeContainer.cs index 7d7a4b0680..e39fba64ce 100644 --- a/osu.Game/Graphics/Containers/FacadeContainer.cs +++ b/osu.Game/Graphics/Containers/FacadeContainer.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Screens.Menu; using osuTK; @@ -13,14 +14,62 @@ namespace osu.Game.Graphics.Containers [Cached] private Facade facade; + private OsuLogo logo; + + private bool tracking; + private bool smoothTransform; + public FacadeContainer() { facade = new Facade(); } - public void SetLogo(OsuLogo logo) + private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(facade.ScreenSpaceDrawQuad.Centre); + + public void SetLogo(OsuLogo logo, bool resuming, double transformDelay) { - facade.Size = new Vector2(logo.SizeForFlow); + if (logo != null) + { + facade.Size = new Vector2(logo.SizeForFlow * 0.3f); + this.logo = logo; + Scheduler.AddDelayed(() => + { + tracking = true; + smoothTransform = !resuming; + }, transformDelay); + } + } + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + facade.Size = new Vector2(logo.SizeForFlow * 0.3f); + + if (!tracking) + return; + + logo.RelativePositionAxes = Axes.None; + + bool childrenLoaded = true; + + foreach (var d in Children) + { + if (!d.IsAlive) + childrenLoaded = false; + } + + if (smoothTransform && childrenLoaded) + { + // Our initial movement to the tracking location should be smooth. + Schedule(() => logo.MoveTo(logoTrackingPosition, 500, Easing.InOutExpo)); + smoothTransform = false; + } + else if (logo.Transforms.Count == 0) + { + // If all transforms have finished playing, the logo constantly track the position of the facade. + logo.Position = logoTrackingPosition; + } } } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 878c2541e9..97249ee6cd 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -149,13 +149,13 @@ namespace osu.Game.Screens.Play { base.LogoArriving(logo, resuming); - logo.ScaleTo(new Vector2(0.15f), 300, Easing.In); - logo.MoveTo(new Vector2(0.5f), 300, Easing.In); + const double duration = 300; + + logo.ScaleTo(new Vector2(0.15f), duration, Easing.In); + logo.MoveTo(new Vector2(0.5f), duration, Easing.In); logo.FadeIn(350); - logo.Delay(resuming ? 0 : 500).MoveToOffset(new Vector2(0, -0.24f), 500, Easing.InOutExpo); - - content.SetLogo(logo); + content.SetLogo(logo, resuming, duration); } protected override void LoadComplete() @@ -335,6 +335,9 @@ namespace osu.Game.Screens.Play { var metadata = beatmap.BeatmapInfo?.Metadata ?? new BeatmapMetadata(); + facade.Anchor = Anchor.TopCentre; + facade.Origin = Anchor.TopCentre; + AutoSizeAxes = Axes.Both; Children = new Drawable[] { From d37968d88df2ad6f6f0a6f64596212df28bfabde Mon Sep 17 00:00:00 2001 From: David Zhao Date: Sun, 24 Mar 2019 15:18:38 +0900 Subject: [PATCH 03/54] Add better test for facade containers --- .../Visual/TestCaseFacadeContainer.cs | 113 ++++++++++++++++++ .../Graphics/Containers/FacadeContainer.cs | 33 +++-- osu.Game/Screens/Play/PlayerLoader.cs | 46 +++---- 3 files changed, 152 insertions(+), 40 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseFacadeContainer.cs diff --git a/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs b/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs new file mode 100644 index 0000000000..3063a4ca3f --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs @@ -0,0 +1,113 @@ +// 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 System.Linq; +using System.Threading; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; +using osu.Game.Configuration; +using osu.Game.Graphics.Containers; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Screens; +using osu.Game.Screens.Menu; +using osu.Game.Screens.Play; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseFacadeContainer : ScreenTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(PlayerLoader), + typeof(Player), + typeof(Facade), + }; + + [Cached] + private OsuLogo logo; + + private readonly Bindable uiScale = new Bindable(); + + private OsuScreen baseScreen; + + public TestCaseFacadeContainer() + { + Add(logo = new OsuLogo()); + } + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + baseScreen = null; + config.BindWith(OsuSetting.UIScale, uiScale); + AddSliderStep("Adjust scale", 1f, 1.5f, 1f, v => uiScale.Value = v); + AddToggleStep("Toggle mods", b => { Beatmap.Value.Mods.Value = b ? Beatmap.Value.Mods.Value.Concat(new[] { new OsuModNoFail() }) : Enumerable.Empty(); }); + } + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("Null screens", () => baseScreen = null); + } + + [Test] + public void PlayerLoaderTest() + { + AddStep("Add new playerloader", () => LoadScreen(baseScreen = new TestPlayerLoader(() => new TestPlayer + { + AllowPause = false, + AllowLeadIn = false, + AllowResults = false, + }))); + } + + [Test] + public void MainMenuTest() + { + AddStep("Add new Main Menu", () => LoadScreen(baseScreen = new MainMenu())); + } + + private class TestFacadeContainer : FacadeContainer + { + protected override Facade CreateFacade() => new Facade + { + Colour = Color4.Tomato, + Alpha = 0.35f, + Child = new Box + { + Colour = Color4.Tomato, + RelativeSizeAxes = Axes.Both, + }, + }; + } + + private class TestPlayerLoader : PlayerLoader + { + public TestPlayerLoader(Func player) + : base(player) + { + } + + protected override FacadeContainer CreateFacadeContainer() => new TestFacadeContainer(); + } + + private class TestPlayer : Player + { + [BackgroundDependencyLoader] + private void load() + { + // Never finish loading + while (true) + Thread.Sleep(1); + } + } + } +} diff --git a/osu.Game/Graphics/Containers/FacadeContainer.cs b/osu.Game/Graphics/Containers/FacadeContainer.cs index e39fba64ce..d7fae8887f 100644 --- a/osu.Game/Graphics/Containers/FacadeContainer.cs +++ b/osu.Game/Graphics/Containers/FacadeContainer.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -19,9 +20,11 @@ namespace osu.Game.Graphics.Containers private bool tracking; private bool smoothTransform; + protected virtual Facade CreateFacade() => new Facade(); + public FacadeContainer() { - facade = new Facade(); + facade = CreateFacade(); } private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(facade.ScreenSpaceDrawQuad.Centre); @@ -44,30 +47,26 @@ namespace osu.Game.Graphics.Containers { base.UpdateAfterChildren(); - facade.Size = new Vector2(logo.SizeForFlow * 0.3f); - - if (!tracking) + if (logo == null) return; - logo.RelativePositionAxes = Axes.None; + facade.Size = new Vector2(logo.SizeForFlow * 0.3f); - bool childrenLoaded = true; - - foreach (var d in Children) - { - if (!d.IsAlive) - childrenLoaded = false; - } - - if (smoothTransform && childrenLoaded) + if (smoothTransform && facade.IsLoaded && logo.Transforms.Count == 0) { // Our initial movement to the tracking location should be smooth. - Schedule(() => logo.MoveTo(logoTrackingPosition, 500, Easing.InOutExpo)); - smoothTransform = false; + Schedule(() => + { + facade.Size = new Vector2(logo.SizeForFlow * 0.3f); + logo.RelativePositionAxes = Axes.None; + logo.MoveTo(logoTrackingPosition, 500, Easing.InOutExpo); + smoothTransform = false; + }); } - else if (logo.Transforms.Count == 0) + else if (facade.IsLoaded && logo.Transforms.Count == 0) { // If all transforms have finished playing, the logo constantly track the position of the facade. + logo.RelativePositionAxes = Axes.None; logo.Position = logoTrackingPosition; } } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 97249ee6cd..5817e11277 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -35,6 +35,8 @@ namespace osu.Game.Screens.Play private FacadeContainer content; + protected virtual FacadeContainer CreateFacadeContainer() => new FacadeContainer(); + private BeatmapMetadataDisplay info; private bool hideOverlays; @@ -60,32 +62,30 @@ namespace osu.Game.Screens.Play [BackgroundDependencyLoader] private void load() { - InternalChild = content = new FacadeContainer + InternalChild = content = CreateFacadeContainer(); + content.Anchor = Anchor.Centre; + content.Origin = Anchor.Centre; + content.RelativeSizeAxes = Axes.Both; + content.Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] + info = new BeatmapMetadataDisplay(Beatmap.Value) { - info = new BeatmapMetadataDisplay(Beatmap.Value) + Alpha = 0, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new FillFlowContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Margin = new MarginPadding(25), + Children = new PlayerSettingsGroup[] { - Alpha = 0, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - new FillFlowContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 20), - Margin = new MarginPadding(25), - Children = new PlayerSettingsGroup[] - { - VisualSettings = new VisualSettings(), - new InputSettings() - } + VisualSettings = new VisualSettings(), + new InputSettings() } } }; From a0f6718145f4cadb74e86161fe635c221d30e2d9 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 26 Mar 2019 10:48:29 +0900 Subject: [PATCH 04/54] Better tests and implementation --- .../Visual/TestCaseFacadeContainer.cs | 75 ++++++++++++++++++- .../Graphics/Containers/FacadeContainer.cs | 55 ++++++++------ osu.Game/Screens/Play/PlayerLoader.cs | 5 +- 3 files changed, 109 insertions(+), 26 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs b/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs index 3063a4ca3f..d3f854998c 100644 --- a/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs @@ -9,7 +9,9 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Framework.Testing; using osu.Game.Configuration; using osu.Game.Graphics.Containers; @@ -18,6 +20,7 @@ using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; +using osuTK; using osuTK.Graphics; namespace osu.Game.Tests.Visual @@ -36,6 +39,7 @@ namespace osu.Game.Tests.Visual private readonly Bindable uiScale = new Bindable(); + private TestScreen screen1; private OsuScreen baseScreen; public TestCaseFacadeContainer() @@ -49,7 +53,6 @@ namespace osu.Game.Tests.Visual baseScreen = null; config.BindWith(OsuSetting.UIScale, uiScale); AddSliderStep("Adjust scale", 1f, 1.5f, 1f, v => uiScale.Value = v); - AddToggleStep("Toggle mods", b => { Beatmap.Value.Mods.Value = b ? Beatmap.Value.Mods.Value.Concat(new[] { new OsuModNoFail() }) : Enumerable.Empty(); }); } [SetUpSteps] @@ -58,9 +61,18 @@ namespace osu.Game.Tests.Visual AddStep("Null screens", () => baseScreen = null); } + [Test] + public void IsolatedTest() + { + bool randomPositions = false; + AddToggleStep("Toggle move continuously", b => randomPositions = b); + AddStep("Move facade to random position", () => LoadScreen(screen1 = new TestScreen(randomPositions))); + } + [Test] public void PlayerLoaderTest() { + AddToggleStep("Toggle mods", b => { Beatmap.Value.Mods.Value = b ? Beatmap.Value.Mods.Value.Concat(new[] { new OsuModNoFail() }) : Enumerable.Empty(); }); AddStep("Add new playerloader", () => LoadScreen(baseScreen = new TestPlayerLoader(() => new TestPlayer { AllowPause = false, @@ -89,6 +101,67 @@ namespace osu.Game.Tests.Visual }; } + private class TestScreen : OsuScreen + { + private TestFacadeContainer facadeContainer; + private FacadeFlowComponent facadeFlowComponent; + private OsuLogo logo; + + private readonly bool randomPositions; + + public TestScreen(bool randomPositions = false) + { + this.randomPositions = randomPositions; + } + + private SpriteText positionText; + private SpriteText sizeAxesText; + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = facadeContainer = new TestFacadeContainer + { + Child = facadeFlowComponent = new FacadeFlowComponent + { + AutoSizeAxes = Axes.Both + } + }; + } + + protected override void LogoArriving(OsuLogo logo, bool resuming) + { + base.LogoArriving(logo, resuming); + logo.FadeIn(350); + logo.ScaleTo(new Vector2(0.15f), 350, Easing.In); + facadeContainer.SetLogo(logo); + moveLogoFacade(); + } + + private void moveLogoFacade() + { + Random random = new Random(); + if (facadeFlowComponent.Transforms.Count == 0) + { + facadeFlowComponent.Delay(500).MoveTo(new Vector2(random.Next(0, 800), random.Next(0, 600)), 300); + } + + if (randomPositions) + Schedule(moveLogoFacade); + } + } + + private class FacadeFlowComponent : FillFlowContainer + { + [BackgroundDependencyLoader] + private void load(Facade facade) + { + facade.Anchor = Anchor.TopCentre; + facade.Origin = Anchor.TopCentre; + Child = facade; + } + } + private class TestPlayerLoader : PlayerLoader { public TestPlayerLoader(Func player) diff --git a/osu.Game/Graphics/Containers/FacadeContainer.cs b/osu.Game/Graphics/Containers/FacadeContainer.cs index d7fae8887f..0511c87166 100644 --- a/osu.Game/Graphics/Containers/FacadeContainer.cs +++ b/osu.Game/Graphics/Containers/FacadeContainer.cs @@ -1,10 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.MathUtils; using osu.Game.Screens.Menu; using osuTK; @@ -18,7 +18,6 @@ namespace osu.Game.Graphics.Containers private OsuLogo logo; private bool tracking; - private bool smoothTransform; protected virtual Facade CreateFacade() => new Facade(); @@ -29,7 +28,7 @@ namespace osu.Game.Graphics.Containers private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(facade.ScreenSpaceDrawQuad.Centre); - public void SetLogo(OsuLogo logo, bool resuming, double transformDelay) + public void SetLogo(OsuLogo logo, double transformDelay = 0) { if (logo != null) { @@ -38,41 +37,53 @@ namespace osu.Game.Graphics.Containers Scheduler.AddDelayed(() => { tracking = true; - smoothTransform = !resuming; }, transformDelay); } } + private double startTime; + private double duration = 1000; + + private Vector2 startPosition; + private Easing easing = Easing.InOutExpo; + protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); - if (logo == null) + if (logo == null || !tracking) return; facade.Size = new Vector2(logo.SizeForFlow * 0.3f); - if (smoothTransform && facade.IsLoaded && logo.Transforms.Count == 0) + if (facade.IsLoaded && logo.Position != logoTrackingPosition) { - // Our initial movement to the tracking location should be smooth. - Schedule(() => + if (logo.RelativePositionAxes != Axes.None) { - facade.Size = new Vector2(logo.SizeForFlow * 0.3f); + logo.Position = logo.Parent.ToLocalSpace(logo.Position); logo.RelativePositionAxes = Axes.None; - logo.MoveTo(logoTrackingPosition, 500, Easing.InOutExpo); - smoothTransform = false; - }); - } - else if (facade.IsLoaded && logo.Transforms.Count == 0) - { - // If all transforms have finished playing, the logo constantly track the position of the facade. - logo.RelativePositionAxes = Axes.None; - logo.Position = logoTrackingPosition; + } + + if (startTime == 0) + { + startTime = Time.Current; + } + + var endTime = startTime + duration; + var remainingDuration = endTime - Time.Current; + + if (remainingDuration <= 0) + { + remainingDuration = 0; + } + + float currentTime = (float)Interpolation.ApplyEasing(easing, remainingDuration / duration); + logo.Position = Vector2.Lerp(logoTrackingPosition, startPosition, currentTime); } } } - - public class Facade : Container - { - } } + +public class Facade : Container +{ +} \ No newline at end of file diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 5817e11277..b7155f771f 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -155,7 +155,7 @@ namespace osu.Game.Screens.Play logo.MoveTo(new Vector2(0.5f), duration, Easing.In); logo.FadeIn(350); - content.SetLogo(logo, resuming, duration); + content.SetLogo(logo, duration); } protected override void LoadComplete() @@ -167,7 +167,7 @@ namespace osu.Game.Screens.Play private ScheduledDelegate pushDebounce; protected VisualSettings VisualSettings; - // Hhere because IsHovered will not update unless we do so. + // Here because IsHovered will not update unless we do so. public override bool HandlePositionalInput => true; private bool readyForPush => player.LoadState == LoadState.Ready && IsHovered && GetContainingInputManager()?.DraggedDrawable == null; @@ -306,7 +306,6 @@ namespace osu.Game.Screens.Play private Sprite backgroundSprite; private ModDisplay modDisplay; private FillFlowContainer fillFlowContainer; - private FacadeContainer facadeContainer; public bool Loading { From be9ac39f542eb6bea400086c9cf04cb7b4a15e69 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 26 Mar 2019 11:11:27 +0900 Subject: [PATCH 05/54] Cleanup --- .../Visual/TestCaseFacadeContainer.cs | 23 ++++--------------- .../Graphics/Containers/FacadeContainer.cs | 2 +- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs b/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs index d3f854998c..5591bec0b8 100644 --- a/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs @@ -11,7 +11,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; using osu.Framework.Testing; using osu.Game.Configuration; using osu.Game.Graphics.Containers; @@ -32,6 +31,7 @@ namespace osu.Game.Tests.Visual typeof(PlayerLoader), typeof(Player), typeof(Facade), + typeof(FacadeContainer) }; [Cached] @@ -39,9 +39,6 @@ namespace osu.Game.Tests.Visual private readonly Bindable uiScale = new Bindable(); - private TestScreen screen1; - private OsuScreen baseScreen; - public TestCaseFacadeContainer() { Add(logo = new OsuLogo()); @@ -50,30 +47,23 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - baseScreen = null; config.BindWith(OsuSetting.UIScale, uiScale); AddSliderStep("Adjust scale", 1f, 1.5f, 1f, v => uiScale.Value = v); } - [SetUpSteps] - public void SetUpSteps() - { - AddStep("Null screens", () => baseScreen = null); - } - [Test] public void IsolatedTest() { bool randomPositions = false; AddToggleStep("Toggle move continuously", b => randomPositions = b); - AddStep("Move facade to random position", () => LoadScreen(screen1 = new TestScreen(randomPositions))); + AddStep("Move facade to random position", () => LoadScreen(new TestScreen(randomPositions))); } [Test] public void PlayerLoaderTest() { AddToggleStep("Toggle mods", b => { Beatmap.Value.Mods.Value = b ? Beatmap.Value.Mods.Value.Concat(new[] { new OsuModNoFail() }) : Enumerable.Empty(); }); - AddStep("Add new playerloader", () => LoadScreen(baseScreen = new TestPlayerLoader(() => new TestPlayer + AddStep("Add new playerloader", () => LoadScreen(new TestPlayerLoader(() => new TestPlayer { AllowPause = false, AllowLeadIn = false, @@ -84,7 +74,7 @@ namespace osu.Game.Tests.Visual [Test] public void MainMenuTest() { - AddStep("Add new Main Menu", () => LoadScreen(baseScreen = new MainMenu())); + AddStep("Add new Main Menu", () => LoadScreen(new MainMenu())); } private class TestFacadeContainer : FacadeContainer @@ -105,8 +95,6 @@ namespace osu.Game.Tests.Visual { private TestFacadeContainer facadeContainer; private FacadeFlowComponent facadeFlowComponent; - private OsuLogo logo; - private readonly bool randomPositions; public TestScreen(bool randomPositions = false) @@ -114,9 +102,6 @@ namespace osu.Game.Tests.Visual this.randomPositions = randomPositions; } - private SpriteText positionText; - private SpriteText sizeAxesText; - [BackgroundDependencyLoader] private void load() { diff --git a/osu.Game/Graphics/Containers/FacadeContainer.cs b/osu.Game/Graphics/Containers/FacadeContainer.cs index 0511c87166..611cc94958 100644 --- a/osu.Game/Graphics/Containers/FacadeContainer.cs +++ b/osu.Game/Graphics/Containers/FacadeContainer.cs @@ -60,8 +60,8 @@ namespace osu.Game.Graphics.Containers { if (logo.RelativePositionAxes != Axes.None) { - logo.Position = logo.Parent.ToLocalSpace(logo.Position); logo.RelativePositionAxes = Axes.None; + logo.Position = logo.Parent.ToLocalSpace(logo.Position); } if (startTime == 0) From 3fe52be77febe7ce3e41cc1762717cdd71b02db6 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 26 Mar 2019 17:18:35 +0900 Subject: [PATCH 06/54] Better tests, add documentation --- .../Visual/Gameplay/TestCasePlayerLoader.cs | 7 +- .../Visual/TestCaseFacadeContainer.cs | 30 ++++--- .../Graphics/Containers/FacadeContainer.cs | 78 ++++++++++++------- osu.Game/Screens/Menu/ButtonSystem.cs | 63 +++++++-------- osu.Game/Screens/Play/PlayerLoader.cs | 37 +++++---- 5 files changed, 121 insertions(+), 94 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs index 67dba71d45..be2a21d23d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs @@ -7,16 +7,13 @@ using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Screens; -using osu.Game.Screens.Menu; using osu.Game.Screens.Play; -using osuTK; namespace osu.Game.Tests.Visual.Gameplay { public class TestCasePlayerLoader : ManualInputManagerTestCase { private PlayerLoader loader; - private readonly OsuScreenStack stack; public TestCasePlayerLoader() @@ -29,8 +26,6 @@ namespace osu.Game.Tests.Visual.Gameplay { Beatmap.Value = new DummyWorkingBeatmap(game); - AddStep("Reset logo position", () => logo = new OsuLogo { Position = new Vector2(0, 0) }); - AddStep("load dummy beatmap", () => stack.Push(loader = new PlayerLoader(() => new Player { AllowPause = false, @@ -58,6 +53,8 @@ namespace osu.Game.Tests.Visual.Gameplay AllowLeadIn = false, AllowResults = false, })); + + Scheduler.AddDelayed(() => slow.Ready = true, 5000); }); AddUntilStep("wait for no longer current", () => !loader.IsCurrentScreen()); diff --git a/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs b/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs index 5591bec0b8..0d4caff97e 100644 --- a/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs @@ -11,7 +11,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Testing; +using osu.Framework.Graphics.UserInterface; using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Mods; @@ -31,7 +31,11 @@ namespace osu.Game.Tests.Visual typeof(PlayerLoader), typeof(Player), typeof(Facade), - typeof(FacadeContainer) + typeof(FacadeContainer), + typeof(ButtonSystem), + typeof(ButtonSystemState), + typeof(Menu), + typeof(MainMenu) }; [Cached] @@ -68,15 +72,10 @@ namespace osu.Game.Tests.Visual AllowPause = false, AllowLeadIn = false, AllowResults = false, + Ready = false }))); } - [Test] - public void MainMenuTest() - { - AddStep("Add new Main Menu", () => LoadScreen(new MainMenu())); - } - private class TestFacadeContainer : FacadeContainer { protected override Facade CreateFacade() => new Facade @@ -119,16 +118,23 @@ namespace osu.Game.Tests.Visual base.LogoArriving(logo, resuming); logo.FadeIn(350); logo.ScaleTo(new Vector2(0.15f), 350, Easing.In); - facadeContainer.SetLogo(logo); + facadeContainer.SetLogo(logo, 0.3f, 1000, Easing.InOutQuint); + facadeContainer.Tracking = true; moveLogoFacade(); } + protected override void LogoExiting(OsuLogo logo) + { + base.LogoExiting(logo); + facadeContainer.Tracking = false; + } + private void moveLogoFacade() { Random random = new Random(); if (facadeFlowComponent.Transforms.Count == 0) { - facadeFlowComponent.Delay(500).MoveTo(new Vector2(random.Next(0, 800), random.Next(0, 600)), 300); + facadeFlowComponent.Delay(500).MoveTo(new Vector2(random.Next(0, (int)DrawWidth), random.Next(0, (int)DrawHeight)), 300); } if (randomPositions) @@ -159,11 +165,13 @@ namespace osu.Game.Tests.Visual private class TestPlayer : Player { + public bool Ready; + [BackgroundDependencyLoader] private void load() { // Never finish loading - while (true) + while (!Ready) Thread.Sleep(1); } } diff --git a/osu.Game/Graphics/Containers/FacadeContainer.cs b/osu.Game/Graphics/Containers/FacadeContainer.cs index 611cc94958..47ba738f1c 100644 --- a/osu.Game/Graphics/Containers/FacadeContainer.cs +++ b/osu.Game/Graphics/Containers/FacadeContainer.cs @@ -10,80 +10,98 @@ using osuTK; namespace osu.Game.Graphics.Containers { + /// + /// A container that creates a to be used by its children. + /// This container also updates the position and size of the Facade, and contains logic for tracking an on the Facade's position. + /// public class FacadeContainer : Container { + protected virtual Facade CreateFacade() => new Facade(); + + public Facade Facade => facade; + + /// + /// Whether or not the logo assigned to this FacadeContainer should be tracking the position its facade. + /// + public bool Tracking; + [Cached] private Facade facade; private OsuLogo logo; + private float facadeScale; - private bool tracking; - - protected virtual Facade CreateFacade() => new Facade(); + private Vector2 startPosition; + private Easing easing; + private double startTime; + private double duration; public FacadeContainer() { facade = CreateFacade(); } - private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(facade.ScreenSpaceDrawQuad.Centre); - - public void SetLogo(OsuLogo logo, double transformDelay = 0) + /// + /// Set the logo that should track the Facade's position, as well as how it should transform to its initial position. + /// + /// The instance of the logo to be used for tracking. + /// The scale of the facade. + /// The duration of the initial transform. Default is instant. + /// The easing type of the initial transform. + public void SetLogo(OsuLogo logo, float facadeScale, double duration = 0, Easing easing = Easing.None) { if (logo != null) { - facade.Size = new Vector2(logo.SizeForFlow * 0.3f); this.logo = logo; - Scheduler.AddDelayed(() => - { - tracking = true; - }, transformDelay); } + + this.facadeScale = facadeScale; + this.duration = duration; + this.easing = easing; } - private double startTime; - private double duration = 1000; - - private Vector2 startPosition; - private Easing easing = Easing.InOutExpo; + private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(facade.ScreenSpaceDrawQuad.Centre); protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); - if (logo == null || !tracking) + if (logo == null || !Tracking) return; - facade.Size = new Vector2(logo.SizeForFlow * 0.3f); + facade.Size = new Vector2(logo.SizeForFlow * facadeScale); if (facade.IsLoaded && logo.Position != logoTrackingPosition) { - if (logo.RelativePositionAxes != Axes.None) - { - logo.RelativePositionAxes = Axes.None; - logo.Position = logo.Parent.ToLocalSpace(logo.Position); - } + // Required for the correct position of the logo to be set with respect to logoTrackingPosition + logo.RelativePositionAxes = Axes.None; + // If this is our first update since tracking has started, initialize our starting values for interpolation if (startTime == 0) { startTime = Time.Current; + startPosition = logo.Position; } var endTime = startTime + duration; var remainingDuration = endTime - Time.Current; - if (remainingDuration <= 0) - { - remainingDuration = 0; - } + // If our transform should be instant, our position should already be at logoTrackingPosition, thus set the blend to 0. + // If we are already past when the transform should be finished playing, set the blend to 0 so that the logo is always at the position of the facade. + var blend = duration > 0 && remainingDuration > 0 + ? (float)Interpolation.ApplyEasing(easing, remainingDuration / duration) + : 0; - float currentTime = (float)Interpolation.ApplyEasing(easing, remainingDuration / duration); - logo.Position = Vector2.Lerp(logoTrackingPosition, startPosition, currentTime); + // Interpolate the position of the logo, where blend 0 is the position of the Facade, and blend 1 is where the logo was when it first began interpolating. + logo.Position = Vector2.Lerp(logoTrackingPosition, startPosition, blend); } } } } +/// +/// A placeholder container that serves as a dummy object to denote another object's location and size. +/// public class Facade : Container { -} \ No newline at end of file +} diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 3df4ef9059..4c0bcd399a 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -9,6 +9,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; @@ -16,6 +17,7 @@ using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Threading; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Input; using osu.Game.Input.Bindings; using osu.Game.Online.API; @@ -53,15 +55,19 @@ namespace osu.Game.Screens.Menu if (this.logo != null) { this.logo.Action = onOsuLogo; + facadeContainer.SetLogo(logo, 0.5f); // osuLogo.SizeForFlow relies on loading to be complete. buttonArea.Flow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + this.logo.SizeForFlow / 4), 0); updateLogoState(); } + else + { + facadeContainer.Tracking = false; + } } - private readonly Drawable iconFacade; private readonly ButtonArea buttonArea; private readonly Button backButton; @@ -71,26 +77,29 @@ namespace osu.Game.Screens.Menu private SampleChannel sampleBack; + private readonly FacadeContainer facadeContainer; + public ButtonSystem() { RelativeSizeAxes = Axes.Both; - Child = buttonArea = new ButtonArea(); + Child = facadeContainer = new FacadeContainer + { + RelativeSizeAxes = Axes.Both, + Child = buttonArea = new ButtonArea() + }; - buttonArea.AddRange(new[] + buttonArea.AddRange(new Container[] { new Button(@"settings", string.Empty, FontAwesome.fa_gear, new Color4(85, 85, 85, 255), () => OnSettings?.Invoke(), -WEDGE_WIDTH, Key.O), backButton = new Button(@"back", @"button-back-select", FontAwesome.fa_osu_left_o, new Color4(51, 58, 94, 255), () => State = ButtonSystemState.TopLevel, -WEDGE_WIDTH) { VisibleState = ButtonSystemState.Play, }, - iconFacade = new Container //need a container to make the osu! icon flow properly. - { - Size = new Vector2(0, ButtonArea.BUTTON_AREA_HEIGHT) - } + facadeContainer.Facade }); - buttonArea.Flow.CentreTarget = iconFacade; + buttonArea.Flow.CentreTarget = facadeContainer.Facade; } [Resolved(CanBeNull = true)] @@ -120,6 +129,15 @@ namespace osu.Game.Screens.Menu buttonArea.AddRange(buttonsPlay); buttonArea.AddRange(buttonsTopLevel); + buttonArea.ForEach(b => + { + if (b is Button) + { + b.Origin = Anchor.CentreLeft; + b.Anchor = Anchor.CentreLeft; + } + }); + isIdle.ValueChanged += idle => updateIdleState(idle.NewValue); if (idleTracker != null) isIdle.BindTo(idleTracker.IsIdle); @@ -247,7 +265,7 @@ namespace osu.Game.Screens.Menu logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => { - logoTracking = false; + facadeContainer.Tracking = false; game?.Toolbar.Hide(); @@ -266,19 +284,16 @@ namespace osu.Game.Screens.Menu break; case ButtonSystemState.Initial: logo.ClearTransforms(targetMember: nameof(Position)); - logo.RelativePositionAxes = Axes.None; bool impact = logo.Scale.X > 0.6f; if (lastState == ButtonSystemState.Initial) logo.ScaleTo(0.5f, 200, Easing.In); - logo.MoveTo(logoTrackingPosition, lastState == ButtonSystemState.EnteringMode ? 0 : 200, Easing.In); - logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => { - logoTracking = true; + facadeContainer.Tracking = true; if (impact) logo.Impact(); @@ -288,35 +303,17 @@ namespace osu.Game.Screens.Menu break; default: logo.ClearTransforms(targetMember: nameof(Position)); - logo.RelativePositionAxes = Axes.None; - logoTracking = true; + facadeContainer.Tracking = true; logo.ScaleTo(0.5f, 200, Easing.OutQuint); break; } break; case ButtonSystemState.EnteringMode: - logoTracking = true; + facadeContainer.Tracking = true; break; } } - - private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(iconFacade.ScreenSpaceDrawQuad.Centre); - - private bool logoTracking; - - protected override void Update() - { - base.Update(); - - if (logo != null) - { - if (logoTracking && logo.RelativePositionAxes == Axes.None && iconFacade.IsLoaded) - logo.Position = logoTrackingPosition; - - iconFacade.Width = logo.SizeForFlow * 0.5f; - } - } } public enum ButtonSystemState diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index b7155f771f..f35eb6979d 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Play private Player player; - private FacadeContainer content; + private FacadeContainer facadeContainer; protected virtual FacadeContainer CreateFacadeContainer() => new FacadeContainer(); @@ -62,11 +62,11 @@ namespace osu.Game.Screens.Play [BackgroundDependencyLoader] private void load() { - InternalChild = content = CreateFacadeContainer(); - content.Anchor = Anchor.Centre; - content.Origin = Anchor.Centre; - content.RelativeSizeAxes = Axes.Both; - content.Children = new Drawable[] + InternalChild = facadeContainer = CreateFacadeContainer(); + facadeContainer.Anchor = Anchor.Centre; + facadeContainer.Origin = Anchor.Centre; + facadeContainer.RelativeSizeAxes = Axes.Both; + facadeContainer.Children = new Drawable[] { info = new BeatmapMetadataDisplay(Beatmap.Value) { @@ -122,21 +122,21 @@ namespace osu.Game.Screens.Play private void contentIn() { - content.ScaleTo(1, 650, Easing.OutQuint); - content.FadeInFromZero(400); + facadeContainer.ScaleTo(1, 650, Easing.OutQuint); + facadeContainer.FadeInFromZero(400); } private void contentOut() { - content.ScaleTo(0.7f, 300, Easing.InQuint); - content.FadeOut(250); + facadeContainer.ScaleTo(0.7f, 300, Easing.InQuint); + facadeContainer.FadeOut(250); } public override void OnEntering(IScreen last) { base.OnEntering(last); - content.ScaleTo(0.7f); + facadeContainer.ScaleTo(0.7f); Background?.FadeColour(Color4.White, 800, Easing.OutQuint); contentIn(); @@ -155,7 +155,15 @@ namespace osu.Game.Screens.Play logo.MoveTo(new Vector2(0.5f), duration, Easing.In); logo.FadeIn(350); - content.SetLogo(logo, duration); + facadeContainer.SetLogo(logo, 0.3f, 500, Easing.InOutQuint); + + Scheduler.AddDelayed(() => facadeContainer.Tracking = true, duration); + } + + protected override void LogoExiting(OsuLogo logo) + { + base.LogoExiting(logo); + facadeContainer.Tracking = false; } protected override void LoadComplete() @@ -230,7 +238,7 @@ namespace osu.Game.Screens.Play public override bool OnExiting(IScreen next) { - content.ScaleTo(0.7f, 150, Easing.InQuint); + facadeContainer.ScaleTo(0.7f, 150, Easing.InQuint); this.FadeOut(150); cancelLoad(); @@ -305,7 +313,6 @@ namespace osu.Game.Screens.Play private LoadingAnimation loading; private Sprite backgroundSprite; private ModDisplay modDisplay; - private FillFlowContainer fillFlowContainer; public bool Loading { @@ -340,7 +347,7 @@ namespace osu.Game.Screens.Play AutoSizeAxes = Axes.Both; Children = new Drawable[] { - fillFlowContainer = new FillFlowContainer + new FillFlowContainer { AutoSizeAxes = Axes.Both, Origin = Anchor.TopCentre, From 384eee33957a30c88ec2b8ff2baffa30ede3bb98 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 27 Mar 2019 11:32:26 +0900 Subject: [PATCH 07/54] Remove DI requirement for the Facade in PlayerLoader --- .../Visual/TestCaseFacadeContainer.cs | 11 +++-------- osu.Game/Graphics/Containers/FacadeContainer.cs | 17 ++++++----------- osu.Game/Screens/Play/PlayerLoader.cs | 8 +++++--- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs b/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs index 0d4caff97e..6291b026f3 100644 --- a/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs @@ -93,7 +93,7 @@ namespace osu.Game.Tests.Visual private class TestScreen : OsuScreen { private TestFacadeContainer facadeContainer; - private FacadeFlowComponent facadeFlowComponent; + private Facade facadeFlowComponent; private readonly bool randomPositions; public TestScreen(bool randomPositions = false) @@ -104,13 +104,8 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load() { - InternalChild = facadeContainer = new TestFacadeContainer - { - Child = facadeFlowComponent = new FacadeFlowComponent - { - AutoSizeAxes = Axes.Both - } - }; + InternalChild = facadeContainer = new TestFacadeContainer(); + facadeContainer.Child = facadeFlowComponent = facadeContainer.Facade; } protected override void LogoArriving(OsuLogo logo, bool resuming) diff --git a/osu.Game/Graphics/Containers/FacadeContainer.cs b/osu.Game/Graphics/Containers/FacadeContainer.cs index 47ba738f1c..11c256725d 100644 --- a/osu.Game/Graphics/Containers/FacadeContainer.cs +++ b/osu.Game/Graphics/Containers/FacadeContainer.cs @@ -1,7 +1,6 @@ // 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.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.MathUtils; @@ -18,19 +17,15 @@ namespace osu.Game.Graphics.Containers { protected virtual Facade CreateFacade() => new Facade(); - public Facade Facade => facade; + public readonly Facade Facade; /// /// Whether or not the logo assigned to this FacadeContainer should be tracking the position its facade. /// public bool Tracking; - [Cached] - private Facade facade; - private OsuLogo logo; private float facadeScale; - private Vector2 startPosition; private Easing easing; private double startTime; @@ -38,11 +33,11 @@ namespace osu.Game.Graphics.Containers public FacadeContainer() { - facade = CreateFacade(); + Facade = CreateFacade(); } /// - /// Set the logo that should track the Facade's position, as well as how it should transform to its initial position. + /// Assign the logo that should track the Facade's position, as well as how it should transform to its initial position. /// /// The instance of the logo to be used for tracking. /// The scale of the facade. @@ -60,7 +55,7 @@ namespace osu.Game.Graphics.Containers this.easing = easing; } - private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(facade.ScreenSpaceDrawQuad.Centre); + private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(Facade.ScreenSpaceDrawQuad.Centre); protected override void UpdateAfterChildren() { @@ -69,9 +64,9 @@ namespace osu.Game.Graphics.Containers if (logo == null || !Tracking) return; - facade.Size = new Vector2(logo.SizeForFlow * facadeScale); + Facade.Size = new Vector2(logo.SizeForFlow * facadeScale); - if (facade.IsLoaded && logo.Position != logoTrackingPosition) + if (Facade.IsLoaded && logo.Position != logoTrackingPosition) { // Required for the correct position of the logo to be set with respect to logoTrackingPosition logo.RelativePositionAxes = Axes.None; diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index f35eb6979d..4601cf71e0 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -68,7 +68,7 @@ namespace osu.Game.Screens.Play facadeContainer.RelativeSizeAxes = Axes.Both; facadeContainer.Children = new Drawable[] { - info = new BeatmapMetadataDisplay(Beatmap.Value) + info = new BeatmapMetadataDisplay(Beatmap.Value, facadeContainer.Facade) { Alpha = 0, Anchor = Anchor.Centre, @@ -310,6 +310,7 @@ namespace osu.Game.Screens.Play } private readonly WorkingBeatmap beatmap; + private readonly Facade facade; private LoadingAnimation loading; private Sprite backgroundSprite; private ModDisplay modDisplay; @@ -331,13 +332,14 @@ namespace osu.Game.Screens.Play } } - public BeatmapMetadataDisplay(WorkingBeatmap beatmap) + public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Facade facade) { this.beatmap = beatmap; + this.facade = facade; } [BackgroundDependencyLoader] - private void load(Facade facade) + private void load() { var metadata = beatmap.BeatmapInfo?.Metadata ?? new BeatmapMetadata(); From efeed715170c5e9e45501cabda7da80d59f947fa Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 27 Mar 2019 11:37:16 +0900 Subject: [PATCH 08/54] Add comment --- osu.Game/Screens/Menu/ButtonSystem.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 4c0bcd399a..7b458809b1 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -64,6 +64,8 @@ namespace osu.Game.Screens.Menu } else { + // If logo is null, we are suspending from the screen that uses this ButtonSystem. + // We should stop tracking as the facade is now out of scope. facadeContainer.Tracking = false; } } From 43c6a8d2e59a3fbdba14ce3014abaa289d32bef8 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 27 Mar 2019 11:44:50 +0900 Subject: [PATCH 09/54] use a property instead --- osu.Game/Graphics/Containers/FacadeContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/FacadeContainer.cs b/osu.Game/Graphics/Containers/FacadeContainer.cs index 11c256725d..0ec5e77c72 100644 --- a/osu.Game/Graphics/Containers/FacadeContainer.cs +++ b/osu.Game/Graphics/Containers/FacadeContainer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Graphics.Containers { protected virtual Facade CreateFacade() => new Facade(); - public readonly Facade Facade; + public Facade Facade { get; } /// /// Whether or not the logo assigned to this FacadeContainer should be tracking the position its facade. From 4b1e564df2fe8d7882725ad71b744dd6ffc70f42 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 27 Mar 2019 14:31:07 +0900 Subject: [PATCH 10/54] Fix test cases potentially getting stuck after 4th run --- osu.Game.Tests/Visual/TestCaseFacadeContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs b/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs index 6291b026f3..55842af867 100644 --- a/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs @@ -163,10 +163,10 @@ namespace osu.Game.Tests.Visual public bool Ready; [BackgroundDependencyLoader] - private void load() + private void load(CancellationToken token) { // Never finish loading - while (!Ready) + while (!Ready && !token.IsCancellationRequested) Thread.Sleep(1); } } From ca7a20585dbb58b09b7426949e0ad4b28543efd5 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 27 Mar 2019 17:28:53 +0900 Subject: [PATCH 11/54] Apply reviews, delete playerloader test --- ...iner.cs => TestCaseLogoFacadeContainer.cs} | 72 +++---------- .../Graphics/Containers/FacadeContainer.cs | 102 ------------------ .../Containers/LogoFacadeContainer.cs | 100 +++++++++++++++++ osu.Game/Screens/Menu/ButtonSystem.cs | 25 +++-- osu.Game/Screens/Play/PlayerLoader.cs | 70 ++++++------ 5 files changed, 161 insertions(+), 208 deletions(-) rename osu.Game.Tests/Visual/{TestCaseFacadeContainer.cs => TestCaseLogoFacadeContainer.cs} (60%) delete mode 100644 osu.Game/Graphics/Containers/FacadeContainer.cs create mode 100644 osu.Game/Graphics/Containers/LogoFacadeContainer.cs diff --git a/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs similarity index 60% rename from osu.Game.Tests/Visual/TestCaseFacadeContainer.cs rename to osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs index 55842af867..0e7f4d4bc0 100644 --- a/osu.Game.Tests/Visual/TestCaseFacadeContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs @@ -9,7 +9,6 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Game.Configuration; @@ -24,14 +23,14 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual { - public class TestCaseFacadeContainer : ScreenTestCase + public class TestCaseLogoFacadeContainer : ScreenTestCase { public override IReadOnlyList RequiredTypes => new[] { typeof(PlayerLoader), typeof(Player), - typeof(Facade), - typeof(FacadeContainer), + typeof(LogoFacadeContainer.Facade), + typeof(LogoFacadeContainer), typeof(ButtonSystem), typeof(ButtonSystemState), typeof(Menu), @@ -43,7 +42,7 @@ namespace osu.Game.Tests.Visual private readonly Bindable uiScale = new Bindable(); - public TestCaseFacadeContainer() + public TestCaseLogoFacadeContainer() { Add(logo = new OsuLogo()); } @@ -63,20 +62,7 @@ namespace osu.Game.Tests.Visual AddStep("Move facade to random position", () => LoadScreen(new TestScreen(randomPositions))); } - [Test] - public void PlayerLoaderTest() - { - AddToggleStep("Toggle mods", b => { Beatmap.Value.Mods.Value = b ? Beatmap.Value.Mods.Value.Concat(new[] { new OsuModNoFail() }) : Enumerable.Empty(); }); - AddStep("Add new playerloader", () => LoadScreen(new TestPlayerLoader(() => new TestPlayer - { - AllowPause = false, - AllowLeadIn = false, - AllowResults = false, - Ready = false - }))); - } - - private class TestFacadeContainer : FacadeContainer + private class TestLogoFacadeContainer : LogoFacadeContainer { protected override Facade CreateFacade() => new Facade { @@ -92,8 +78,8 @@ namespace osu.Game.Tests.Visual private class TestScreen : OsuScreen { - private TestFacadeContainer facadeContainer; - private Facade facadeFlowComponent; + private TestLogoFacadeContainer logoFacadeContainer; + private LogoFacadeContainer.Facade facadeFlowComponent; private readonly bool randomPositions; public TestScreen(bool randomPositions = false) @@ -104,8 +90,8 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load() { - InternalChild = facadeContainer = new TestFacadeContainer(); - facadeContainer.Child = facadeFlowComponent = facadeContainer.Facade; + InternalChild = logoFacadeContainer = new TestLogoFacadeContainer(); + logoFacadeContainer.Child = facadeFlowComponent = logoFacadeContainer.LogoFacade; } protected override void LogoArriving(OsuLogo logo, bool resuming) @@ -113,15 +99,15 @@ namespace osu.Game.Tests.Visual base.LogoArriving(logo, resuming); logo.FadeIn(350); logo.ScaleTo(new Vector2(0.15f), 350, Easing.In); - facadeContainer.SetLogo(logo, 0.3f, 1000, Easing.InOutQuint); - facadeContainer.Tracking = true; + logoFacadeContainer.SetLogo(logo, 0.3f, 1000, Easing.InOutQuint); + logoFacadeContainer.Tracking = true; moveLogoFacade(); } protected override void LogoExiting(OsuLogo logo) { base.LogoExiting(logo); - facadeContainer.Tracking = false; + logoFacadeContainer.Tracking = false; } private void moveLogoFacade() @@ -136,39 +122,5 @@ namespace osu.Game.Tests.Visual Schedule(moveLogoFacade); } } - - private class FacadeFlowComponent : FillFlowContainer - { - [BackgroundDependencyLoader] - private void load(Facade facade) - { - facade.Anchor = Anchor.TopCentre; - facade.Origin = Anchor.TopCentre; - Child = facade; - } - } - - private class TestPlayerLoader : PlayerLoader - { - public TestPlayerLoader(Func player) - : base(player) - { - } - - protected override FacadeContainer CreateFacadeContainer() => new TestFacadeContainer(); - } - - private class TestPlayer : Player - { - public bool Ready; - - [BackgroundDependencyLoader] - private void load(CancellationToken token) - { - // Never finish loading - while (!Ready && !token.IsCancellationRequested) - Thread.Sleep(1); - } - } } } diff --git a/osu.Game/Graphics/Containers/FacadeContainer.cs b/osu.Game/Graphics/Containers/FacadeContainer.cs deleted file mode 100644 index 0ec5e77c72..0000000000 --- a/osu.Game/Graphics/Containers/FacadeContainer.cs +++ /dev/null @@ -1,102 +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 osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.MathUtils; -using osu.Game.Screens.Menu; -using osuTK; - -namespace osu.Game.Graphics.Containers -{ - /// - /// A container that creates a to be used by its children. - /// This container also updates the position and size of the Facade, and contains logic for tracking an on the Facade's position. - /// - public class FacadeContainer : Container - { - protected virtual Facade CreateFacade() => new Facade(); - - public Facade Facade { get; } - - /// - /// Whether or not the logo assigned to this FacadeContainer should be tracking the position its facade. - /// - public bool Tracking; - - private OsuLogo logo; - private float facadeScale; - private Vector2 startPosition; - private Easing easing; - private double startTime; - private double duration; - - public FacadeContainer() - { - Facade = CreateFacade(); - } - - /// - /// Assign the logo that should track the Facade's position, as well as how it should transform to its initial position. - /// - /// The instance of the logo to be used for tracking. - /// The scale of the facade. - /// The duration of the initial transform. Default is instant. - /// The easing type of the initial transform. - public void SetLogo(OsuLogo logo, float facadeScale, double duration = 0, Easing easing = Easing.None) - { - if (logo != null) - { - this.logo = logo; - } - - this.facadeScale = facadeScale; - this.duration = duration; - this.easing = easing; - } - - private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(Facade.ScreenSpaceDrawQuad.Centre); - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - if (logo == null || !Tracking) - return; - - Facade.Size = new Vector2(logo.SizeForFlow * facadeScale); - - if (Facade.IsLoaded && logo.Position != logoTrackingPosition) - { - // Required for the correct position of the logo to be set with respect to logoTrackingPosition - logo.RelativePositionAxes = Axes.None; - - // If this is our first update since tracking has started, initialize our starting values for interpolation - if (startTime == 0) - { - startTime = Time.Current; - startPosition = logo.Position; - } - - var endTime = startTime + duration; - var remainingDuration = endTime - Time.Current; - - // If our transform should be instant, our position should already be at logoTrackingPosition, thus set the blend to 0. - // If we are already past when the transform should be finished playing, set the blend to 0 so that the logo is always at the position of the facade. - var blend = duration > 0 && remainingDuration > 0 - ? (float)Interpolation.ApplyEasing(easing, remainingDuration / duration) - : 0; - - // Interpolate the position of the logo, where blend 0 is the position of the Facade, and blend 1 is where the logo was when it first began interpolating. - logo.Position = Vector2.Lerp(logoTrackingPosition, startPosition, blend); - } - } - } -} - -/// -/// A placeholder container that serves as a dummy object to denote another object's location and size. -/// -public class Facade : Container -{ -} diff --git a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs new file mode 100644 index 0000000000..a556fa697c --- /dev/null +++ b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs @@ -0,0 +1,100 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.MathUtils; +using osu.Game.Screens.Menu; +using osuTK; + +namespace osu.Game.Graphics.Containers +{ + /// + /// A container that creates a to be used to update and track the position of an . + /// + public class LogoFacadeContainer : Container + { + protected virtual Facade CreateFacade() => new Facade(); + + public Facade LogoFacade { get; } + + /// + /// Whether or not the logo assigned to this FacadeContainer should be tracking the position its facade. + /// + public bool Tracking = false; + + private OsuLogo logo; + private float facadeScale; + private Vector2 startPosition; + private Easing easing; + private double? startTime; + private double duration; + + public LogoFacadeContainer() + { + LogoFacade = CreateFacade(); + } + + /// + /// Assign the logo that should track the Facade's position, as well as how it should transform to its initial position. + /// + /// The instance of the logo to be used for tracking. + /// The scale of the facade. Does not actually affect the logo itself. + /// The duration of the initial transform. Default is instant. + /// The easing type of the initial transform. + public void SetLogo(OsuLogo logo, float facadeScale, double duration = 0, Easing easing = Easing.None) + { + this.logo = logo ?? throw new ArgumentNullException(nameof(logo)); + this.facadeScale = facadeScale; + this.duration = duration; + this.easing = easing; + } + + private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre); + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + if (logo == null || !Tracking) + return; + + LogoFacade.Size = new Vector2(logo.SizeForFlow * facadeScale); + + if (LogoFacade.Parent != null && logo.Position != logoTrackingPosition) + { + // Required for the correct position of the logo to be set with respect to logoTrackingPosition + logo.RelativePositionAxes = Axes.None; + + // If this is our first update since tracking has started, initialize our starting values for interpolation + if (startTime == null) + { + startTime = Time.Current; + startPosition = logo.Position; + } + + if (duration != 0) + { + double elapsedDuration = Time.Current - startTime ?? 0; + + var mount = (float)Interpolation.ApplyEasing(easing, Math.Min(elapsedDuration / duration, 1)); + + // Interpolate the position of the logo, where mount 0 is where the logo was when it first began interpolating, and mount 1 is the target location. + logo.Position = Vector2.Lerp(startPosition, logoTrackingPosition, mount); + } + else + { + logo.Position = logoTrackingPosition; + } + } + } + + /// + /// A placeholder container that serves as a dummy object to denote another object's location and size. + /// + public class Facade : Container + { + } + } +} diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 7b458809b1..3fad36cddb 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -48,6 +48,10 @@ namespace osu.Game.Screens.Menu private OsuLogo logo; + /// + /// Assign the that this ButtonSystem should manage the position of. + /// + /// The instance of the logo to be assigned. If null, we are suspending from the screen that uses this ButtonSystem. public void SetOsuLogo(OsuLogo logo) { this.logo = logo; @@ -55,7 +59,7 @@ namespace osu.Game.Screens.Menu if (this.logo != null) { this.logo.Action = onOsuLogo; - facadeContainer.SetLogo(logo, 0.5f); + logoFacadeContainer.SetLogo(logo, 0.5f); // osuLogo.SizeForFlow relies on loading to be complete. buttonArea.Flow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + this.logo.SizeForFlow / 4), 0); @@ -64,9 +68,8 @@ namespace osu.Game.Screens.Menu } else { - // If logo is null, we are suspending from the screen that uses this ButtonSystem. // We should stop tracking as the facade is now out of scope. - facadeContainer.Tracking = false; + logoFacadeContainer.Tracking = false; } } @@ -79,13 +82,13 @@ namespace osu.Game.Screens.Menu private SampleChannel sampleBack; - private readonly FacadeContainer facadeContainer; + private readonly LogoFacadeContainer logoFacadeContainer; public ButtonSystem() { RelativeSizeAxes = Axes.Both; - Child = facadeContainer = new FacadeContainer + Child = logoFacadeContainer = new LogoFacadeContainer { RelativeSizeAxes = Axes.Both, Child = buttonArea = new ButtonArea() @@ -98,10 +101,10 @@ namespace osu.Game.Screens.Menu { VisibleState = ButtonSystemState.Play, }, - facadeContainer.Facade + logoFacadeContainer.LogoFacade }); - buttonArea.Flow.CentreTarget = facadeContainer.Facade; + buttonArea.Flow.CentreTarget = logoFacadeContainer.LogoFacade; } [Resolved(CanBeNull = true)] @@ -267,7 +270,7 @@ namespace osu.Game.Screens.Menu logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => { - facadeContainer.Tracking = false; + logoFacadeContainer.Tracking = false; game?.Toolbar.Hide(); @@ -295,7 +298,7 @@ namespace osu.Game.Screens.Menu logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => { - facadeContainer.Tracking = true; + logoFacadeContainer.Tracking = true; if (impact) logo.Impact(); @@ -305,14 +308,14 @@ namespace osu.Game.Screens.Menu break; default: logo.ClearTransforms(targetMember: nameof(Position)); - facadeContainer.Tracking = true; + logoFacadeContainer.Tracking = true; logo.ScaleTo(0.5f, 200, Easing.OutQuint); break; } break; case ButtonSystemState.EnteringMode: - facadeContainer.Tracking = true; + logoFacadeContainer.Tracking = true; break; } } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 4601cf71e0..6ac2c8220f 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -33,9 +33,7 @@ namespace osu.Game.Screens.Play private Player player; - private FacadeContainer facadeContainer; - - protected virtual FacadeContainer CreateFacadeContainer() => new FacadeContainer(); + private LogoFacadeContainer content; private BeatmapMetadataDisplay info; @@ -62,30 +60,32 @@ namespace osu.Game.Screens.Play [BackgroundDependencyLoader] private void load() { - InternalChild = facadeContainer = CreateFacadeContainer(); - facadeContainer.Anchor = Anchor.Centre; - facadeContainer.Origin = Anchor.Centre; - facadeContainer.RelativeSizeAxes = Axes.Both; - facadeContainer.Children = new Drawable[] + InternalChild = content = new LogoFacadeContainer { - info = new BeatmapMetadataDisplay(Beatmap.Value, facadeContainer.Facade) + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - Alpha = 0, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - new FillFlowContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 20), - Margin = new MarginPadding(25), - Children = new PlayerSettingsGroup[] + info = new BeatmapMetadataDisplay(Beatmap.Value, content.LogoFacade) { - VisualSettings = new VisualSettings(), - new InputSettings() + Alpha = 0, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new FillFlowContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Margin = new MarginPadding(25), + Children = new PlayerSettingsGroup[] + { + VisualSettings = new VisualSettings(), + new InputSettings() + } } } }; @@ -122,21 +122,21 @@ namespace osu.Game.Screens.Play private void contentIn() { - facadeContainer.ScaleTo(1, 650, Easing.OutQuint); - facadeContainer.FadeInFromZero(400); + content.ScaleTo(1, 650, Easing.OutQuint); + content.FadeInFromZero(400); } private void contentOut() { - facadeContainer.ScaleTo(0.7f, 300, Easing.InQuint); - facadeContainer.FadeOut(250); + content.ScaleTo(0.7f, 300, Easing.InQuint); + content.FadeOut(250); } public override void OnEntering(IScreen last) { base.OnEntering(last); - facadeContainer.ScaleTo(0.7f); + content.ScaleTo(0.7f); Background?.FadeColour(Color4.White, 800, Easing.OutQuint); contentIn(); @@ -155,15 +155,15 @@ namespace osu.Game.Screens.Play logo.MoveTo(new Vector2(0.5f), duration, Easing.In); logo.FadeIn(350); - facadeContainer.SetLogo(logo, 0.3f, 500, Easing.InOutQuint); + content.SetLogo(logo, 0.3f, 500, Easing.InOutExpo); - Scheduler.AddDelayed(() => facadeContainer.Tracking = true, duration); + Scheduler.AddDelayed(() => content.Tracking = true, resuming ? 0 : 500); } protected override void LogoExiting(OsuLogo logo) { base.LogoExiting(logo); - facadeContainer.Tracking = false; + content.Tracking = false; } protected override void LoadComplete() @@ -238,7 +238,7 @@ namespace osu.Game.Screens.Play public override bool OnExiting(IScreen next) { - facadeContainer.ScaleTo(0.7f, 150, Easing.InQuint); + content.ScaleTo(0.7f, 150, Easing.InQuint); this.FadeOut(150); cancelLoad(); @@ -310,7 +310,7 @@ namespace osu.Game.Screens.Play } private readonly WorkingBeatmap beatmap; - private readonly Facade facade; + private readonly LogoFacadeContainer.Facade facade; private LoadingAnimation loading; private Sprite backgroundSprite; private ModDisplay modDisplay; @@ -332,7 +332,7 @@ namespace osu.Game.Screens.Play } } - public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Facade facade) + public BeatmapMetadataDisplay(WorkingBeatmap beatmap, LogoFacadeContainer.Facade facade) { this.beatmap = beatmap; this.facade = facade; From 34a33b335d1e5046cd1cc5f9712f5994753d8fc9 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 27 Mar 2019 17:29:38 +0900 Subject: [PATCH 12/54] oops --- osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs index 0e7f4d4bc0..152b9b1706 100644 --- a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs @@ -3,8 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Threading; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -13,8 +11,6 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Game.Configuration; using osu.Game.Graphics.Containers; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; From 2e3791be1ca9e67676e4b5b42be184cd7c001060 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 27 Mar 2019 18:11:12 +0900 Subject: [PATCH 13/54] Fix incorrect usage of LogoFacade --- osu.Game/Screens/Play/PlayerLoader.cs | 39 ++++++++++++++------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 6ac2c8220f..3f547755c1 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -65,27 +65,28 @@ namespace osu.Game.Screens.Play Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - Children = new Drawable[] + }; + + content.Children = new Drawable[] + { + info = new BeatmapMetadataDisplay(Beatmap.Value, content.LogoFacade) { - info = new BeatmapMetadataDisplay(Beatmap.Value, content.LogoFacade) + Alpha = 0, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new FillFlowContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Margin = new MarginPadding(25), + Children = new PlayerSettingsGroup[] { - Alpha = 0, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - new FillFlowContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 20), - Margin = new MarginPadding(25), - Children = new PlayerSettingsGroup[] - { - VisualSettings = new VisualSettings(), - new InputSettings() - } + VisualSettings = new VisualSettings(), + new InputSettings() } } }; From 061527a260241e78b5ce479006f6c91e2b91e271 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 27 Mar 2019 20:04:01 +0900 Subject: [PATCH 14/54] Add new automated tests for logofacade, reset interpolation --- .../Visual/TestCaseLogoFacadeContainer.cs | 115 ++++++++++++++---- .../Containers/LogoFacadeContainer.cs | 11 +- osu.Game/Screens/Play/PlayerLoader.cs | 4 +- 3 files changed, 103 insertions(+), 27 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs index 152b9b1706..8be0d25a86 100644 --- a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs @@ -7,8 +7,10 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Screens; using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Screens; @@ -25,7 +27,6 @@ namespace osu.Game.Tests.Visual { typeof(PlayerLoader), typeof(Player), - typeof(LogoFacadeContainer.Facade), typeof(LogoFacadeContainer), typeof(ButtonSystem), typeof(ButtonSystemState), @@ -47,36 +48,65 @@ namespace osu.Game.Tests.Visual private void load(OsuConfigManager config) { config.BindWith(OsuSetting.UIScale, uiScale); - AddSliderStep("Adjust scale", 1f, 1.5f, 1f, v => uiScale.Value = v); + AddSliderStep("Adjust scale", 0.8f, 1.5f, 1f, v => uiScale.Value = v); } + /// + /// Move the facade to 0,0, then move it to a random new location while the logo is still transforming to it. + /// Check if the logo is still tracking the facade. + /// [Test] - public void IsolatedTest() + public void MoveFacadeTest() { + TestScreen screen = null; bool randomPositions = false; AddToggleStep("Toggle move continuously", b => randomPositions = b); - AddStep("Move facade to random position", () => LoadScreen(new TestScreen(randomPositions))); + AddStep("Move facade to random position", () => LoadScreen(screen = new TestScreen(randomPositions))); + AddUntilStep("Screen is current", () => screen.IsCurrentScreen()); + waitForMove(); + AddAssert("Logo is tracking", () => screen.IsLogoTracking); } - private class TestLogoFacadeContainer : LogoFacadeContainer + /// + /// Check if the facade is removed from the container, the logo stops tracking. + /// + [Test] + public void RemoveFacadeTest() { - protected override Facade CreateFacade() => new Facade - { - Colour = Color4.Tomato, - Alpha = 0.35f, - Child = new Box - { - Colour = Color4.Tomato, - RelativeSizeAxes = Axes.Both, - }, - }; + TestScreen screen = null; + AddStep("Move facade to random position", () => LoadScreen(screen = new TestScreen())); + AddUntilStep("Screen is current", () => screen.IsCurrentScreen()); + AddStep("Remove facade from FacadeContainer", () => screen.RemoveFacade()); + waitForMove(); + AddAssert("Logo is not tracking", () => !screen.IsLogoTracking); } + /// + /// Check if the facade gets added to a new container, tracking starts on the new facade. + /// + [Test] + public void TransferFacadeTest() + { + TestScreen screen = null; + AddStep("Move facade to random position", () => LoadScreen(screen = new TestScreen())); + AddUntilStep("Screen is current", () => screen.IsCurrentScreen()); + AddStep("Remove facade from FacadeContainer", () => screen.RemoveFacade()); + AddStep("Transfer facade to a new container", () => screen.TransferFacade()); + waitForMove(); + AddAssert("Logo is tracking", () => screen.IsLogoTracking); + } + + private void waitForMove() => AddWaitStep("Wait for transforms to finish", 5); + private class TestScreen : OsuScreen { - private TestLogoFacadeContainer logoFacadeContainer; - private LogoFacadeContainer.Facade facadeFlowComponent; + private LogoFacadeContainer logoFacadeContainer; + private Container transferContainer; + private Container logoFacade; private readonly bool randomPositions; + private OsuLogo logo; + private Box visualBox; + private Box transferContainerBox; public TestScreen(bool randomPositions = false) { @@ -86,13 +116,55 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load() { - InternalChild = logoFacadeContainer = new TestLogoFacadeContainer(); - logoFacadeContainer.Child = facadeFlowComponent = logoFacadeContainer.LogoFacade; + InternalChildren = new Drawable[] + { + logoFacadeContainer = new LogoFacadeContainer + { + Alpha = 0.35f, + RelativeSizeAxes = Axes.None, + Size = new Vector2(107), + Child = visualBox = new Box + { + Colour = Color4.Tomato, + RelativeSizeAxes = Axes.Both, + } + }, + transferContainer = new Container + { + Alpha = 0.35f, + RelativeSizeAxes = Axes.None, + Size = new Vector2(107), + Child = transferContainerBox = new Box + { + Colour = Color4.White, + RelativeSizeAxes = Axes.Both, + } + }, + }; + + logoFacadeContainer.Add(logoFacade = logoFacadeContainer.LogoFacade); + } + + public bool IsLogoTracking => logo.Position == logo.Parent.ToLocalSpace(logoFacadeContainer.LogoFacade.ScreenSpaceDrawQuad.Centre); + + public void RemoveFacade() + { + logoFacadeContainer.Remove(logoFacade); + visualBox.Colour = Color4.White; + moveLogoFacade(); + } + + public void TransferFacade() + { + transferContainer.Add(logoFacade); + transferContainerBox.Colour = Color4.Tomato; + moveLogoFacade(); } protected override void LogoArriving(OsuLogo logo, bool resuming) { base.LogoArriving(logo, resuming); + this.logo = logo; logo.FadeIn(350); logo.ScaleTo(new Vector2(0.15f), 350, Easing.In); logoFacadeContainer.SetLogo(logo, 0.3f, 1000, Easing.InOutQuint); @@ -109,9 +181,10 @@ namespace osu.Game.Tests.Visual private void moveLogoFacade() { Random random = new Random(); - if (facadeFlowComponent.Transforms.Count == 0) + if (logoFacade.Transforms.Count == 0 && transferContainer.Transforms.Count == 0) { - facadeFlowComponent.Delay(500).MoveTo(new Vector2(random.Next(0, (int)DrawWidth), random.Next(0, (int)DrawHeight)), 300); + logoFacadeContainer.Delay(500).MoveTo(new Vector2(random.Next(0, (int)DrawWidth), random.Next(0, (int)DrawHeight)), 300); + transferContainer.Delay(500).MoveTo(new Vector2(random.Next(0, (int)DrawWidth), random.Next(0, (int)DrawHeight)), 300); } if (randomPositions) diff --git a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs index a556fa697c..f4599e0039 100644 --- a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs +++ b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs @@ -26,8 +26,8 @@ namespace osu.Game.Graphics.Containers private OsuLogo logo; private float facadeScale; - private Vector2 startPosition; private Easing easing; + private Vector2? startPosition; private double? startTime; private double duration; @@ -49,6 +49,9 @@ namespace osu.Game.Graphics.Containers this.facadeScale = facadeScale; this.duration = duration; this.easing = easing; + + startTime = null; + startPosition = null; } private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre); @@ -68,7 +71,7 @@ namespace osu.Game.Graphics.Containers logo.RelativePositionAxes = Axes.None; // If this is our first update since tracking has started, initialize our starting values for interpolation - if (startTime == null) + if (startTime == null || startPosition == null) { startTime = Time.Current; startPosition = logo.Position; @@ -76,12 +79,12 @@ namespace osu.Game.Graphics.Containers if (duration != 0) { - double elapsedDuration = Time.Current - startTime ?? 0; + double elapsedDuration = Time.Current - startTime ?? throw new ArgumentNullException(nameof(startTime)); var mount = (float)Interpolation.ApplyEasing(easing, Math.Min(elapsedDuration / duration, 1)); // Interpolate the position of the logo, where mount 0 is where the logo was when it first began interpolating, and mount 1 is the target location. - logo.Position = Vector2.Lerp(startPosition, logoTrackingPosition, mount); + logo.Position = Vector2.Lerp(startPosition ?? throw new ArgumentNullException(nameof(startPosition)), logoTrackingPosition, mount); } else { diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 3f547755c1..72fbb378a4 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -311,7 +311,7 @@ namespace osu.Game.Screens.Play } private readonly WorkingBeatmap beatmap; - private readonly LogoFacadeContainer.Facade facade; + private readonly Container facade; private LoadingAnimation loading; private Sprite backgroundSprite; private ModDisplay modDisplay; @@ -333,7 +333,7 @@ namespace osu.Game.Screens.Play } } - public BeatmapMetadataDisplay(WorkingBeatmap beatmap, LogoFacadeContainer.Facade facade) + public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Container facade) { this.beatmap = beatmap; this.facade = facade; From 9b047d9b90c112013369959d23fb1703775ac52d Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 28 Mar 2019 12:00:50 +0900 Subject: [PATCH 15/54] Add back menu logo transform --- osu.Game/Screens/Menu/ButtonSystem.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 3fad36cddb..21305c6489 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -295,11 +295,12 @@ namespace osu.Game.Screens.Menu if (lastState == ButtonSystemState.Initial) logo.ScaleTo(0.5f, 200, Easing.In); + logoFacadeContainer.SetLogo(logo, 0.5f, lastState == ButtonSystemState.EnteringMode ? 0 : 200, Easing.In); + logoFacadeContainer.Tracking = true; + logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => { - logoFacadeContainer.Tracking = true; - if (impact) logo.Impact(); From bfe44eb33d7df500b5031171b928c9320b347473 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 28 Mar 2019 15:40:58 +0900 Subject: [PATCH 16/54] Remove SizeForFlow magic number --- osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs | 7 ++++++- osu.Game/Graphics/Containers/LogoFacadeContainer.cs | 3 ++- osu.Game/Screens/Menu/OsuLogo.cs | 2 +- osu.Game/Screens/Play/PlayerLoader.cs | 3 ++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs index 8be0d25a86..f81e70e7b0 100644 --- a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs @@ -145,7 +145,12 @@ namespace osu.Game.Tests.Visual logoFacadeContainer.Add(logoFacade = logoFacadeContainer.LogoFacade); } - public bool IsLogoTracking => logo.Position == logo.Parent.ToLocalSpace(logoFacadeContainer.LogoFacade.ScreenSpaceDrawQuad.Centre); + private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(logoFacade.ScreenSpaceDrawQuad.Centre); + + /// + /// Check that the logo is tracking the position of the facade, with an acceptable precision lenience. + /// + public bool IsLogoTracking => Math.Abs(logo.Position.X - logoTrackingPosition.X) < 0.001f && Math.Abs(logo.Position.Y - logoTrackingPosition.Y) < 0.001f; public void RemoveFacade() { diff --git a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs index f4599e0039..547af87522 100644 --- a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs +++ b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs @@ -63,7 +63,8 @@ namespace osu.Game.Graphics.Containers if (logo == null || !Tracking) return; - LogoFacade.Size = new Vector2(logo.SizeForFlow * facadeScale); + // Account for the scale of the actual logo container, as SizeForFlow only accounts for the sprite scale. + LogoFacade.Size = new Vector2(logo.SizeForFlow * logo.Scale.X * facadeScale); if (LogoFacade.Parent != null && logo.Position != logoTrackingPosition) { diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index af697d37bd..c54ccd21b5 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -54,7 +54,7 @@ namespace osu.Game.Screens.Menu /// public Func Action; - public float SizeForFlow => logo == null ? 0 : logo.DrawSize.X * logo.Scale.X * logoBounceContainer.Scale.X * logoHoverContainer.Scale.X * 0.74f; + public float SizeForFlow => logo == null ? 0 : logo.DrawSize.X * logo.Scale.X * logoBounceContainer.Scale.X * logoHoverContainer.Scale.X; private readonly Sprite ripple; diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 72fbb378a4..5a8c3846fa 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -156,7 +156,7 @@ namespace osu.Game.Screens.Play logo.MoveTo(new Vector2(0.5f), duration, Easing.In); logo.FadeIn(350); - content.SetLogo(logo, 0.3f, 500, Easing.InOutExpo); + content.SetLogo(logo, 1.0f, 500, Easing.InOutExpo); Scheduler.AddDelayed(() => content.Tracking = true, resuming ? 0 : 500); } @@ -365,6 +365,7 @@ namespace osu.Game.Screens.Play Font = OsuFont.GetFont(size: 36, italics: true), Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, + Margin = new MarginPadding { Top = 15 }, }, new OsuSpriteText { From 039e451ab1b4eee334c937a9bcaf3320118e1f48 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 28 Mar 2019 16:09:42 +0900 Subject: [PATCH 17/54] ensure logo is where it already needs to be on resume --- osu.Game/Screens/Play/PlayerLoader.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 5a8c3846fa..da5abbae95 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -152,8 +152,12 @@ namespace osu.Game.Screens.Play const double duration = 300; + if (!resuming) + { + logo.MoveTo(new Vector2(0.5f), duration, Easing.In); + } + logo.ScaleTo(new Vector2(0.15f), duration, Easing.In); - logo.MoveTo(new Vector2(0.5f), duration, Easing.In); logo.FadeIn(350); content.SetLogo(logo, 1.0f, 500, Easing.InOutExpo); From 9d66a5e4b20841ed8d6222a71e5767a4fe7c6eaa Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 28 Mar 2019 16:29:35 +0900 Subject: [PATCH 18/54] Ensure logo stops tracking before suspend animation --- osu.Game/Screens/Play/PlayerLoader.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index da5abbae95..53a349f595 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -129,6 +129,9 @@ namespace osu.Game.Screens.Play private void contentOut() { + // Ensure the logo is no longer tracking before we scale the content. + content.Tracking = false; + content.ScaleTo(0.7f, 300, Easing.InQuint); content.FadeOut(250); } From f066bd11384b56ea55afb7a0439b9a6fc8de12fd Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 28 Mar 2019 16:35:15 +0900 Subject: [PATCH 19/54] Adjust facade scale now that the size is different --- osu.Game/Screens/Menu/ButtonSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 21305c6489..19b460250f 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -59,7 +59,7 @@ namespace osu.Game.Screens.Menu if (this.logo != null) { this.logo.Action = onOsuLogo; - logoFacadeContainer.SetLogo(logo, 0.5f); + logoFacadeContainer.SetLogo(logo, 0.74f); // osuLogo.SizeForFlow relies on loading to be complete. buttonArea.Flow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + this.logo.SizeForFlow / 4), 0); @@ -295,7 +295,7 @@ namespace osu.Game.Screens.Menu if (lastState == ButtonSystemState.Initial) logo.ScaleTo(0.5f, 200, Easing.In); - logoFacadeContainer.SetLogo(logo, 0.5f, lastState == ButtonSystemState.EnteringMode ? 0 : 200, Easing.In); + logoFacadeContainer.SetLogo(logo, 0.74f, lastState == ButtonSystemState.EnteringMode ? 0 : 200, Easing.In); logoFacadeContainer.Tracking = true; logoDelayedAction?.Cancel(); From 352b4b20d917d34d2d8f9ec4b34e9b9323f41c46 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 29 Mar 2019 16:28:25 +0900 Subject: [PATCH 20/54] Correct the sizes of TestCaseLogoFacadeContainer --- osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs index f81e70e7b0..adbf22302b 100644 --- a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs @@ -122,7 +122,7 @@ namespace osu.Game.Tests.Visual { Alpha = 0.35f, RelativeSizeAxes = Axes.None, - Size = new Vector2(107), + Size = new Vector2(72), Child = visualBox = new Box { Colour = Color4.Tomato, @@ -133,7 +133,7 @@ namespace osu.Game.Tests.Visual { Alpha = 0.35f, RelativeSizeAxes = Axes.None, - Size = new Vector2(107), + Size = new Vector2(72), Child = transferContainerBox = new Box { Colour = Color4.White, @@ -172,7 +172,7 @@ namespace osu.Game.Tests.Visual this.logo = logo; logo.FadeIn(350); logo.ScaleTo(new Vector2(0.15f), 350, Easing.In); - logoFacadeContainer.SetLogo(logo, 0.3f, 1000, Easing.InOutQuint); + logoFacadeContainer.SetLogo(logo, 1.0f, 1000, Easing.InOutQuint); logoFacadeContainer.Tracking = true; moveLogoFacade(); } From 952a12bb19b118fa129b8aa73551906e8baa8388 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 29 Mar 2019 16:54:34 +0900 Subject: [PATCH 21/54] Return logo relativepositionaxes on content out --- osu.Game/Screens/Play/PlayerLoader.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 53a349f595..9e6f7cf24e 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -37,6 +37,8 @@ namespace osu.Game.Screens.Play private BeatmapMetadataDisplay info; + private OsuLogo logo; + private bool hideOverlays; public override bool HideOverlaysOnEnter => hideOverlays; @@ -129,9 +131,12 @@ namespace osu.Game.Screens.Play private void contentOut() { - // Ensure the logo is no longer tracking before we scale the content. + // Ensure the logo is no longer tracking before we scale the content, and that its RelativePositionAxes have been returned. content.Tracking = false; + if (logo != null) + logo.RelativePositionAxes = Axes.Both; + content.ScaleTo(0.7f, 300, Easing.InQuint); content.FadeOut(250); } @@ -153,6 +158,8 @@ namespace osu.Game.Screens.Play { base.LogoArriving(logo, resuming); + this.logo = logo; + const double duration = 300; if (!resuming) From 2ed945605ec06da3c2ff57493a83c4bc953904b3 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 3 Apr 2019 19:57:22 +0900 Subject: [PATCH 22/54] Fix Axes.None requirement for FacadeContainer --- .../Visual/TestCaseLogoFacadeContainer.cs | 292 +++++++++++------- osu.Game.Tests/Visual/TestCasePositionAxes.cs | 33 ++ .../Containers/LogoFacadeContainer.cs | 21 +- osu.Game/Screens/Menu/ButtonSystem.cs | 2 + osu.Game/Screens/Play/PlayerLoader.cs | 6 +- 5 files changed, 229 insertions(+), 125 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCasePositionAxes.cs diff --git a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs index adbf22302b..b4d7976e4a 100644 --- a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Drawing; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -10,10 +11,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Screens; +using osu.Framework.Testing; using osu.Game.Configuration; using osu.Game.Graphics.Containers; -using osu.Game.Screens; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; using osuTK; @@ -21,7 +21,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual { - public class TestCaseLogoFacadeContainer : ScreenTestCase + public class TestCaseLogoFacadeContainer : OsuTestCase { public override IReadOnlyList RequiredTypes => new[] { @@ -34,23 +34,38 @@ namespace osu.Game.Tests.Visual typeof(MainMenu) }; - [Cached] private OsuLogo logo; private readonly Bindable uiScale = new Bindable(); + private LogoFacadeContainer logoFacadeContainer; + private Container transferContainer; + private Box visualBox; + private Box transferContainerBox; + private Container logoFacade; - public TestCaseLogoFacadeContainer() - { - Add(logo = new OsuLogo()); - } + private bool randomPositions = false; [BackgroundDependencyLoader] private void load(OsuConfigManager config) { + Add(logo = new OsuLogo { Scale = new Vector2(0.15f), RelativePositionAxes = Axes.None }); + config.BindWith(OsuSetting.UIScale, uiScale); AddSliderStep("Adjust scale", 0.8f, 1.5f, 1f, v => uiScale.Value = v); } + [SetUpSteps] + public void SetUpSteps() + { + AddStep("Clear facades", () => + { + Clear(); + Add(logo = new OsuLogo { Scale = new Vector2(0.15f), RelativePositionAxes = Axes.None }); + logoFacadeContainer = null; + transferContainer = null; + }); + } + /// /// Move the facade to 0,0, then move it to a random new location while the logo is still transforming to it. /// Check if the logo is still tracking the facade. @@ -58,13 +73,11 @@ namespace osu.Game.Tests.Visual [Test] public void MoveFacadeTest() { - TestScreen screen = null; - bool randomPositions = false; AddToggleStep("Toggle move continuously", b => randomPositions = b); - AddStep("Move facade to random position", () => LoadScreen(screen = new TestScreen(randomPositions))); - AddUntilStep("Screen is current", () => screen.IsCurrentScreen()); + AddStep("Add facade containers", addFacadeContainers); + AddStep("Move facade to random position", StartTrackingRandom); waitForMove(); - AddAssert("Logo is tracking", () => screen.IsLogoTracking); + AddAssert("Logo is tracking", () => IsLogoTracking); } /// @@ -73,12 +86,11 @@ namespace osu.Game.Tests.Visual [Test] public void RemoveFacadeTest() { - TestScreen screen = null; - AddStep("Move facade to random position", () => LoadScreen(screen = new TestScreen())); - AddUntilStep("Screen is current", () => screen.IsCurrentScreen()); - AddStep("Remove facade from FacadeContainer", () => screen.RemoveFacade()); + AddStep("Add facade containers", addFacadeContainers); + AddStep("Move facade to random position", StartTrackingRandom); + AddStep("Remove facade from FacadeContainer", RemoveFacade); waitForMove(); - AddAssert("Logo is not tracking", () => !screen.IsLogoTracking); + AddAssert("Logo is not tracking", () => !IsLogoTracking); } /// @@ -87,114 +99,162 @@ namespace osu.Game.Tests.Visual [Test] public void TransferFacadeTest() { - TestScreen screen = null; - AddStep("Move facade to random position", () => LoadScreen(screen = new TestScreen())); - AddUntilStep("Screen is current", () => screen.IsCurrentScreen()); - AddStep("Remove facade from FacadeContainer", () => screen.RemoveFacade()); - AddStep("Transfer facade to a new container", () => screen.TransferFacade()); + AddStep("Add facade containers", addFacadeContainers); + AddStep("Move facade to random position", StartTrackingRandom); + AddStep("Remove facade from FacadeContainer", RemoveFacade); + AddStep("Transfer facade to a new container", TransferFacade); waitForMove(); - AddAssert("Logo is tracking", () => screen.IsLogoTracking); + AddAssert("Logo is tracking", () => IsLogoTracking); + } + + /// + /// Add a facade to a flow container then move logo to facade. + /// + [Test] + public void FlowContainerTest() + { + FillFlowContainer flowContainer; + + AddStep("Create new Logo Facade Container", () => + { + Add(logoFacadeContainer = new LogoFacadeContainer + { + AutoSizeAxes = Axes.Both, + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Child = flowContainer = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Direction = FillDirection.Vertical, + } + }); + flowContainer.Children = new Drawable[] + { + new Box + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Colour = Color4.Azure, + Size = new Vector2(70) + }, + new Container + { + Alpha = 0.35f, + RelativeSizeAxes = Axes.None, + Size = new Vector2(72), + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Children = new Drawable[] + { + visualBox = new Box + { + Colour = Color4.White, + RelativeSizeAxes = Axes.Both, + }, + logoFacadeContainer.LogoFacade, + } + }, + new Box + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Colour = Color4.Azure, + Size = new Vector2(70) + }, + }; + }); + + AddStep("Perform logo movements", () => + { + logoFacadeContainer.Tracking = false; + logo.RelativePositionAxes = Axes.Both; + logo.MoveTo(new Vector2(0.5f), 500, Easing.InOutExpo); + logoFacadeContainer.SetLogo(logo, 1.0f, 1000, Easing.InOutExpo); + visualBox.Colour = Color4.White; + + Scheduler.AddDelayed(() => + { + logoFacadeContainer.Tracking = true; + //logo.RelativePositionAxes = Axes.None; + visualBox.Colour = Color4.Tomato; + }, 700); + }); + } + + private void addFacadeContainers() + { + AddRange(new Drawable[] + { + logoFacadeContainer = new LogoFacadeContainer + { + Alpha = 0.35f, + RelativeSizeAxes = Axes.None, + Size = new Vector2(72), + Child = visualBox = new Box + { + Colour = Color4.Tomato, + RelativeSizeAxes = Axes.Both, + } + }, + transferContainer = new Container + { + Alpha = 0.35f, + RelativeSizeAxes = Axes.None, + Size = new Vector2(72), + Child = transferContainerBox = new Box + { + Colour = Color4.White, + RelativeSizeAxes = Axes.Both, + } + }, + }); + + logoFacadeContainer.Add(logoFacade = logoFacadeContainer.LogoFacade); + logoFacadeContainer.SetLogo(logo, 1.0f, 1000); } private void waitForMove() => AddWaitStep("Wait for transforms to finish", 5); - private class TestScreen : OsuScreen + private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(logoFacade.ScreenSpaceDrawQuad.Centre); + + /// + /// Check that the logo is tracking the position of the facade, with an acceptable precision lenience. + /// + public bool IsLogoTracking => Math.Abs(logo.Position.X - logoTrackingPosition.X) < 0.001f && Math.Abs(logo.Position.Y - logoTrackingPosition.Y) < 0.001f; + + public void RemoveFacade() { - private LogoFacadeContainer logoFacadeContainer; - private Container transferContainer; - private Container logoFacade; - private readonly bool randomPositions; - private OsuLogo logo; - private Box visualBox; - private Box transferContainerBox; + logoFacadeContainer.Remove(logoFacade); + visualBox.Colour = Color4.White; + moveLogoFacade(); + } - public TestScreen(bool randomPositions = false) + public void TransferFacade() + { + transferContainer.Add(logoFacade); + transferContainerBox.Colour = Color4.Tomato; + moveLogoFacade(); + } + + public void StartTrackingRandom() + { + logoFacadeContainer.Tracking = true; + moveLogoFacade(); + } + + private void moveLogoFacade() + { + Random random = new Random(); + if (logoFacade.Transforms.Count == 0 && transferContainer.Transforms.Count == 0) { - this.randomPositions = randomPositions; + logoFacadeContainer.Delay(500).MoveTo(new Vector2(random.Next(0, (int)logo.Parent.DrawWidth), random.Next(0, (int)logo.Parent.DrawHeight)), 300); + transferContainer.Delay(500).MoveTo(new Vector2(random.Next(0, (int)logo.Parent.DrawWidth), random.Next(0, (int)logo.Parent.DrawHeight)), 300); } - [BackgroundDependencyLoader] - private void load() - { - InternalChildren = new Drawable[] - { - logoFacadeContainer = new LogoFacadeContainer - { - Alpha = 0.35f, - RelativeSizeAxes = Axes.None, - Size = new Vector2(72), - Child = visualBox = new Box - { - Colour = Color4.Tomato, - RelativeSizeAxes = Axes.Both, - } - }, - transferContainer = new Container - { - Alpha = 0.35f, - RelativeSizeAxes = Axes.None, - Size = new Vector2(72), - Child = transferContainerBox = new Box - { - Colour = Color4.White, - RelativeSizeAxes = Axes.Both, - } - }, - }; - - logoFacadeContainer.Add(logoFacade = logoFacadeContainer.LogoFacade); - } - - private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(logoFacade.ScreenSpaceDrawQuad.Centre); - - /// - /// Check that the logo is tracking the position of the facade, with an acceptable precision lenience. - /// - public bool IsLogoTracking => Math.Abs(logo.Position.X - logoTrackingPosition.X) < 0.001f && Math.Abs(logo.Position.Y - logoTrackingPosition.Y) < 0.001f; - - public void RemoveFacade() - { - logoFacadeContainer.Remove(logoFacade); - visualBox.Colour = Color4.White; - moveLogoFacade(); - } - - public void TransferFacade() - { - transferContainer.Add(logoFacade); - transferContainerBox.Colour = Color4.Tomato; - moveLogoFacade(); - } - - protected override void LogoArriving(OsuLogo logo, bool resuming) - { - base.LogoArriving(logo, resuming); - this.logo = logo; - logo.FadeIn(350); - logo.ScaleTo(new Vector2(0.15f), 350, Easing.In); - logoFacadeContainer.SetLogo(logo, 1.0f, 1000, Easing.InOutQuint); - logoFacadeContainer.Tracking = true; - moveLogoFacade(); - } - - protected override void LogoExiting(OsuLogo logo) - { - base.LogoExiting(logo); - logoFacadeContainer.Tracking = false; - } - - private void moveLogoFacade() - { - Random random = new Random(); - if (logoFacade.Transforms.Count == 0 && transferContainer.Transforms.Count == 0) - { - logoFacadeContainer.Delay(500).MoveTo(new Vector2(random.Next(0, (int)DrawWidth), random.Next(0, (int)DrawHeight)), 300); - transferContainer.Delay(500).MoveTo(new Vector2(random.Next(0, (int)DrawWidth), random.Next(0, (int)DrawHeight)), 300); - } - - if (randomPositions) - Schedule(moveLogoFacade); - } + if (randomPositions) + Schedule(moveLogoFacade); } } } diff --git a/osu.Game.Tests/Visual/TestCasePositionAxes.cs b/osu.Game.Tests/Visual/TestCasePositionAxes.cs new file mode 100644 index 0000000000..04ff0dcf8c --- /dev/null +++ b/osu.Game.Tests/Visual/TestCasePositionAxes.cs @@ -0,0 +1,33 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; +using osuTK; + +namespace osu.Game.Tests.Visual +{ + public class TestCasePositionAxes : OsuTestCase + { + private Box box; + + public TestCasePositionAxes() + { + Add(new Container() + { + Size = new Vector2(1), + Child = box = new Box + { + Size = new Vector2(25), + RelativePositionAxes = Axes.None, + Position = new Vector2(250) + } + }); + + AddStep("blank", () => { }); + AddStep("change axes", () => box.RelativePositionAxes = Axes.Both); + } + } +} diff --git a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs index 547af87522..c9f41e75e7 100644 --- a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs +++ b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs @@ -43,7 +43,7 @@ namespace osu.Game.Graphics.Containers /// The scale of the facade. Does not actually affect the logo itself. /// The duration of the initial transform. Default is instant. /// The easing type of the initial transform. - public void SetLogo(OsuLogo logo, float facadeScale, double duration = 0, Easing easing = Easing.None) + public void SetLogo(OsuLogo logo, float facadeScale = 1.0f, double duration = 0, Easing easing = Easing.None) { this.logo = logo ?? throw new ArgumentNullException(nameof(logo)); this.facadeScale = facadeScale; @@ -54,11 +54,19 @@ namespace osu.Game.Graphics.Containers startPosition = null; } - private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre); - - protected override void UpdateAfterChildren() + private Vector2 localSpaceConversion() { - base.UpdateAfterChildren(); + Vector2 local; + local.X = logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre).X / logo.Parent.RelativeToAbsoluteFactor.X; + local.Y = logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre).Y / logo.Parent.RelativeToAbsoluteFactor.Y; + return local; + } + + private Vector2 logoTrackingPosition => logo.RelativePositionAxes == Axes.None ? logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre) : localSpaceConversion(); + + protected override void Update() + { + base.Update(); if (logo == null || !Tracking) return; @@ -68,9 +76,6 @@ namespace osu.Game.Graphics.Containers if (LogoFacade.Parent != null && logo.Position != logoTrackingPosition) { - // Required for the correct position of the logo to be set with respect to logoTrackingPosition - logo.RelativePositionAxes = Axes.None; - // If this is our first update since tracking has started, initialize our starting values for interpolation if (startTime == null || startPosition == null) { diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index f13dadf3dd..607700649d 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -290,6 +290,7 @@ namespace osu.Game.Screens.Menu break; case ButtonSystemState.Initial: logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.None; bool impact = logo.Scale.X > 0.6f; @@ -310,6 +311,7 @@ namespace osu.Game.Screens.Menu break; default: logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.None; logoFacadeContainer.Tracking = true; logo.ScaleTo(0.5f, 200, Easing.OutQuint); break; diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 9e6f7cf24e..19607129a0 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -172,7 +172,11 @@ namespace osu.Game.Screens.Play content.SetLogo(logo, 1.0f, 500, Easing.InOutExpo); - Scheduler.AddDelayed(() => content.Tracking = true, resuming ? 0 : 500); + Scheduler.AddDelayed(() => + { + content.Tracking = true; + //logo.RelativePositionAxes = Axes.None; + }, resuming ? 0 : 500); } protected override void LogoExiting(OsuLogo logo) From 8a40b27e8fc3cf9b17069439e8af130a72d7564e Mon Sep 17 00:00:00 2001 From: David Zhao Date: Wed, 3 Apr 2019 20:32:53 +0900 Subject: [PATCH 23/54] Remove need for logo relativePositionAxes none --- osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs | 1 - osu.Game/Graphics/Containers/LogoFacadeContainer.cs | 10 ++++------ osu.Game/Screens/Menu/ButtonSystem.cs | 2 -- osu.Game/Screens/Play/PlayerLoader.cs | 1 - 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs index b4d7976e4a..bd1fb932bb 100644 --- a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs @@ -177,7 +177,6 @@ namespace osu.Game.Tests.Visual Scheduler.AddDelayed(() => { logoFacadeContainer.Tracking = true; - //logo.RelativePositionAxes = Axes.None; visualBox.Colour = Color4.Tomato; }, 700); }); diff --git a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs index c9f41e75e7..76903a20b3 100644 --- a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs +++ b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs @@ -54,7 +54,7 @@ namespace osu.Game.Graphics.Containers startPosition = null; } - private Vector2 localSpaceConversion() + private Vector2 logoTrackingPosition() { Vector2 local; local.X = logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre).X / logo.Parent.RelativeToAbsoluteFactor.X; @@ -62,8 +62,6 @@ namespace osu.Game.Graphics.Containers return local; } - private Vector2 logoTrackingPosition => logo.RelativePositionAxes == Axes.None ? logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre) : localSpaceConversion(); - protected override void Update() { base.Update(); @@ -74,7 +72,7 @@ namespace osu.Game.Graphics.Containers // Account for the scale of the actual logo container, as SizeForFlow only accounts for the sprite scale. LogoFacade.Size = new Vector2(logo.SizeForFlow * logo.Scale.X * facadeScale); - if (LogoFacade.Parent != null && logo.Position != logoTrackingPosition) + if (LogoFacade.Parent != null && logo.Position != logoTrackingPosition()) { // If this is our first update since tracking has started, initialize our starting values for interpolation if (startTime == null || startPosition == null) @@ -90,11 +88,11 @@ namespace osu.Game.Graphics.Containers var mount = (float)Interpolation.ApplyEasing(easing, Math.Min(elapsedDuration / duration, 1)); // Interpolate the position of the logo, where mount 0 is where the logo was when it first began interpolating, and mount 1 is the target location. - logo.Position = Vector2.Lerp(startPosition ?? throw new ArgumentNullException(nameof(startPosition)), logoTrackingPosition, mount); + logo.Position = Vector2.Lerp(startPosition ?? throw new ArgumentNullException(nameof(startPosition)), logoTrackingPosition(), mount); } else { - logo.Position = logoTrackingPosition; + logo.Position = logoTrackingPosition(); } } } diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 607700649d..f13dadf3dd 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -290,7 +290,6 @@ namespace osu.Game.Screens.Menu break; case ButtonSystemState.Initial: logo.ClearTransforms(targetMember: nameof(Position)); - logo.RelativePositionAxes = Axes.None; bool impact = logo.Scale.X > 0.6f; @@ -311,7 +310,6 @@ namespace osu.Game.Screens.Menu break; default: logo.ClearTransforms(targetMember: nameof(Position)); - logo.RelativePositionAxes = Axes.None; logoFacadeContainer.Tracking = true; logo.ScaleTo(0.5f, 200, Easing.OutQuint); break; diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 19607129a0..2ba5bd81d1 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -175,7 +175,6 @@ namespace osu.Game.Screens.Play Scheduler.AddDelayed(() => { content.Tracking = true; - //logo.RelativePositionAxes = Axes.None; }, resuming ? 0 : 500); } From 6b5458a625840759eb178278a88f423532359081 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 4 Apr 2019 11:22:05 +0900 Subject: [PATCH 24/54] Clean up test cases --- .../Visual/TestCaseLogoFacadeContainer.cs | 92 +++++++++---------- osu.Game.Tests/Visual/TestCasePositionAxes.cs | 33 ------- .../Containers/LogoFacadeContainer.cs | 23 ++--- 3 files changed, 57 insertions(+), 91 deletions(-) delete mode 100644 osu.Game.Tests/Visual/TestCasePositionAxes.cs diff --git a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs index bd1fb932bb..d66ac19aed 100644 --- a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Drawing; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -35,21 +34,18 @@ namespace osu.Game.Tests.Visual }; private OsuLogo logo; - private readonly Bindable uiScale = new Bindable(); - private LogoFacadeContainer logoFacadeContainer; + private TestLogoFacadeContainer facadeContainer; private Container transferContainer; private Box visualBox; private Box transferContainerBox; private Container logoFacade; - private bool randomPositions = false; + private bool randomPositions; [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - Add(logo = new OsuLogo { Scale = new Vector2(0.15f), RelativePositionAxes = Axes.None }); - config.BindWith(OsuSetting.UIScale, uiScale); AddSliderStep("Adjust scale", 0.8f, 1.5f, 1f, v => uiScale.Value = v); } @@ -60,8 +56,8 @@ namespace osu.Game.Tests.Visual AddStep("Clear facades", () => { Clear(); - Add(logo = new OsuLogo { Scale = new Vector2(0.15f), RelativePositionAxes = Axes.None }); - logoFacadeContainer = null; + Add(logo = new OsuLogo { Scale = new Vector2(0.15f), RelativePositionAxes = Axes.Both }); + facadeContainer = null; transferContainer = null; }); } @@ -75,9 +71,9 @@ namespace osu.Game.Tests.Visual { AddToggleStep("Toggle move continuously", b => randomPositions = b); AddStep("Add facade containers", addFacadeContainers); - AddStep("Move facade to random position", StartTrackingRandom); + AddStep("Move facade to random position", startTrackingRandom); waitForMove(); - AddAssert("Logo is tracking", () => IsLogoTracking); + AddAssert("Logo is tracking", () => facadeContainer.IsLogoTracking); } /// @@ -87,10 +83,10 @@ namespace osu.Game.Tests.Visual public void RemoveFacadeTest() { AddStep("Add facade containers", addFacadeContainers); - AddStep("Move facade to random position", StartTrackingRandom); - AddStep("Remove facade from FacadeContainer", RemoveFacade); + AddStep("Move facade to random position", startTrackingRandom); + AddStep("Remove facade from FacadeContainer", removeFacade); waitForMove(); - AddAssert("Logo is not tracking", () => !IsLogoTracking); + AddAssert("Logo is not tracking", () => !facadeContainer.IsLogoTracking); } /// @@ -100,11 +96,16 @@ namespace osu.Game.Tests.Visual public void TransferFacadeTest() { AddStep("Add facade containers", addFacadeContainers); - AddStep("Move facade to random position", StartTrackingRandom); - AddStep("Remove facade from FacadeContainer", RemoveFacade); - AddStep("Transfer facade to a new container", TransferFacade); + AddStep("Move facade to random position", startTrackingRandom); + AddStep("Remove facade from FacadeContainer", removeFacade); + AddStep("Transfer facade to a new container", () => + { + transferContainer.Add(logoFacade); + transferContainerBox.Colour = Color4.Tomato; + moveLogoFacade(); + }); waitForMove(); - AddAssert("Logo is tracking", () => IsLogoTracking); + AddAssert("Logo is tracking", () => facadeContainer.IsLogoTracking); } /// @@ -115,9 +116,9 @@ namespace osu.Game.Tests.Visual { FillFlowContainer flowContainer; - AddStep("Create new Logo Facade Container", () => + AddStep("Create new flow container with facade", () => { - Add(logoFacadeContainer = new LogoFacadeContainer + Add(facadeContainer = new TestLogoFacadeContainer { AutoSizeAxes = Axes.Both, Origin = Anchor.TopCentre, @@ -153,7 +154,7 @@ namespace osu.Game.Tests.Visual Colour = Color4.White, RelativeSizeAxes = Axes.Both, }, - logoFacadeContainer.LogoFacade, + facadeContainer.LogoFacade, } }, new Box @@ -168,25 +169,28 @@ namespace osu.Game.Tests.Visual AddStep("Perform logo movements", () => { - logoFacadeContainer.Tracking = false; + facadeContainer.Tracking = false; logo.RelativePositionAxes = Axes.Both; logo.MoveTo(new Vector2(0.5f), 500, Easing.InOutExpo); - logoFacadeContainer.SetLogo(logo, 1.0f, 1000, Easing.InOutExpo); + facadeContainer.SetLogo(logo, 1.0f, 1000, Easing.InOutExpo); visualBox.Colour = Color4.White; Scheduler.AddDelayed(() => { - logoFacadeContainer.Tracking = true; + facadeContainer.Tracking = true; visualBox.Colour = Color4.Tomato; }, 700); }); + + waitForMove(); + AddAssert("Logo is tracking", () => facadeContainer.IsLogoTracking); } private void addFacadeContainers() { AddRange(new Drawable[] { - logoFacadeContainer = new LogoFacadeContainer + facadeContainer = new TestLogoFacadeContainer { Alpha = 0.35f, RelativeSizeAxes = Axes.None, @@ -210,50 +214,44 @@ namespace osu.Game.Tests.Visual }, }); - logoFacadeContainer.Add(logoFacade = logoFacadeContainer.LogoFacade); - logoFacadeContainer.SetLogo(logo, 1.0f, 1000); + facadeContainer.Add(logoFacade = facadeContainer.LogoFacade); + facadeContainer.SetLogo(logo, 1.0f, 1000); } private void waitForMove() => AddWaitStep("Wait for transforms to finish", 5); - private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(logoFacade.ScreenSpaceDrawQuad.Centre); - - /// - /// Check that the logo is tracking the position of the facade, with an acceptable precision lenience. - /// - public bool IsLogoTracking => Math.Abs(logo.Position.X - logoTrackingPosition.X) < 0.001f && Math.Abs(logo.Position.Y - logoTrackingPosition.Y) < 0.001f; - - public void RemoveFacade() + private void removeFacade() { - logoFacadeContainer.Remove(logoFacade); + facadeContainer.Remove(logoFacade); visualBox.Colour = Color4.White; moveLogoFacade(); } - public void TransferFacade() + private void startTrackingRandom() { - transferContainer.Add(logoFacade); - transferContainerBox.Colour = Color4.Tomato; - moveLogoFacade(); - } - - public void StartTrackingRandom() - { - logoFacadeContainer.Tracking = true; + facadeContainer.Tracking = true; moveLogoFacade(); } private void moveLogoFacade() { - Random random = new Random(); - if (logoFacade.Transforms.Count == 0 && transferContainer.Transforms.Count == 0) + if (logoFacade?.Transforms.Count == 0 && transferContainer?.Transforms.Count == 0) { - logoFacadeContainer.Delay(500).MoveTo(new Vector2(random.Next(0, (int)logo.Parent.DrawWidth), random.Next(0, (int)logo.Parent.DrawHeight)), 300); + Random random = new Random(); + facadeContainer.Delay(500).MoveTo(new Vector2(random.Next(0, (int)logo.Parent.DrawWidth), random.Next(0, (int)logo.Parent.DrawHeight)), 300); transferContainer.Delay(500).MoveTo(new Vector2(random.Next(0, (int)logo.Parent.DrawWidth), random.Next(0, (int)logo.Parent.DrawHeight)), 300); } if (randomPositions) Schedule(moveLogoFacade); } + + private class TestLogoFacadeContainer : LogoFacadeContainer + { + /// + /// Check that the logo is tracking the position of the facade, with an acceptable precision lenience. + /// + public bool IsLogoTracking => Math.Abs(Logo.Position.X - LogoTrackingPosition().X) < 0.001f && Math.Abs(Logo.Position.Y - LogoTrackingPosition().Y) < 0.001f; + } } } diff --git a/osu.Game.Tests/Visual/TestCasePositionAxes.cs b/osu.Game.Tests/Visual/TestCasePositionAxes.cs deleted file mode 100644 index 04ff0dcf8c..0000000000 --- a/osu.Game.Tests/Visual/TestCasePositionAxes.cs +++ /dev/null @@ -1,33 +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 osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Testing; -using osuTK; - -namespace osu.Game.Tests.Visual -{ - public class TestCasePositionAxes : OsuTestCase - { - private Box box; - - public TestCasePositionAxes() - { - Add(new Container() - { - Size = new Vector2(1), - Child = box = new Box - { - Size = new Vector2(25), - RelativePositionAxes = Axes.None, - Position = new Vector2(250) - } - }); - - AddStep("blank", () => { }); - AddStep("change axes", () => box.RelativePositionAxes = Axes.Both); - } - } -} diff --git a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs index 76903a20b3..a80b687057 100644 --- a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs +++ b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs @@ -24,7 +24,8 @@ namespace osu.Game.Graphics.Containers /// public bool Tracking = false; - private OsuLogo logo; + protected OsuLogo Logo; + private float facadeScale; private Easing easing; private Vector2? startPosition; @@ -45,7 +46,7 @@ namespace osu.Game.Graphics.Containers /// The easing type of the initial transform. public void SetLogo(OsuLogo logo, float facadeScale = 1.0f, double duration = 0, Easing easing = Easing.None) { - this.logo = logo ?? throw new ArgumentNullException(nameof(logo)); + Logo = logo ?? throw new ArgumentNullException(nameof(logo)); this.facadeScale = facadeScale; this.duration = duration; this.easing = easing; @@ -54,11 +55,11 @@ namespace osu.Game.Graphics.Containers startPosition = null; } - private Vector2 logoTrackingPosition() + protected Vector2 LogoTrackingPosition() { Vector2 local; - local.X = logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre).X / logo.Parent.RelativeToAbsoluteFactor.X; - local.Y = logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre).Y / logo.Parent.RelativeToAbsoluteFactor.Y; + local.X = Logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre).X / Logo.Parent.RelativeToAbsoluteFactor.X; + local.Y = Logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre).Y / Logo.Parent.RelativeToAbsoluteFactor.Y; return local; } @@ -66,19 +67,19 @@ namespace osu.Game.Graphics.Containers { base.Update(); - if (logo == null || !Tracking) + if (Logo == null || !Tracking) return; // Account for the scale of the actual logo container, as SizeForFlow only accounts for the sprite scale. - LogoFacade.Size = new Vector2(logo.SizeForFlow * logo.Scale.X * facadeScale); + LogoFacade.Size = new Vector2(Logo.SizeForFlow * Logo.Scale.X * facadeScale); - if (LogoFacade.Parent != null && logo.Position != logoTrackingPosition()) + if (LogoFacade.Parent != null && Logo.Position != LogoTrackingPosition()) { // If this is our first update since tracking has started, initialize our starting values for interpolation if (startTime == null || startPosition == null) { startTime = Time.Current; - startPosition = logo.Position; + startPosition = Logo.Position; } if (duration != 0) @@ -88,11 +89,11 @@ namespace osu.Game.Graphics.Containers var mount = (float)Interpolation.ApplyEasing(easing, Math.Min(elapsedDuration / duration, 1)); // Interpolate the position of the logo, where mount 0 is where the logo was when it first began interpolating, and mount 1 is the target location. - logo.Position = Vector2.Lerp(startPosition ?? throw new ArgumentNullException(nameof(startPosition)), logoTrackingPosition(), mount); + Logo.Position = Vector2.Lerp(startPosition ?? throw new ArgumentNullException(nameof(startPosition)), LogoTrackingPosition(), mount); } else { - logo.Position = logoTrackingPosition(); + Logo.Position = LogoTrackingPosition(); } } } From 15b2b6af7d8c8da6c371b14ff4c571b1c284d423 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 4 Apr 2019 11:28:36 +0900 Subject: [PATCH 25/54] Clean up remaining assignments of logo relativePositionAxes --- osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs | 1 - osu.Game/Screens/Menu/ButtonSystem.cs | 2 -- osu.Game/Screens/Play/PlayerLoader.cs | 5 +---- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs index d66ac19aed..3e9d52483d 100644 --- a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs @@ -170,7 +170,6 @@ namespace osu.Game.Tests.Visual AddStep("Perform logo movements", () => { facadeContainer.Tracking = false; - logo.RelativePositionAxes = Axes.Both; logo.MoveTo(new Vector2(0.5f), 500, Easing.InOutExpo); facadeContainer.SetLogo(logo, 1.0f, 1000, Easing.InOutExpo); visualBox.Colour = Color4.White; diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index f13dadf3dd..cb95ec1765 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -276,8 +276,6 @@ namespace osu.Game.Screens.Menu game?.Toolbar.Hide(); logo.ClearTransforms(targetMember: nameof(Position)); - logo.RelativePositionAxes = Axes.Both; - logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); logo.ScaleTo(1, 800, Easing.OutExpo); }, buttonArea.Alpha * 150); diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 2ba5bd81d1..ba27f87ee6 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -131,12 +131,9 @@ namespace osu.Game.Screens.Play private void contentOut() { - // Ensure the logo is no longer tracking before we scale the content, and that its RelativePositionAxes have been returned. + // Ensure the logo is no longer tracking before we scale the content content.Tracking = false; - if (logo != null) - logo.RelativePositionAxes = Axes.Both; - content.ScaleTo(0.7f, 300, Easing.InQuint); content.FadeOut(250); } From e89143d76b94610bf88c3a733e64e340f97713e5 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 4 Apr 2019 12:07:11 +0900 Subject: [PATCH 26/54] Add xmldoc for LogoTrackingPosition --- osu.Game/Graphics/Containers/LogoFacadeContainer.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs index a80b687057..1664fdde4d 100644 --- a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs +++ b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs @@ -55,6 +55,12 @@ namespace osu.Game.Graphics.Containers startPosition = null; } + /// + /// Gets the position that the logo should move to with respect to the . + /// Manually performs a conversion of the Facade's position to the relative position of the Logo's Parent. + /// + /// Will only be correct if the logo's are set to Axes.Both + /// The position that the logo should move to in its parent's relative space. protected Vector2 LogoTrackingPosition() { Vector2 local; From b2857384b8f3c83be474b17cca9c7cc90342cf4e Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 4 Apr 2019 12:08:05 +0900 Subject: [PATCH 27/54] Remove unnecessary logo assignment --- osu.Game/Screens/Play/PlayerLoader.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index ba27f87ee6..ccfd965f53 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -37,8 +37,6 @@ namespace osu.Game.Screens.Play private BeatmapMetadataDisplay info; - private OsuLogo logo; - private bool hideOverlays; public override bool HideOverlaysOnEnter => hideOverlays; @@ -155,8 +153,6 @@ namespace osu.Game.Screens.Play { base.LogoArriving(logo, resuming); - this.logo = logo; - const double duration = 300; if (!resuming) From f2bbde83bf3788957ffb3ad7b7e35b1f2e4c9e6d Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 4 Apr 2019 13:05:34 +0900 Subject: [PATCH 28/54] Use precision almost equals --- .../{ => UserInterface}/TestCaseLogoFacadeContainer.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) rename osu.Game.Tests/Visual/{ => UserInterface}/TestCaseLogoFacadeContainer.cs (97%) diff --git a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoFacadeContainer.cs similarity index 97% rename from osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs rename to osu.Game.Tests/Visual/UserInterface/TestCaseLogoFacadeContainer.cs index 3e9d52483d..4bc4ae724a 100644 --- a/osu.Game.Tests/Visual/TestCaseLogoFacadeContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoFacadeContainer.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; +using osu.Framework.MathUtils; using osu.Framework.Testing; using osu.Game.Configuration; using osu.Game.Graphics.Containers; @@ -18,7 +19,7 @@ using osu.Game.Screens.Play; using osuTK; using osuTK.Graphics; -namespace osu.Game.Tests.Visual +namespace osu.Game.Tests.Visual.UserInterface { public class TestCaseLogoFacadeContainer : OsuTestCase { @@ -250,7 +251,7 @@ namespace osu.Game.Tests.Visual /// /// Check that the logo is tracking the position of the facade, with an acceptable precision lenience. /// - public bool IsLogoTracking => Math.Abs(Logo.Position.X - LogoTrackingPosition().X) < 0.001f && Math.Abs(Logo.Position.Y - LogoTrackingPosition().Y) < 0.001f; + public bool IsLogoTracking => Precision.AlmostEquals(Logo.Position, LogoTrackingPosition()); } } } From b2e932dc74c5eae1184172758b3a62789d23e719 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 4 Apr 2019 13:13:03 +0900 Subject: [PATCH 29/54] Clean up tests, xmldoc --- .../UserInterface/TestCaseLogoFacadeContainer.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoFacadeContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoFacadeContainer.cs index 4bc4ae724a..5f864eeabb 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoFacadeContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoFacadeContainer.cs @@ -41,9 +41,10 @@ namespace osu.Game.Tests.Visual.UserInterface private Box visualBox; private Box transferContainerBox; private Container logoFacade; - private bool randomPositions; + private const float visual_box_size = 72; + [BackgroundDependencyLoader] private void load(OsuConfigManager config) { @@ -110,7 +111,7 @@ namespace osu.Game.Tests.Visual.UserInterface } /// - /// Add a facade to a flow container then move logo to facade. + /// Add a facade to a flow container, move the logo to the center of the screen, then start tracking on the facade. /// [Test] public void FlowContainerTest() @@ -139,13 +140,13 @@ namespace osu.Game.Tests.Visual.UserInterface Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, Colour = Color4.Azure, - Size = new Vector2(70) + Size = new Vector2(visual_box_size) }, new Container { Alpha = 0.35f, RelativeSizeAxes = Axes.None, - Size = new Vector2(72), + Size = new Vector2(visual_box_size), Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, Children = new Drawable[] @@ -163,7 +164,7 @@ namespace osu.Game.Tests.Visual.UserInterface Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, Colour = Color4.Azure, - Size = new Vector2(70) + Size = new Vector2(visual_box_size) }, }; }); @@ -194,7 +195,7 @@ namespace osu.Game.Tests.Visual.UserInterface { Alpha = 0.35f, RelativeSizeAxes = Axes.None, - Size = new Vector2(72), + Size = new Vector2(visual_box_size), Child = visualBox = new Box { Colour = Color4.Tomato, @@ -205,7 +206,7 @@ namespace osu.Game.Tests.Visual.UserInterface { Alpha = 0.35f, RelativeSizeAxes = Axes.None, - Size = new Vector2(72), + Size = new Vector2(visual_box_size), Child = transferContainerBox = new Box { Colour = Color4.White, From 456459cafa91f49981dd085e43312d10e9dc1255 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 4 Apr 2019 13:25:24 +0900 Subject: [PATCH 30/54] Give flow container test long enough to finish --- .../Visual/UserInterface/TestCaseLogoFacadeContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoFacadeContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoFacadeContainer.cs index 5f864eeabb..0b664a310a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoFacadeContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoFacadeContainer.cs @@ -183,7 +183,7 @@ namespace osu.Game.Tests.Visual.UserInterface }, 700); }); - waitForMove(); + waitForMove(8); AddAssert("Logo is tracking", () => facadeContainer.IsLogoTracking); } @@ -219,7 +219,7 @@ namespace osu.Game.Tests.Visual.UserInterface facadeContainer.SetLogo(logo, 1.0f, 1000); } - private void waitForMove() => AddWaitStep("Wait for transforms to finish", 5); + private void waitForMove(int count = 5) => AddWaitStep("Wait for transforms to finish", count); private void removeFacade() { From 6f5e9fe50d3976de9c1d686bce6e14c75ada64f8 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Thu, 4 Apr 2019 13:33:13 +0900 Subject: [PATCH 31/54] Correct xmldoc --- osu.Game/Graphics/Containers/LogoFacadeContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs index 1664fdde4d..c37588cb55 100644 --- a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs +++ b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs @@ -57,7 +57,7 @@ namespace osu.Game.Graphics.Containers /// /// Gets the position that the logo should move to with respect to the . - /// Manually performs a conversion of the Facade's position to the relative position of the Logo's Parent. + /// Manually performs a conversion of the Facade's position to the Logo's parent's relative space. /// /// Will only be correct if the logo's are set to Axes.Both /// The position that the logo should move to in its parent's relative space. From 7047f305a1a7af92532d8902e4490f96119d23a9 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 5 Apr 2019 12:02:47 +0900 Subject: [PATCH 32/54] Apply reviews, add safety for multiple facades --- ...er.cs => TestCaseLogoTrackingContainer.cs} | 71 ++++---- .../Containers/LogoFacadeContainer.cs | 114 ------------- .../Containers/LogoTrackingContainer.cs | 156 ++++++++++++++++++ osu.Game/Screens/Menu/ButtonSystem.cs | 24 +-- osu.Game/Screens/Menu/OsuLogo.cs | 6 + osu.Game/Screens/Play/PlayerLoader.cs | 23 +-- 6 files changed, 223 insertions(+), 171 deletions(-) rename osu.Game.Tests/Visual/UserInterface/{TestCaseLogoFacadeContainer.cs => TestCaseLogoTrackingContainer.cs} (77%) delete mode 100644 osu.Game/Graphics/Containers/LogoFacadeContainer.cs create mode 100644 osu.Game/Graphics/Containers/LogoTrackingContainer.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoFacadeContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs similarity index 77% rename from osu.Game.Tests/Visual/UserInterface/TestCaseLogoFacadeContainer.cs rename to osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs index 0b664a310a..4d255eb25a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoFacadeContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs @@ -21,13 +21,13 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestCaseLogoFacadeContainer : OsuTestCase + public class TestCaseLogoTrackingContainer : OsuTestCase { public override IReadOnlyList RequiredTypes => new[] { typeof(PlayerLoader), typeof(Player), - typeof(LogoFacadeContainer), + typeof(LogoTrackingContainer), typeof(ButtonSystem), typeof(ButtonSystemState), typeof(Menu), @@ -36,11 +36,11 @@ namespace osu.Game.Tests.Visual.UserInterface private OsuLogo logo; private readonly Bindable uiScale = new Bindable(); - private TestLogoFacadeContainer facadeContainer; + private TestLogoTrackingContainer trackingContainer; private Container transferContainer; private Box visualBox; private Box transferContainerBox; - private Container logoFacade; + private Drawable logoFacade; private bool randomPositions; private const float visual_box_size = 72; @@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.UserInterface { Clear(); Add(logo = new OsuLogo { Scale = new Vector2(0.15f), RelativePositionAxes = Axes.Both }); - facadeContainer = null; + trackingContainer = null; transferContainer = null; }); } @@ -72,10 +72,10 @@ namespace osu.Game.Tests.Visual.UserInterface public void MoveFacadeTest() { AddToggleStep("Toggle move continuously", b => randomPositions = b); - AddStep("Add facade containers", addFacadeContainers); + AddStep("Add tracking containers", addFacadeContainers); AddStep("Move facade to random position", startTrackingRandom); waitForMove(); - AddAssert("Logo is tracking", () => facadeContainer.IsLogoTracking); + AddAssert("Logo is tracking", () => trackingContainer.IsLogoTracking); } /// @@ -84,11 +84,11 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void RemoveFacadeTest() { - AddStep("Add facade containers", addFacadeContainers); + AddStep("Add tracking containers", addFacadeContainers); AddStep("Move facade to random position", startTrackingRandom); AddStep("Remove facade from FacadeContainer", removeFacade); waitForMove(); - AddAssert("Logo is not tracking", () => !facadeContainer.IsLogoTracking); + AddAssert("Logo is not tracking", () => !trackingContainer.IsLogoTracking); } /// @@ -97,17 +97,12 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TransferFacadeTest() { - AddStep("Add facade containers", addFacadeContainers); + AddStep("Add tracking containers", addFacadeContainers); AddStep("Move facade to random position", startTrackingRandom); AddStep("Remove facade from FacadeContainer", removeFacade); - AddStep("Transfer facade to a new container", () => - { - transferContainer.Add(logoFacade); - transferContainerBox.Colour = Color4.Tomato; - moveLogoFacade(); - }); + AddStep("Transfer facade to a new container", addFacadeToNewContainer); waitForMove(); - AddAssert("Logo is tracking", () => facadeContainer.IsLogoTracking); + AddAssert("Logo is tracking", () => trackingContainer.IsLogoTracking); } /// @@ -120,7 +115,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Create new flow container with facade", () => { - Add(facadeContainer = new TestLogoFacadeContainer + Add(trackingContainer = new TestLogoTrackingContainer { AutoSizeAxes = Axes.Both, Origin = Anchor.TopCentre, @@ -156,7 +151,7 @@ namespace osu.Game.Tests.Visual.UserInterface Colour = Color4.White, RelativeSizeAxes = Axes.Both, }, - facadeContainer.LogoFacade, + trackingContainer.LogoFacade, } }, new Box @@ -171,27 +166,34 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Perform logo movements", () => { - facadeContainer.Tracking = false; + trackingContainer.Tracking = false; logo.MoveTo(new Vector2(0.5f), 500, Easing.InOutExpo); - facadeContainer.SetLogo(logo, 1.0f, 1000, Easing.InOutExpo); + trackingContainer.SetLogo(logo, 1.0f, 1000, Easing.InOutExpo); visualBox.Colour = Color4.White; Scheduler.AddDelayed(() => { - facadeContainer.Tracking = true; + trackingContainer.Tracking = true; visualBox.Colour = Color4.Tomato; }, 700); }); waitForMove(8); - AddAssert("Logo is tracking", () => facadeContainer.IsLogoTracking); + AddAssert("Logo is tracking", () => trackingContainer.IsLogoTracking); + } + + [Test] + public void SetFacadeSizeTest() + { + AddStep("Add tracking containers", addFacadeContainers); + AddStep("Break shit", () => { logoFacade.Size = new Vector2(0, 0); }); } private void addFacadeContainers() { AddRange(new Drawable[] { - facadeContainer = new TestLogoFacadeContainer + trackingContainer = new TestLogoTrackingContainer { Alpha = 0.35f, RelativeSizeAxes = Axes.None, @@ -215,22 +217,29 @@ namespace osu.Game.Tests.Visual.UserInterface }, }); - facadeContainer.Add(logoFacade = facadeContainer.LogoFacade); - facadeContainer.SetLogo(logo, 1.0f, 1000); + trackingContainer.Add(logoFacade = trackingContainer.LogoFacade); + trackingContainer.SetLogo(logo, 1.0f, 1000); } private void waitForMove(int count = 5) => AddWaitStep("Wait for transforms to finish", count); private void removeFacade() { - facadeContainer.Remove(logoFacade); + trackingContainer.Remove(logoFacade); visualBox.Colour = Color4.White; moveLogoFacade(); } private void startTrackingRandom() { - facadeContainer.Tracking = true; + trackingContainer.Tracking = true; + moveLogoFacade(); + } + + private void addFacadeToNewContainer() + { + transferContainer.Add(logoFacade); + transferContainerBox.Colour = Color4.Tomato; moveLogoFacade(); } @@ -239,7 +248,7 @@ namespace osu.Game.Tests.Visual.UserInterface if (logoFacade?.Transforms.Count == 0 && transferContainer?.Transforms.Count == 0) { Random random = new Random(); - facadeContainer.Delay(500).MoveTo(new Vector2(random.Next(0, (int)logo.Parent.DrawWidth), random.Next(0, (int)logo.Parent.DrawHeight)), 300); + trackingContainer.Delay(500).MoveTo(new Vector2(random.Next(0, (int)logo.Parent.DrawWidth), random.Next(0, (int)logo.Parent.DrawHeight)), 300); transferContainer.Delay(500).MoveTo(new Vector2(random.Next(0, (int)logo.Parent.DrawWidth), random.Next(0, (int)logo.Parent.DrawHeight)), 300); } @@ -247,12 +256,12 @@ namespace osu.Game.Tests.Visual.UserInterface Schedule(moveLogoFacade); } - private class TestLogoFacadeContainer : LogoFacadeContainer + private class TestLogoTrackingContainer : LogoTrackingContainer { /// /// Check that the logo is tracking the position of the facade, with an acceptable precision lenience. /// - public bool IsLogoTracking => Precision.AlmostEquals(Logo.Position, LogoTrackingPosition()); + public bool IsLogoTracking => Precision.AlmostEquals(Logo.Position, LogoTrackingPosition); } } } diff --git a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs b/osu.Game/Graphics/Containers/LogoFacadeContainer.cs deleted file mode 100644 index c37588cb55..0000000000 --- a/osu.Game/Graphics/Containers/LogoFacadeContainer.cs +++ /dev/null @@ -1,114 +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 osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.MathUtils; -using osu.Game.Screens.Menu; -using osuTK; - -namespace osu.Game.Graphics.Containers -{ - /// - /// A container that creates a to be used to update and track the position of an . - /// - public class LogoFacadeContainer : Container - { - protected virtual Facade CreateFacade() => new Facade(); - - public Facade LogoFacade { get; } - - /// - /// Whether or not the logo assigned to this FacadeContainer should be tracking the position its facade. - /// - public bool Tracking = false; - - protected OsuLogo Logo; - - private float facadeScale; - private Easing easing; - private Vector2? startPosition; - private double? startTime; - private double duration; - - public LogoFacadeContainer() - { - LogoFacade = CreateFacade(); - } - - /// - /// Assign the logo that should track the Facade's position, as well as how it should transform to its initial position. - /// - /// The instance of the logo to be used for tracking. - /// The scale of the facade. Does not actually affect the logo itself. - /// The duration of the initial transform. Default is instant. - /// The easing type of the initial transform. - public void SetLogo(OsuLogo logo, float facadeScale = 1.0f, double duration = 0, Easing easing = Easing.None) - { - Logo = logo ?? throw new ArgumentNullException(nameof(logo)); - this.facadeScale = facadeScale; - this.duration = duration; - this.easing = easing; - - startTime = null; - startPosition = null; - } - - /// - /// Gets the position that the logo should move to with respect to the . - /// Manually performs a conversion of the Facade's position to the Logo's parent's relative space. - /// - /// Will only be correct if the logo's are set to Axes.Both - /// The position that the logo should move to in its parent's relative space. - protected Vector2 LogoTrackingPosition() - { - Vector2 local; - local.X = Logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre).X / Logo.Parent.RelativeToAbsoluteFactor.X; - local.Y = Logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre).Y / Logo.Parent.RelativeToAbsoluteFactor.Y; - return local; - } - - protected override void Update() - { - base.Update(); - - if (Logo == null || !Tracking) - return; - - // Account for the scale of the actual logo container, as SizeForFlow only accounts for the sprite scale. - LogoFacade.Size = new Vector2(Logo.SizeForFlow * Logo.Scale.X * facadeScale); - - if (LogoFacade.Parent != null && Logo.Position != LogoTrackingPosition()) - { - // If this is our first update since tracking has started, initialize our starting values for interpolation - if (startTime == null || startPosition == null) - { - startTime = Time.Current; - startPosition = Logo.Position; - } - - if (duration != 0) - { - double elapsedDuration = Time.Current - startTime ?? throw new ArgumentNullException(nameof(startTime)); - - var mount = (float)Interpolation.ApplyEasing(easing, Math.Min(elapsedDuration / duration, 1)); - - // Interpolate the position of the logo, where mount 0 is where the logo was when it first began interpolating, and mount 1 is the target location. - Logo.Position = Vector2.Lerp(startPosition ?? throw new ArgumentNullException(nameof(startPosition)), LogoTrackingPosition(), mount); - } - else - { - Logo.Position = LogoTrackingPosition(); - } - } - } - - /// - /// A placeholder container that serves as a dummy object to denote another object's location and size. - /// - public class Facade : Container - { - } - } -} diff --git a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs new file mode 100644 index 0000000000..afb30f981b --- /dev/null +++ b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs @@ -0,0 +1,156 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.MathUtils; +using osu.Game.Screens.Menu; +using osuTK; + +namespace osu.Game.Graphics.Containers +{ + /// + /// A container that handles tracking of an through different layout scenarios + /// + public class LogoTrackingContainer : Container + { + public Facade LogoFacade { get; } + + /// + /// Whether or not the logo assigned to this FacadeContainer should be tracking the position of its facade. + /// + public bool Tracking { get; set; } + + protected OsuLogo Logo; + + private float facadeScale; + private Easing easing; + private Vector2? startPosition; + private double? startTime; + private double duration; + + public LogoTrackingContainer() + { + LogoFacade = new ExposedFacade(); + } + + /// + /// Assign the logo that should track the Facade's position, as well as how it should transform to its initial position. + /// + /// The instance of the logo to be used for tracking. + /// The scale of the facade. Does not actually affect the logo itself. + /// The duration of the initial transform. Default is instant. + /// The easing type of the initial transform. + public void SetLogo(OsuLogo logo, float facadeScale = 1.0f, double duration = 0, Easing easing = Easing.None) + { + if (Logo != logo) + { + if (logo?.HasTrackingContainer ?? throw new ArgumentNullException(nameof(logo))) + { + // Prevent the same logo from being added to multiple LogoTrackingContainers. + throw new InvalidOperationException($"Cannot add an instance of {typeof(OsuLogo)} to multiple {typeof(LogoTrackingContainer)}s"); + } + + if (Logo != null) + { + // If we're replacing the logo to be tracked, the old one no longer has a tracking container + Logo.HasTrackingContainer = false; + } + } + + Logo = logo; + Logo.HasTrackingContainer = true; + this.facadeScale = facadeScale; + this.duration = duration; + this.easing = easing; + + startTime = null; + startPosition = null; + } + + /// + /// Gets the position that the logo should move to with respect to the . + /// Manually performs a conversion of the Facade's position to the Logo's parent's relative space. + /// + /// Will only be correct if the logo's are set to Axes.Both + protected Vector2 LogoTrackingPosition => new Vector2(Logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre).X / Logo.Parent.RelativeToAbsoluteFactor.X, + Logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre).Y / Logo.Parent.RelativeToAbsoluteFactor.Y); + + protected override void Update() + { + base.Update(); + + if (Logo == null || !Tracking) + return; + + // Account for the scale of the actual OsuLogo, as SizeForFlow only accounts for the sprite scale. + ((ExposedFacade)LogoFacade).SetSize(new Vector2(Logo.SizeForFlow * Logo.Scale.X * facadeScale)); + + if (LogoFacade.Parent != null && Logo.Position != LogoTrackingPosition && Logo.RelativePositionAxes == Axes.Both) + { + // If this is our first update since tracking has started, initialize our starting values for interpolation + if (startTime == null || startPosition == null) + { + startTime = Time.Current; + startPosition = Logo.Position; + } + + if (duration != 0) + { + double elapsedDuration = (double)(Time.Current - startTime); + + var amount = (float)Interpolation.ApplyEasing(easing, Math.Min(elapsedDuration / duration, 1)); + + // Interpolate the position of the logo, where amount 0 is where the logo was when it first began interpolating, and amount 1 is the target location. + Logo.Position = Vector2.Lerp((Vector2)startPosition, LogoTrackingPosition, amount); + } + else + { + Logo.Position = LogoTrackingPosition; + } + } + } + + protected override void Dispose(bool isDisposing) + { + if (Logo != null) + Logo.HasTrackingContainer = false; + + base.Dispose(isDisposing); + } + + private Vector2 size; + + private class ExposedFacade : Facade + { + public override Vector2 Size + { + get => base.Size; + set => throw new InvalidOperationException($"Cannot set the Size of a {typeof(Facade)} outside of a {typeof(LogoTrackingContainer)}"); + } + + public void SetSize(Vector2 size) + { + base.SetSize(size); + } + } + + /// + /// A dummy object used to denote another object's location. + /// + public abstract class Facade : Drawable + { + public override Vector2 Size + { + get => base.Size; + set => throw new InvalidOperationException($"Cannot set the Size of a {typeof(Facade)} outside of a {typeof(LogoTrackingContainer)}"); + } + + protected void SetSize(Vector2 size) + { + base.Size = size; + } + } + } +} diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index cb95ec1765..a359893418 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -60,7 +60,7 @@ namespace osu.Game.Screens.Menu if (this.logo != null) { this.logo.Action = onOsuLogo; - logoFacadeContainer.SetLogo(logo, 0.74f); + logoTrackingContainer.SetLogo(logo, 0.74f); // osuLogo.SizeForFlow relies on loading to be complete. buttonArea.Flow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + this.logo.SizeForFlow / 4), 0); @@ -70,7 +70,7 @@ namespace osu.Game.Screens.Menu else { // We should stop tracking as the facade is now out of scope. - logoFacadeContainer.Tracking = false; + logoTrackingContainer.Tracking = false; } } @@ -83,29 +83,29 @@ namespace osu.Game.Screens.Menu private SampleChannel sampleBack; - private readonly LogoFacadeContainer logoFacadeContainer; + private readonly LogoTrackingContainer logoTrackingContainer; public ButtonSystem() { RelativeSizeAxes = Axes.Both; - Child = logoFacadeContainer = new LogoFacadeContainer + Child = logoTrackingContainer = new LogoTrackingContainer { RelativeSizeAxes = Axes.Both, Child = buttonArea = new ButtonArea() }; - buttonArea.AddRange(new Container[] + buttonArea.AddRange(new Drawable[] { new Button(@"settings", string.Empty, FontAwesome.Gear, new Color4(85, 85, 85, 255), () => OnSettings?.Invoke(), -WEDGE_WIDTH, Key.O), backButton = new Button(@"back", @"button-back-select", OsuIcon.LeftCircle, new Color4(51, 58, 94, 255), () => State = ButtonSystemState.TopLevel, -WEDGE_WIDTH) { VisibleState = ButtonSystemState.Play, }, - logoFacadeContainer.LogoFacade + logoTrackingContainer.LogoFacade }); - buttonArea.Flow.CentreTarget = logoFacadeContainer.LogoFacade; + buttonArea.Flow.CentreTarget = logoTrackingContainer.LogoFacade; } [Resolved(CanBeNull = true)] @@ -271,7 +271,7 @@ namespace osu.Game.Screens.Menu logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => { - logoFacadeContainer.Tracking = false; + logoTrackingContainer.Tracking = false; game?.Toolbar.Hide(); @@ -294,8 +294,8 @@ namespace osu.Game.Screens.Menu if (lastState == ButtonSystemState.Initial) logo.ScaleTo(0.5f, 200, Easing.In); - logoFacadeContainer.SetLogo(logo, 0.74f, lastState == ButtonSystemState.EnteringMode ? 0 : 200, Easing.In); - logoFacadeContainer.Tracking = true; + logoTrackingContainer.SetLogo(logo, 0.74f, lastState == ButtonSystemState.EnteringMode ? 0 : 200, Easing.In); + logoTrackingContainer.Tracking = true; logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => @@ -308,14 +308,14 @@ namespace osu.Game.Screens.Menu break; default: logo.ClearTransforms(targetMember: nameof(Position)); - logoFacadeContainer.Tracking = true; + logoTrackingContainer.Tracking = true; logo.ScaleTo(0.5f, 200, Easing.OutQuint); break; } break; case ButtonSystemState.EnteringMode: - logoFacadeContainer.Tracking = true; + logoTrackingContainer.Tracking = true; break; } } diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index c54ccd21b5..ad70d34637 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -54,8 +54,14 @@ namespace osu.Game.Screens.Menu /// public Func Action; + /// + /// The size of the logo Sprite with respect to the scale of its hover and bounce containers. + /// + /// Does not account for the scale of this public float SizeForFlow => logo == null ? 0 : logo.DrawSize.X * logo.Scale.X * logoBounceContainer.Scale.X * logoHoverContainer.Scale.X; + public bool HasTrackingContainer { get; set; } + private readonly Sprite ripple; private readonly Container rippleContainer; diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index ccfd965f53..f7feb3535d 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Play private Player player; - private LogoFacadeContainer content; + private LogoTrackingContainer content; private BeatmapMetadataDisplay info; @@ -60,14 +60,12 @@ namespace osu.Game.Screens.Play [BackgroundDependencyLoader] private void load() { - InternalChild = content = new LogoFacadeContainer + InternalChild = (content = new LogoTrackingContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - }; - - content.Children = new Drawable[] + }).WithChildren(new Drawable[] { info = new BeatmapMetadataDisplay(Beatmap.Value, content.LogoFacade) { @@ -89,7 +87,7 @@ namespace osu.Game.Screens.Play new InputSettings() } } - }; + }); loadNewPlayer(); } @@ -163,12 +161,9 @@ namespace osu.Game.Screens.Play logo.ScaleTo(new Vector2(0.15f), duration, Easing.In); logo.FadeIn(350); - content.SetLogo(logo, 1.0f, 500, Easing.InOutExpo); + content.SetLogo(logo, 1.0f, resuming ? 0 : 500, Easing.InOutExpo); - Scheduler.AddDelayed(() => - { - content.Tracking = true; - }, resuming ? 0 : 500); + Scheduler.AddDelayed(() => { content.Tracking = true; }, resuming ? 0 : 500); } protected override void LogoExiting(OsuLogo logo) @@ -321,7 +316,7 @@ namespace osu.Game.Screens.Play } private readonly WorkingBeatmap beatmap; - private readonly Container facade; + private readonly Drawable facade; private LoadingAnimation loading; private Sprite backgroundSprite; private ModDisplay modDisplay; @@ -343,7 +338,7 @@ namespace osu.Game.Screens.Play } } - public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Container facade) + public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Drawable facade) { this.beatmap = beatmap; this.facade = facade; @@ -366,7 +361,7 @@ namespace osu.Game.Screens.Play Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, Direction = FillDirection.Vertical, - Children = new Drawable[] + Children = new[] { facade, new OsuSpriteText From b1d74e57e58fc175fed9061dabed5f8e6d2e9642 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 5 Apr 2019 13:56:08 +0900 Subject: [PATCH 33/54] Add checks guarding against setting tracking on multiple trackingcongtainers and setting facade size --- .../Containers/LogoTrackingContainer.cs | 48 ++++++++++--------- osu.Game/Screens/Menu/OsuLogo.cs | 2 +- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs index afb30f981b..ee6d5dec20 100644 --- a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs +++ b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Reflection.Metadata.Ecma335; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.MathUtils; @@ -20,7 +21,24 @@ namespace osu.Game.Graphics.Containers /// /// Whether or not the logo assigned to this FacadeContainer should be tracking the position of its facade. /// - public bool Tracking { get; set; } + public bool Tracking + { + get => tracking; + set + { + if (Logo != null) + { + if (value && !tracking && Logo.IsTracking) + throw new InvalidOperationException($"Cannot track an instance of {typeof(OsuLogo)} to multiple {typeof(LogoTrackingContainer)}s"); + + Logo.IsTracking = value; + } + + tracking = value; + } + } + + private bool tracking; protected OsuLogo Logo; @@ -44,23 +62,15 @@ namespace osu.Game.Graphics.Containers /// The easing type of the initial transform. public void SetLogo(OsuLogo logo, float facadeScale = 1.0f, double duration = 0, Easing easing = Easing.None) { - if (Logo != logo) + if (Logo != logo && Logo != null) { - if (logo?.HasTrackingContainer ?? throw new ArgumentNullException(nameof(logo))) - { - // Prevent the same logo from being added to multiple LogoTrackingContainers. - throw new InvalidOperationException($"Cannot add an instance of {typeof(OsuLogo)} to multiple {typeof(LogoTrackingContainer)}s"); - } - - if (Logo != null) - { - // If we're replacing the logo to be tracked, the old one no longer has a tracking container - Logo.HasTrackingContainer = false; - } + // If we're replacing the logo to be tracked, the old one no longer has a tracking container + Logo.IsTracking = false; } - Logo = logo; - Logo.HasTrackingContainer = true; + Logo = logo ?? throw new ArgumentNullException(nameof(logo)); + Logo.IsTracking = Tracking; + this.facadeScale = facadeScale; this.duration = duration; this.easing = easing; @@ -115,7 +125,7 @@ namespace osu.Game.Graphics.Containers protected override void Dispose(bool isDisposing) { if (Logo != null) - Logo.HasTrackingContainer = false; + Tracking = false; base.Dispose(isDisposing); } @@ -124,12 +134,6 @@ namespace osu.Game.Graphics.Containers private class ExposedFacade : Facade { - public override Vector2 Size - { - get => base.Size; - set => throw new InvalidOperationException($"Cannot set the Size of a {typeof(Facade)} outside of a {typeof(LogoTrackingContainer)}"); - } - public void SetSize(Vector2 size) { base.SetSize(size); diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index ad70d34637..4631f4e222 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -60,7 +60,7 @@ namespace osu.Game.Screens.Menu /// Does not account for the scale of this public float SizeForFlow => logo == null ? 0 : logo.DrawSize.X * logo.Scale.X * logoBounceContainer.Scale.X * logoHoverContainer.Scale.X; - public bool HasTrackingContainer { get; set; } + public bool IsTracking { get; set; } private readonly Sprite ripple; From 5fa93f4a050263be0a2a546bcbfbd1bbc97e2771 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 5 Apr 2019 15:05:11 +0900 Subject: [PATCH 34/54] Add test for checking exception --- .../UserInterface/TestCaseLogoTrackingContainer.cs | 12 +++++++++++- .../Graphics/Containers/LogoTrackingContainer.cs | 11 +++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs index 4d255eb25a..3b57d892ad 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs @@ -186,7 +186,17 @@ namespace osu.Game.Tests.Visual.UserInterface public void SetFacadeSizeTest() { AddStep("Add tracking containers", addFacadeContainers); - AddStep("Break shit", () => { logoFacade.Size = new Vector2(0, 0); }); + AddStep("Break stuff", () => { logoFacade.Size = new Vector2(0, 0); }); + } + + [Test] + public void SetMultipleContainers() + { + LogoTrackingContainer newContainer = new LogoTrackingContainer(); + AddStep("Add tracking containers", addFacadeContainers); + AddStep("Move facade to random position", startTrackingRandom); + AddStep("Add logo to new container", () => newContainer.SetLogo(logo)); + AddStep("Break stuff", () => newContainer.Tracking = true); } private void addFacadeContainers() diff --git a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs index ee6d5dec20..ab6f7ebc2a 100644 --- a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs +++ b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Graphics.Containers { /// - /// A container that handles tracking of an through different layout scenarios + /// A container that handles tracking of an through different layout scenarios. /// public class LogoTrackingContainer : Container { @@ -38,8 +38,6 @@ namespace osu.Game.Graphics.Containers } } - private bool tracking; - protected OsuLogo Logo; private float facadeScale; @@ -47,6 +45,7 @@ namespace osu.Game.Graphics.Containers private Vector2? startPosition; private double? startTime; private double duration; + private bool tracking; public LogoTrackingContainer() { @@ -69,7 +68,11 @@ namespace osu.Game.Graphics.Containers } Logo = logo ?? throw new ArgumentNullException(nameof(logo)); - Logo.IsTracking = Tracking; + + if (Tracking) + { + Logo.IsTracking = true; + } this.facadeScale = facadeScale; this.duration = duration; From e06fe7950b04bec9df82a6244281b06faaf4892d Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 5 Apr 2019 15:06:37 +0900 Subject: [PATCH 35/54] Cleanup --- .../TestCaseLogoTrackingContainer.cs | 17 ----------------- .../Containers/LogoTrackingContainer.cs | 3 --- 2 files changed, 20 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs index 3b57d892ad..19e430da3e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs @@ -182,23 +182,6 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("Logo is tracking", () => trackingContainer.IsLogoTracking); } - [Test] - public void SetFacadeSizeTest() - { - AddStep("Add tracking containers", addFacadeContainers); - AddStep("Break stuff", () => { logoFacade.Size = new Vector2(0, 0); }); - } - - [Test] - public void SetMultipleContainers() - { - LogoTrackingContainer newContainer = new LogoTrackingContainer(); - AddStep("Add tracking containers", addFacadeContainers); - AddStep("Move facade to random position", startTrackingRandom); - AddStep("Add logo to new container", () => newContainer.SetLogo(logo)); - AddStep("Break stuff", () => newContainer.Tracking = true); - } - private void addFacadeContainers() { AddRange(new Drawable[] diff --git a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs index ab6f7ebc2a..746710bcda 100644 --- a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs +++ b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Reflection.Metadata.Ecma335; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.MathUtils; @@ -133,8 +132,6 @@ namespace osu.Game.Graphics.Containers base.Dispose(isDisposing); } - private Vector2 size; - private class ExposedFacade : Facade { public void SetSize(Vector2 size) From 37ffe47e4b763140befcea82f29cfe662869b2c4 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 5 Apr 2019 15:30:09 +0900 Subject: [PATCH 36/54] Add back exception tests with better descriptions --- .../TestCaseLogoTrackingContainer.cs | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs index 19e430da3e..cf84a34344 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs @@ -182,6 +182,49 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("Logo is tracking", () => trackingContainer.IsLogoTracking); } + [Test] + public void SetFacadeSizeTest() + { + bool failed = false; + AddStep("Add tracking containers", addFacadeContainers); + AddStep("Try setting facade size", () => + { + try + { + logoFacade.Size = new Vector2(0, 0); + } + catch (Exception e) + { + if (e is InvalidOperationException) + failed = true; + } + }); + AddAssert("Exception thrown", () => failed); + } + + [Test] + public void SetMultipleContainers() + { + bool failed = false; + LogoTrackingContainer newContainer = new LogoTrackingContainer(); + AddStep("Add tracking containers", addFacadeContainers); + AddStep("Move facade to random position", startTrackingRandom); + AddStep("Add logo to new container", () => newContainer.SetLogo(logo)); + AddStep("Try tracking new container", () => + { + try + { + newContainer.Tracking = true; + } + catch (Exception e) + { + if (e is InvalidOperationException) + failed = true; + } + }); + AddAssert("Exception thrown", () => failed); + } + private void addFacadeContainers() { AddRange(new Drawable[] From c693d1fad89ea3b3d4ab655808668a6350bb9f6c Mon Sep 17 00:00:00 2001 From: David Zhao Date: Fri, 5 Apr 2019 15:48:48 +0900 Subject: [PATCH 37/54] Further condense steps --- .../TestCaseLogoTrackingContainer.cs | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs index cf84a34344..01a3113fe1 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs @@ -100,7 +100,12 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Add tracking containers", addFacadeContainers); AddStep("Move facade to random position", startTrackingRandom); AddStep("Remove facade from FacadeContainer", removeFacade); - AddStep("Transfer facade to a new container", addFacadeToNewContainer); + AddStep("Transfer facade to a new container", () => + { + transferContainer.Add(logoFacade); + transferContainerBox.Colour = Color4.Tomato; + moveLogoFacade(); + }); waitForMove(); AddAssert("Logo is tracking", () => trackingContainer.IsLogoTracking); } @@ -186,7 +191,11 @@ namespace osu.Game.Tests.Visual.UserInterface public void SetFacadeSizeTest() { bool failed = false; - AddStep("Add tracking containers", addFacadeContainers); + AddStep("Set up scenario", () => + { + failed = false; + addFacadeContainers(); + }); AddStep("Try setting facade size", () => { try @@ -203,13 +212,18 @@ namespace osu.Game.Tests.Visual.UserInterface } [Test] - public void SetMultipleContainers() + public void SetMultipleContainersTest() { bool failed = false; LogoTrackingContainer newContainer = new LogoTrackingContainer(); - AddStep("Add tracking containers", addFacadeContainers); - AddStep("Move facade to random position", startTrackingRandom); - AddStep("Add logo to new container", () => newContainer.SetLogo(logo)); + AddStep("Set up scenario", () => + { + failed = false; + newContainer = new LogoTrackingContainer(); + addFacadeContainers(); + startTrackingRandom(); + newContainer.SetLogo(logo); + }); AddStep("Try tracking new container", () => { try @@ -272,13 +286,6 @@ namespace osu.Game.Tests.Visual.UserInterface moveLogoFacade(); } - private void addFacadeToNewContainer() - { - transferContainer.Add(logoFacade); - transferContainerBox.Colour = Color4.Tomato; - moveLogoFacade(); - } - private void moveLogoFacade() { if (logoFacade?.Transforms.Count == 0 && transferContainer?.Transforms.Count == 0) From d7655bc579df0a5193caa5cad65b02fd7084c3d8 Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Mon, 8 Apr 2019 11:22:01 +0900 Subject: [PATCH 38/54] Use .Value instead of cast Co-Authored-By: nyquillerium --- osu.Game/Graphics/Containers/LogoTrackingContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs index 746710bcda..de70231989 100644 --- a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs +++ b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs @@ -115,7 +115,7 @@ namespace osu.Game.Graphics.Containers var amount = (float)Interpolation.ApplyEasing(easing, Math.Min(elapsedDuration / duration, 1)); // Interpolate the position of the logo, where amount 0 is where the logo was when it first began interpolating, and amount 1 is the target location. - Logo.Position = Vector2.Lerp((Vector2)startPosition, LogoTrackingPosition, amount); + Logo.Position = Vector2.Lerp(startPosition.Value, LogoTrackingPosition, amount); } else { From a690302d00cefdae17fa150e1d567cb9669fbc9d Mon Sep 17 00:00:00 2001 From: David Zhao Date: Mon, 8 Apr 2019 15:24:09 +0900 Subject: [PATCH 39/54] Apply reviews --- .../UserInterface/TestCaseButtonSystem.cs | 2 +- .../TestCaseLogoTrackingContainer.cs | 27 +++---- .../Containers/LogoTrackingContainer.cs | 78 +++++++++---------- osu.Game/Screens/Menu/ButtonSystem.cs | 13 ++-- .../Screens/Menu/FlowContainerWithOrigin.cs | 2 +- osu.Game/Screens/Play/PlayerLoader.cs | 8 +- 6 files changed, 59 insertions(+), 71 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestCaseButtonSystem.cs b/osu.Game.Tests/Visual/UserInterface/TestCaseButtonSystem.cs index 261e87ff07..04aa8bce7e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestCaseButtonSystem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestCaseButtonSystem.cs @@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual.UserInterface RelativeSizeAxes = Axes.Both, }, buttons = new ButtonSystem(), - logo = new OsuLogo() + logo = new OsuLogo { RelativePositionAxes = Axes.Both } }; buttons.SetOsuLogo(logo); diff --git a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs index 01a3113fe1..8b70a34c85 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs @@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.UserInterface { AddToggleStep("Toggle move continuously", b => randomPositions = b); AddStep("Add tracking containers", addFacadeContainers); - AddStep("Move facade to random position", startTrackingRandom); + AddStep("Move facade to random position", moveLogoFacade); waitForMove(); AddAssert("Logo is tracking", () => trackingContainer.IsLogoTracking); } @@ -85,7 +85,7 @@ namespace osu.Game.Tests.Visual.UserInterface public void RemoveFacadeTest() { AddStep("Add tracking containers", addFacadeContainers); - AddStep("Move facade to random position", startTrackingRandom); + AddStep("Move facade to random position", moveLogoFacade); AddStep("Remove facade from FacadeContainer", removeFacade); waitForMove(); AddAssert("Logo is not tracking", () => !trackingContainer.IsLogoTracking); @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual.UserInterface public void TransferFacadeTest() { AddStep("Add tracking containers", addFacadeContainers); - AddStep("Move facade to random position", startTrackingRandom); + AddStep("Move facade to random position", moveLogoFacade); AddStep("Remove facade from FacadeContainer", removeFacade); AddStep("Transfer facade to a new container", () => { @@ -171,14 +171,14 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Perform logo movements", () => { - trackingContainer.Tracking = false; + trackingContainer.StopTracking(); logo.MoveTo(new Vector2(0.5f), 500, Easing.InOutExpo); - trackingContainer.SetLogo(logo, 1.0f, 1000, Easing.InOutExpo); + visualBox.Colour = Color4.White; Scheduler.AddDelayed(() => { - trackingContainer.Tracking = true; + trackingContainer.StartTracking(logo, 1000, Easing.InOutExpo); visualBox.Colour = Color4.Tomato; }, 700); }); @@ -221,14 +221,13 @@ namespace osu.Game.Tests.Visual.UserInterface failed = false; newContainer = new LogoTrackingContainer(); addFacadeContainers(); - startTrackingRandom(); - newContainer.SetLogo(logo); + moveLogoFacade(); }); AddStep("Try tracking new container", () => { try { - newContainer.Tracking = true; + newContainer.StartTracking(logo); } catch (Exception e) { @@ -268,7 +267,7 @@ namespace osu.Game.Tests.Visual.UserInterface }); trackingContainer.Add(logoFacade = trackingContainer.LogoFacade); - trackingContainer.SetLogo(logo, 1.0f, 1000); + trackingContainer.StartTracking(logo, 1000); } private void waitForMove(int count = 5) => AddWaitStep("Wait for transforms to finish", count); @@ -280,12 +279,6 @@ namespace osu.Game.Tests.Visual.UserInterface moveLogoFacade(); } - private void startTrackingRandom() - { - trackingContainer.Tracking = true; - moveLogoFacade(); - } - private void moveLogoFacade() { if (logoFacade?.Transforms.Count == 0 && transferContainer?.Transforms.Count == 0) @@ -304,7 +297,7 @@ namespace osu.Game.Tests.Visual.UserInterface /// /// Check that the logo is tracking the position of the facade, with an acceptable precision lenience. /// - public bool IsLogoTracking => Precision.AlmostEquals(Logo.Position, LogoTrackingPosition); + public bool IsLogoTracking => Precision.AlmostEquals(Logo.Position, ComputeLogoTrackingPosition()); } } } diff --git a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs index 746710bcda..ae585a2ba7 100644 --- a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs +++ b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs @@ -17,29 +17,9 @@ namespace osu.Game.Graphics.Containers { public Facade LogoFacade { get; } - /// - /// Whether or not the logo assigned to this FacadeContainer should be tracking the position of its facade. - /// - public bool Tracking - { - get => tracking; - set - { - if (Logo != null) - { - if (value && !tracking && Logo.IsTracking) - throw new InvalidOperationException($"Cannot track an instance of {typeof(OsuLogo)} to multiple {typeof(LogoTrackingContainer)}s"); + protected OsuLogo Logo => logo; - Logo.IsTracking = value; - } - - tracking = value; - } - } - - protected OsuLogo Logo; - - private float facadeScale; + private OsuLogo logo; private Easing easing; private Vector2? startPosition; private double? startTime; @@ -58,27 +38,38 @@ namespace osu.Game.Graphics.Containers /// The scale of the facade. Does not actually affect the logo itself. /// The duration of the initial transform. Default is instant. /// The easing type of the initial transform. - public void SetLogo(OsuLogo logo, float facadeScale = 1.0f, double duration = 0, Easing easing = Easing.None) + public void StartTracking(OsuLogo logo, double duration = 0, Easing easing = Easing.None) { - if (Logo != logo && Logo != null) + if (logo == null) + throw new ArgumentNullException(nameof(logo)); + + if (logo.IsTracking && tracking == false) + throw new InvalidOperationException($"Cannot track an instance of {typeof(OsuLogo)} to multiple {typeof(LogoTrackingContainer)}s"); + + if (this.logo != logo && this.logo != null) { // If we're replacing the logo to be tracked, the old one no longer has a tracking container - Logo.IsTracking = false; + this.logo.IsTracking = false; } - Logo = logo ?? throw new ArgumentNullException(nameof(logo)); + this.logo = logo; + this.logo.IsTracking = true; - if (Tracking) - { - Logo.IsTracking = true; - } - - this.facadeScale = facadeScale; this.duration = duration; this.easing = easing; startTime = null; startPosition = null; + + tracking = true; + } + + public void StopTracking() + { + if (logo != null) + logo.IsTracking = false; + + tracking = false; } /// @@ -86,20 +77,27 @@ namespace osu.Game.Graphics.Containers /// Manually performs a conversion of the Facade's position to the Logo's parent's relative space. /// /// Will only be correct if the logo's are set to Axes.Both - protected Vector2 LogoTrackingPosition => new Vector2(Logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre).X / Logo.Parent.RelativeToAbsoluteFactor.X, - Logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre).Y / Logo.Parent.RelativeToAbsoluteFactor.Y); + protected Vector2 ComputeLogoTrackingPosition() + { + var absolutePos = Logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre); + + return new Vector2(absolutePos.X / Logo.Parent.RelativeToAbsoluteFactor.X, + absolutePos.Y / Logo.Parent.RelativeToAbsoluteFactor.Y); + } protected override void Update() { base.Update(); - if (Logo == null || !Tracking) + if (Logo == null || !tracking) return; // Account for the scale of the actual OsuLogo, as SizeForFlow only accounts for the sprite scale. - ((ExposedFacade)LogoFacade).SetSize(new Vector2(Logo.SizeForFlow * Logo.Scale.X * facadeScale)); + ((ExposedFacade)LogoFacade).SetSize(new Vector2(Logo.SizeForFlow * Logo.Scale.X)); - if (LogoFacade.Parent != null && Logo.Position != LogoTrackingPosition && Logo.RelativePositionAxes == Axes.Both) + var localPos = ComputeLogoTrackingPosition(); + + if (LogoFacade.Parent != null && Logo.Position != localPos && Logo.RelativePositionAxes == Axes.Both) { // If this is our first update since tracking has started, initialize our starting values for interpolation if (startTime == null || startPosition == null) @@ -115,11 +113,11 @@ namespace osu.Game.Graphics.Containers var amount = (float)Interpolation.ApplyEasing(easing, Math.Min(elapsedDuration / duration, 1)); // Interpolate the position of the logo, where amount 0 is where the logo was when it first began interpolating, and amount 1 is the target location. - Logo.Position = Vector2.Lerp((Vector2)startPosition, LogoTrackingPosition, amount); + Logo.Position = Vector2.Lerp((Vector2)startPosition, localPos, amount); } else { - Logo.Position = LogoTrackingPosition; + Logo.Position = localPos; } } } @@ -127,7 +125,7 @@ namespace osu.Game.Graphics.Containers protected override void Dispose(bool isDisposing) { if (Logo != null) - Tracking = false; + Logo.IsTracking = false; base.Dispose(isDisposing); } diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index d042e110e9..1d2ee3c284 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -60,17 +60,17 @@ namespace osu.Game.Screens.Menu if (this.logo != null) { this.logo.Action = onOsuLogo; - logoTrackingContainer.SetLogo(logo, 0.74f); // osuLogo.SizeForFlow relies on loading to be complete. buttonArea.Flow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + this.logo.SizeForFlow / 4), 0); + logoTrackingContainer.LogoFacade.Scale = new Vector2(0.74f); updateLogoState(); } else { // We should stop tracking as the facade is now out of scope. - logoTrackingContainer.Tracking = false; + logoTrackingContainer.StopTracking(); } } @@ -271,7 +271,7 @@ namespace osu.Game.Screens.Menu logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => { - logoTrackingContainer.Tracking = false; + logoTrackingContainer.StopTracking(); game?.Toolbar.Hide(); @@ -294,8 +294,7 @@ namespace osu.Game.Screens.Menu if (lastState == ButtonSystemState.Initial) logo.ScaleTo(0.5f, 200, Easing.In); - logoTrackingContainer.SetLogo(logo, 0.74f, lastState == ButtonSystemState.EnteringMode ? 0 : 200, Easing.In); - logoTrackingContainer.Tracking = true; + logoTrackingContainer.StartTracking(logo, lastState == ButtonSystemState.EnteringMode ? 0 : 200, Easing.In); logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => @@ -308,14 +307,14 @@ namespace osu.Game.Screens.Menu break; default: logo.ClearTransforms(targetMember: nameof(Position)); - logoTrackingContainer.Tracking = true; + logoTrackingContainer.StartTracking(logo, 0, Easing.In); logo.ScaleTo(0.5f, 200, Easing.OutQuint); break; } break; case ButtonSystemState.EnteringMode: - logoTrackingContainer.Tracking = true; + logoTrackingContainer.StartTracking(logo, 0, Easing.In); break; } } diff --git a/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs b/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs index ec7333ec02..8310ab06eb 100644 --- a/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs +++ b/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Menu if (CentreTarget == null) return base.OriginPosition; - return CentreTarget.DrawPosition + CentreTarget.DrawSize / 2; + return CentreTarget.DrawPosition + CentreTarget.DrawSize / 2 * CentreTarget.Scale; } } } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index f7feb3535d..4c8f9a3539 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -128,7 +128,7 @@ namespace osu.Game.Screens.Play private void contentOut() { // Ensure the logo is no longer tracking before we scale the content - content.Tracking = false; + content.StopTracking(); content.ScaleTo(0.7f, 300, Easing.InQuint); content.FadeOut(250); @@ -161,15 +161,13 @@ namespace osu.Game.Screens.Play logo.ScaleTo(new Vector2(0.15f), duration, Easing.In); logo.FadeIn(350); - content.SetLogo(logo, 1.0f, resuming ? 0 : 500, Easing.InOutExpo); - - Scheduler.AddDelayed(() => { content.Tracking = true; }, resuming ? 0 : 500); + Scheduler.AddDelayed(() => { content.StartTracking(logo, resuming ? 0 : 500, Easing.InOutExpo); }, resuming ? 0 : 500); } protected override void LogoExiting(OsuLogo logo) { base.LogoExiting(logo); - content.Tracking = false; + content.StopTracking(); } protected override void LoadComplete() From 8a01995668734e46e0630ce8b143fb446d868a1b Mon Sep 17 00:00:00 2001 From: David Zhao Date: Mon, 8 Apr 2019 16:14:41 +0900 Subject: [PATCH 40/54] Remove need for tracking bool and backing logo --- .../Containers/LogoTrackingContainer.cs | 27 +++++++++---------- osu.Game/Screens/Menu/ButtonSystem.cs | 2 +- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs index 0721011345..5ebdb7d45d 100644 --- a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs +++ b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs @@ -17,14 +17,12 @@ namespace osu.Game.Graphics.Containers { public Facade LogoFacade { get; } - protected OsuLogo Logo => logo; + protected OsuLogo Logo { get; private set; } - private OsuLogo logo; private Easing easing; private Vector2? startPosition; private double? startTime; private double duration; - private bool tracking; public LogoTrackingContainer() { @@ -43,33 +41,32 @@ namespace osu.Game.Graphics.Containers if (logo == null) throw new ArgumentNullException(nameof(logo)); - if (logo.IsTracking && tracking == false) + if (logo.IsTracking && Logo == null) throw new InvalidOperationException($"Cannot track an instance of {typeof(OsuLogo)} to multiple {typeof(LogoTrackingContainer)}s"); - if (this.logo != logo && this.logo != null) + if (Logo != logo && Logo != null) { // If we're replacing the logo to be tracked, the old one no longer has a tracking container - this.logo.IsTracking = false; + Logo.IsTracking = false; } - this.logo = logo; - this.logo.IsTracking = true; + Logo = logo; + Logo.IsTracking = true; this.duration = duration; this.easing = easing; startTime = null; startPosition = null; - - tracking = true; } public void StopTracking() { - if (logo != null) - logo.IsTracking = false; - - tracking = false; + if (Logo != null) + { + Logo.IsTracking = false; + Logo = null; + } } /// @@ -89,7 +86,7 @@ namespace osu.Game.Graphics.Containers { base.Update(); - if (Logo == null || !tracking) + if (Logo == null) return; // Account for the scale of the actual OsuLogo, as SizeForFlow only accounts for the sprite scale. diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 1d2ee3c284..a6157cdb64 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -63,7 +63,6 @@ namespace osu.Game.Screens.Menu // osuLogo.SizeForFlow relies on loading to be complete. buttonArea.Flow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + this.logo.SizeForFlow / 4), 0); - logoTrackingContainer.LogoFacade.Scale = new Vector2(0.74f); updateLogoState(); } @@ -106,6 +105,7 @@ namespace osu.Game.Screens.Menu }); buttonArea.Flow.CentreTarget = logoTrackingContainer.LogoFacade; + logoTrackingContainer.LogoFacade.Scale = new Vector2(0.74f); } [Resolved(CanBeNull = true)] From 4c571acd671a293dfbe3a6aee6963475bcbb67cc Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 9 Apr 2019 13:33:16 +0900 Subject: [PATCH 41/54] Reinstantiate mods for every player --- osu.Game/Screens/Play/Player.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index bf2bbc58b8..d8e31b7ad6 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Audio; @@ -69,6 +70,10 @@ namespace osu.Game.Screens.Play protected GameplayClockContainer GameplayClockContainer { get; private set; } + [Cached] + [Cached(Type = typeof(IBindable>))] + protected readonly Bindable> SelectedMods = new Bindable>(Enumerable.Empty()); + private readonly bool allowPause; private readonly bool showResults; @@ -88,6 +93,8 @@ namespace osu.Game.Screens.Play { this.api = api; + SelectedMods.Value = base.SelectedMods.Value.Select(m => m.CreateCopy()).ToArray(); + WorkingBeatmap working = loadBeatmap(); if (working == null) From d8ec1e73a3025c162e10cebbf8606af91c0ac88c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 9 Apr 2019 13:50:54 +0900 Subject: [PATCH 42/54] Cleanup TestCasePlayerLoader --- .../Visual/Gameplay/TestCasePlayerLoader.cs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs index 41d484e21f..aba689b241 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs @@ -2,10 +2,10 @@ // See the LICENCE file in the repository root for full licence text. using System.Threading; +using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Screens; -using osu.Game.Beatmaps; using osu.Game.Screens; using osu.Game.Screens.Play; @@ -21,23 +21,15 @@ namespace osu.Game.Tests.Visual.Gameplay InputManager.Add(stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }); } - [BackgroundDependencyLoader] - private void load(OsuGameBase game) + [Test] + public void TestLoadContinuation() { - Beatmap.Value = new DummyWorkingBeatmap(game); - AddStep("load dummy beatmap", () => stack.Push(loader = new PlayerLoader(() => new Player(false, false)))); - AddUntilStep("wait for current", () => loader.IsCurrentScreen()); - AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre)); - AddUntilStep("wait for no longer current", () => !loader.IsCurrentScreen()); - AddStep("exit loader", () => loader.Exit()); - AddUntilStep("wait for no longer alive", () => !loader.IsAlive); - AddStep("load slow dummy beatmap", () => { SlowLoadPlayer slow = null; From aa2c97b859eec9cc6778520a45b13bb5d1c21341 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 9 Apr 2019 15:05:03 +0900 Subject: [PATCH 43/54] Add mod reinstantiation testcase --- .../Visual/Gameplay/TestCasePlayerLoader.cs | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs index aba689b241..fba4aca343 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs @@ -1,11 +1,16 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; +using System.Linq; using System.Threading; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Screens; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Scoring; using osu.Game.Screens; using osu.Game.Screens.Play; @@ -42,6 +47,81 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for no longer current", () => !loader.IsCurrentScreen()); } + [Test] + public void TestModReinstantiation() + { + TestPlayer player = null; + TestMod gameMod = null; + TestMod playerMod1 = null; + TestMod playerMod2 = null; + + AddStep("load player", () => + { + SelectedMods.Value = new[] { gameMod = new TestMod() }; + InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre); + stack.Push(new PlayerLoader(() => player = new TestPlayer())); + }); + + AddUntilStep("wait for player to become current", () => + { + if (player.IsCurrentScreen()) + { + playerMod1 = (TestMod)player.SelectedMods.Value.Single(); + return true; + } + + return false; + }); + + AddAssert("game mods not applied", () => gameMod.Applied == false); + AddAssert("player mods applied", () => playerMod1.Applied); + + AddStep("restart player", () => + { + player = null; + player.Restart(); + }); + + AddUntilStep("wait for player to become current", () => + { + if (player.IsCurrentScreen()) + { + playerMod2 = (TestMod)player.SelectedMods.Value.Single(); + return true; + } + + return false; + }); + + AddAssert("game mods not applied", () => gameMod.Applied == false); + AddAssert("player has different mods", () => playerMod1 != playerMod2); + AddAssert("player mods applied", () => playerMod2.Applied); + } + + private class TestMod : Mod, IApplicableToScoreProcessor + { + public override string Name => string.Empty; + public override string Acronym => string.Empty; + public override double ScoreMultiplier => 1; + + public bool Applied { get; private set; } + + public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) + { + Applied = true; + } + } + + private class TestPlayer : Player + { + public new Bindable> SelectedMods => base.SelectedMods; + + public TestPlayer() + : base(false, false) + { + } + } + protected class SlowLoadPlayer : Player { public bool Ready; From ac2eabc9bfb8bf7c5d52b5b8a1f97ca37fc1c585 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 16 Apr 2019 17:47:00 +0900 Subject: [PATCH 44/54] Fix replay rewinding not respecting 60fps playback --- osu.Game/Rulesets/UI/FrameStabilityContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index deec2b8eac..c307520aca 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.UI { if (Math.Abs(manualClock.CurrentTime - newProposedTime) > sixty_frame_time * 1.2f) { - newProposedTime = manualClock.Rate > 0 + newProposedTime = newProposedTime > manualClock.CurrentTime ? Math.Min(newProposedTime, manualClock.CurrentTime + sixty_frame_time) : Math.Max(newProposedTime, manualClock.CurrentTime - sixty_frame_time); } From b684cd49e6fdd0233f91be155c1bdd182a76ddf7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Apr 2019 22:51:57 +0800 Subject: [PATCH 45/54] Update framework --- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 74ed9f91dd..1fcbe7c4c1 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -16,7 +16,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 9fff64c61c..831f33f0b8 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -105,8 +105,8 @@ - - + + From 5a3d6a02585b2d3b97e5846359e28a7b317cf6e3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Apr 2019 16:11:59 +0900 Subject: [PATCH 46/54] Fix post-merge errors --- osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs | 8 ++++---- osu.Game/Screens/Play/Player.cs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs index fba4aca343..f58c0d35b3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestCasePlayerLoader.cs @@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("load player", () => { - SelectedMods.Value = new[] { gameMod = new TestMod() }; + Mods.Value = new[] { gameMod = new TestMod() }; InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre); stack.Push(new PlayerLoader(() => player = new TestPlayer())); }); @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual.Gameplay { if (player.IsCurrentScreen()) { - playerMod1 = (TestMod)player.SelectedMods.Value.Single(); + playerMod1 = (TestMod)player.Mods.Value.Single(); return true; } @@ -86,7 +86,7 @@ namespace osu.Game.Tests.Visual.Gameplay { if (player.IsCurrentScreen()) { - playerMod2 = (TestMod)player.SelectedMods.Value.Single(); + playerMod2 = (TestMod)player.Mods.Value.Single(); return true; } @@ -114,7 +114,7 @@ namespace osu.Game.Tests.Visual.Gameplay private class TestPlayer : Player { - public new Bindable> SelectedMods => base.SelectedMods; + public new Bindable> Mods => base.Mods; public TestPlayer() : base(false, false) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index f8b3efb781..f833aa2bb7 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -71,8 +71,8 @@ namespace osu.Game.Screens.Play protected GameplayClockContainer GameplayClockContainer { get; private set; } [Cached] - [Cached(Type = typeof(IBindable>))] - protected readonly Bindable> SelectedMods = new Bindable>(Enumerable.Empty()); + [Cached(Type = typeof(IBindable>))] + protected readonly Bindable> Mods = new Bindable>(Array.Empty()); private readonly bool allowPause; private readonly bool showResults; @@ -93,7 +93,7 @@ namespace osu.Game.Screens.Play { this.api = api; - SelectedMods.Value = base.SelectedMods.Value.Select(m => m.CreateCopy()).ToArray(); + Mods.Value = base.Mods.Value.Select(m => m.CreateCopy()).ToArray(); WorkingBeatmap working = loadBeatmap(); From 9f92b3a8ba503940bbd559388149812086a4504f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Apr 2019 16:34:53 +0900 Subject: [PATCH 47/54] Add xmldoc --- osu.Game/Graphics/Containers/LogoTrackingContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs index 5ebdb7d45d..f139040abd 100644 --- a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs +++ b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs @@ -60,6 +60,9 @@ namespace osu.Game.Graphics.Containers startPosition = null; } + /// + /// Stops the logo assigned in from tracking the facade's position. + /// public void StopTracking() { if (Logo != null) From 3a1587fa53b53ce5490032469d8e19fce34d3f47 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Apr 2019 16:40:47 +0900 Subject: [PATCH 48/54] Throw exception when not relatively positioned --- osu.Game/Graphics/Containers/LogoTrackingContainer.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs index f139040abd..ddf257776f 100644 --- a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs +++ b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs @@ -92,12 +92,15 @@ namespace osu.Game.Graphics.Containers if (Logo == null) return; + if (Logo.RelativePositionAxes != Axes.Both) + throw new InvalidOperationException($"Tracking logo must have {nameof(RelativePositionAxes)} = Axes.Both"); + // Account for the scale of the actual OsuLogo, as SizeForFlow only accounts for the sprite scale. ((ExposedFacade)LogoFacade).SetSize(new Vector2(Logo.SizeForFlow * Logo.Scale.X)); var localPos = ComputeLogoTrackingPosition(); - if (LogoFacade.Parent != null && Logo.Position != localPos && Logo.RelativePositionAxes == Axes.Both) + if (LogoFacade.Parent != null && Logo.Position != localPos) { // If this is our first update since tracking has started, initialize our starting values for interpolation if (startTime == null || startPosition == null) From 4106da24303cf0289293d0d87ccc16fc4aee0b93 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Apr 2019 16:41:20 +0900 Subject: [PATCH 49/54] Rename facade + cleanup usage --- .../Graphics/Containers/LogoTrackingContainer.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs index ddf257776f..fb23038dde 100644 --- a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs +++ b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs @@ -15,22 +15,19 @@ namespace osu.Game.Graphics.Containers /// public class LogoTrackingContainer : Container { - public Facade LogoFacade { get; } + public Facade LogoFacade => facade; protected OsuLogo Logo { get; private set; } + private readonly InternalFacade facade = new InternalFacade(); + private Easing easing; private Vector2? startPosition; private double? startTime; private double duration; - public LogoTrackingContainer() - { - LogoFacade = new ExposedFacade(); - } - /// - /// Assign the logo that should track the Facade's position, as well as how it should transform to its initial position. + /// Assign the logo that should track the facade's position, as well as how it should transform to its initial position. /// /// The instance of the logo to be used for tracking. /// The scale of the facade. Does not actually affect the logo itself. @@ -96,7 +93,7 @@ namespace osu.Game.Graphics.Containers throw new InvalidOperationException($"Tracking logo must have {nameof(RelativePositionAxes)} = Axes.Both"); // Account for the scale of the actual OsuLogo, as SizeForFlow only accounts for the sprite scale. - ((ExposedFacade)LogoFacade).SetSize(new Vector2(Logo.SizeForFlow * Logo.Scale.X)); + facade.SetSize(new Vector2(Logo.SizeForFlow * Logo.Scale.X)); var localPos = ComputeLogoTrackingPosition(); @@ -133,7 +130,7 @@ namespace osu.Game.Graphics.Containers base.Dispose(isDisposing); } - private class ExposedFacade : Facade + private class InternalFacade : Facade { public void SetSize(Vector2 size) { From 897bfa60db361b01682be36b55640ed3bf4a4d9f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Apr 2019 17:02:47 +0900 Subject: [PATCH 50/54] Fix tracking position during 150ms state change delay --- osu.Game/Screens/Menu/ButtonArea.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Menu/ButtonArea.cs b/osu.Game/Screens/Menu/ButtonArea.cs index d6e1aef63c..eada1e0777 100644 --- a/osu.Game/Screens/Menu/ButtonArea.cs +++ b/osu.Game/Screens/Menu/ButtonArea.cs @@ -32,6 +32,7 @@ namespace osu.Game.Screens.Menu RelativeSizeAxes = Axes.X, Size = new Vector2(1, BUTTON_AREA_HEIGHT), Alpha = 0, + AlwaysPresent = true, // Always needs to be present for correct tracking on initial -> toplevel state change Children = new Drawable[] { buttonAreaBackground = new ButtonAreaBackground(), From 106e77c3d7794ab923380cbeb2cbe72c7b289741 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Apr 2019 17:15:23 +0900 Subject: [PATCH 51/54] Cleanup testcase --- .../TestCaseLogoTrackingContainer.cs | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs index 8b70a34c85..088a46d5e4 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs @@ -35,7 +35,6 @@ namespace osu.Game.Tests.Visual.UserInterface }; private OsuLogo logo; - private readonly Bindable uiScale = new Bindable(); private TestLogoTrackingContainer trackingContainer; private Container transferContainer; private Box visualBox; @@ -45,13 +44,6 @@ namespace osu.Game.Tests.Visual.UserInterface private const float visual_box_size = 72; - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) - { - config.BindWith(OsuSetting.UIScale, uiScale); - AddSliderStep("Adjust scale", 0.8f, 1.5f, 1f, v => uiScale.Value = v); - } - [SetUpSteps] public void SetUpSteps() { @@ -69,7 +61,7 @@ namespace osu.Game.Tests.Visual.UserInterface /// Check if the logo is still tracking the facade. /// [Test] - public void MoveFacadeTest() + public void TestMoveFacade() { AddToggleStep("Toggle move continuously", b => randomPositions = b); AddStep("Add tracking containers", addFacadeContainers); @@ -82,7 +74,7 @@ namespace osu.Game.Tests.Visual.UserInterface /// Check if the facade is removed from the container, the logo stops tracking. /// [Test] - public void RemoveFacadeTest() + public void TestRemoveFacade() { AddStep("Add tracking containers", addFacadeContainers); AddStep("Move facade to random position", moveLogoFacade); @@ -95,7 +87,7 @@ namespace osu.Game.Tests.Visual.UserInterface /// Check if the facade gets added to a new container, tracking starts on the new facade. /// [Test] - public void TransferFacadeTest() + public void TestTransferFacade() { AddStep("Add tracking containers", addFacadeContainers); AddStep("Move facade to random position", moveLogoFacade); @@ -106,6 +98,7 @@ namespace osu.Game.Tests.Visual.UserInterface transferContainerBox.Colour = Color4.Tomato; moveLogoFacade(); }); + waitForMove(); AddAssert("Logo is tracking", () => trackingContainer.IsLogoTracking); } @@ -114,7 +107,7 @@ namespace osu.Game.Tests.Visual.UserInterface /// Add a facade to a flow container, move the logo to the center of the screen, then start tracking on the facade. /// [Test] - public void FlowContainerTest() + public void TestFlowContainer() { FillFlowContainer flowContainer; @@ -188,14 +181,16 @@ namespace osu.Game.Tests.Visual.UserInterface } [Test] - public void SetFacadeSizeTest() + public void TestSetFacadeSize() { bool failed = false; + AddStep("Set up scenario", () => { failed = false; addFacadeContainers(); }); + AddStep("Try setting facade size", () => { try @@ -208,14 +203,16 @@ namespace osu.Game.Tests.Visual.UserInterface failed = true; } }); + AddAssert("Exception thrown", () => failed); } [Test] - public void SetMultipleContainersTest() + public void TestSetMultipleContainers() { bool failed = false; LogoTrackingContainer newContainer = new LogoTrackingContainer(); + AddStep("Set up scenario", () => { failed = false; @@ -223,6 +220,7 @@ namespace osu.Game.Tests.Visual.UserInterface addFacadeContainers(); moveLogoFacade(); }); + AddStep("Try tracking new container", () => { try @@ -235,6 +233,7 @@ namespace osu.Game.Tests.Visual.UserInterface failed = true; } }); + AddAssert("Exception thrown", () => failed); } From c145ce2d005ac723d1625fab276d23cc4384855d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Apr 2019 17:19:55 +0900 Subject: [PATCH 52/54] Remove usings --- .../Visual/UserInterface/TestCaseLogoTrackingContainer.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs index 088a46d5e4..e45e2e24da 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestCaseLogoTrackingContainer.cs @@ -4,15 +4,12 @@ using System; using System.Collections.Generic; using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.MathUtils; using osu.Framework.Testing; -using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; From 12b6bc48bd780a20b563f7c45cd9c8e5662e7c19 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Apr 2019 17:24:09 +0900 Subject: [PATCH 53/54] Use .With() wherever possible --- osu.Game/Screens/Menu/ButtonSystem.cs | 3 +-- osu.Game/Screens/Play/PlayerLoader.cs | 9 +++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index f6778691bf..519fadb34b 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -101,11 +101,10 @@ namespace osu.Game.Screens.Menu { VisibleState = ButtonSystemState.Play, }, - logoTrackingContainer.LogoFacade + logoTrackingContainer.LogoFacade.With(d => d.Scale = new Vector2(0.74f)) }); buttonArea.Flow.CentreTarget = logoTrackingContainer.LogoFacade; - logoTrackingContainer.LogoFacade.Scale = new Vector2(0.74f); } [Resolved(CanBeNull = true)] diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 7ff214c607..6a55fe278b 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -351,9 +351,6 @@ namespace osu.Game.Screens.Play { var metadata = beatmap.BeatmapInfo?.Metadata ?? new BeatmapMetadata(); - facade.Anchor = Anchor.TopCentre; - facade.Origin = Anchor.TopCentre; - AutoSizeAxes = Axes.Both; Children = new Drawable[] { @@ -365,7 +362,11 @@ namespace osu.Game.Screens.Play Direction = FillDirection.Vertical, Children = new[] { - facade, + facade.With(d => + { + d.Anchor = Anchor.TopCentre; + d.Origin = Anchor.TopCentre; + }), new OsuSpriteText { Text = new LocalisedString((metadata.TitleUnicode, metadata.Title)), From 4cf234295c67e05bc598299e70212bf55f7ceb9f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 19 Apr 2019 21:27:24 +0900 Subject: [PATCH 54/54] Fix appveyor temporarily --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 1f485485da..4dcaa7b45e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,6 @@ clone_depth: 1 version: '{branch}-{build}' -image: Visual Studio 2017 +image: Previous Visual Studio 2017 test: off install: - cmd: git submodule update --init --recursive --depth=5