From 0fdd50580714877b9214ae7aa5e8dc8d037fa8a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Sun, 20 Nov 2016 10:02:20 +0100 Subject: [PATCH 1/5] Add wedged background overlay to song select. --- osu-framework | 2 +- .../Backgrounds/BackgroundModeBeatmap.cs | 7 +- osu.Game/Screens/Play/PlaySongSelect.cs | 161 ++++++++++++++++-- 3 files changed, 152 insertions(+), 18 deletions(-) diff --git a/osu-framework b/osu-framework index 2a835c818c..a4f3010768 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 2a835c818ca17e725cc719360e01dbda0d95326a +Subproject commit a4f301076810571bebe9595af7aeaa3c77ac0c59 diff --git a/osu.Game/Screens/Backgrounds/BackgroundModeBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundModeBeatmap.cs index e1a2445245..649952ccfb 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundModeBeatmap.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundModeBeatmap.cs @@ -39,7 +39,7 @@ namespace osu.Game.Screens.Backgrounds { oldBackground.Depth = 1; oldBackground.Flush(); - oldBackground.FadeOut(500); + oldBackground.FadeOut(250); oldBackground.Expire(); background.BlurSigma = oldBackground.BlurSigma; @@ -63,11 +63,6 @@ namespace osu.Game.Screens.Backgrounds background?.BlurTo(sigma, duration, EasingTypes.OutExpo); } - protected override void Update() - { - base.Update(); - } - public override bool Equals(BackgroundMode other) { return base.Equals(other) && beatmap == ((BackgroundModeBeatmap)other).Beatmap; diff --git a/osu.Game/Screens/Play/PlaySongSelect.cs b/osu.Game/Screens/Play/PlaySongSelect.cs index 9a95e1eb55..073c0b4f3b 100644 --- a/osu.Game/Screens/Play/PlaySongSelect.cs +++ b/osu.Game/Screens/Play/PlaySongSelect.cs @@ -21,6 +21,7 @@ using osu.Game.Modes; using osu.Game.Screens.Backgrounds; using OpenTK; using OpenTK.Graphics; +using osu.Framework.Graphics.Colour; namespace osu.Game.Screens.Play { @@ -36,7 +37,13 @@ namespace osu.Game.Screens.Play private ScrollContainer scrollContainer; private FlowContainer beatmapSetFlow; private TrackManager trackManager; - private Container wedgeContainer; + private Container backgroundWedgesContainer; + + private static readonly Vector2 wedged_container_size = new Vector2(600, 300); + private static readonly Vector2 wedged_container_shear = new Vector2(0.15f, 0); + private static readonly Vector2 wedged_container_start_position = new Vector2(0, 50); + private Container wedgedContainer; + private Container wedgedBeatmapInfo; private static readonly Vector2 BACKGROUND_BLUR = new Vector2(20); @@ -49,11 +56,11 @@ namespace osu.Game.Screens.Play const float bottomToolHeight = 50; Children = new Drawable[] { - wedgeContainer = new Container + backgroundWedgesContainer = new Container { RelativeSizeAxes = Axes.Both, Size = Vector2.One, - Padding = new MarginPadding { Right = scrollWidth - 200 }, + Padding = new MarginPadding { Right = scrollWidth }, Children = new[] { new Box @@ -94,6 +101,26 @@ namespace osu.Game.Screens.Play } } }, + wedgedContainer = new Container + { + Position = wedged_container_start_position, + Size = wedged_container_size, + Margin = new MarginPadding { Top = 20, Right = 20, }, + Masking = true, + BorderColour = new Color4(221, 255, 255, 255), + BorderThickness = 2.5f, + EdgeEffect = new EdgeEffect + { + Type = EdgeEffectType.Glow, + Colour = new Color4(130, 204, 255, 150), + Radius = 20, + Roundness = 15, + }, + Shear = wedged_container_shear, + Children = new Drawable[] + { + }, + }, new Container { RelativeSizeAxes = Axes.X, @@ -152,14 +179,14 @@ namespace osu.Game.Screens.Play { base.OnEntering(last); ensurePlayingSelected(); - wedgeContainer.FadeInFromZero(250); + backgroundWedgesContainer.FadeInFromZero(250); - (Background as BackgroundModeBeatmap)?.BlurTo(BACKGROUND_BLUR, 1000); + changeBackground(Beatmap); } protected override void OnResuming(GameMode last) { - (Background as BackgroundModeBeatmap)?.BlurTo(BACKGROUND_BLUR, 1000); + changeBackground(Beatmap); ensurePlayingSelected(); base.OnResuming(last); @@ -176,12 +203,10 @@ namespace osu.Game.Screens.Play { } - /// - /// The global Beatmap was changed. - /// - protected override void OnBeatmapChanged(WorkingBeatmap beatmap) + private void changeBackground(WorkingBeatmap beatmap) { - base.OnBeatmapChanged(beatmap); + if (beatmap == null) + return; var backgroundModeBeatmap = Background as BackgroundModeBeatmap; if (backgroundModeBeatmap != null) @@ -191,6 +216,120 @@ namespace osu.Game.Screens.Play (Background as BackgroundModeBeatmap)?.BlurTo(BACKGROUND_BLUR, 1000); } + refreshWedgedBeatmapInfo(beatmap); + } + + private void refreshWedgedBeatmapInfo(WorkingBeatmap beatmap) + { + if (beatmap == null) + return; + + if (wedgedBeatmapInfo != null) + { + Drawable oldWedgedBeatmapInfo = wedgedBeatmapInfo; + oldWedgedBeatmapInfo.Depth = 1; + oldWedgedBeatmapInfo.FadeOut(250); + oldWedgedBeatmapInfo.Expire(); + } + + BeatmapSetInfo beatmapSetInfo = beatmap.BeatmapSetInfo; + BeatmapInfo beatmapInfo = beatmap.BeatmapInfo; + wedgedContainer.Add(wedgedBeatmapInfo = new BufferedContainer + { + PixelSnapping = true, + CacheDrawnFrameBuffer = true, + Shear = -wedged_container_shear, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + // We will create the white-to-black gradient by modulating transparency and having + // a black backdrop. This results in an sRGB-space gradient and not linear space, + // transitioning from white to black more perceptually uniformly. + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + // We use a container, such that we can set the colour gradient to go across the + // vertices of the masked container instead of the vertices of the (larger) sprite. + new Container + { + RelativeSizeAxes = Axes.Both, + ColourInfo = ColourInfo.GradientVertical(Color4.White, new Color4(1f, 1f, 1f, 0.3f)), + Children = new [] + { + // Zoomed-in and cropped beatmap background + new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Texture = beatmap.Background, + Scale = new Vector2(1366 / beatmap.Background.Width * 0.6f), + }, + }, + }, + // Text for beatmap info + new FlowContainer + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Direction = FlowDirection.VerticalOnly, + Margin = new MarginPadding { Top = 10, Left = 25, Right = 10, Bottom = 40 }, + AutoSizeAxes = Axes.Both, + Children = new[] + { + new SpriteText + { + Font = @"Exo2.0-MediumItalic", + Text = beatmapSetInfo.Metadata.Artist + " -- " + beatmapSetInfo.Metadata.Title, + TextSize = 28, + Shadow = true, + }, + new SpriteText + { + Font = @"Exo2.0-MediumItalic", + Text = beatmapInfo.Version, + TextSize = 17, + Shadow = true, + }, + new FlowContainer + { + Margin = new MarginPadding { Top = 10 }, + Direction = FlowDirection.HorizontalOnly, + AutoSizeAxes = Axes.Both, + Children = new [] + { + new SpriteText + { + Font = @"Exo2.0-Medium", + Text = "mapped by ", + TextSize = 15, + Shadow = true, + }, + new SpriteText + { + Font = @"Exo2.0-Bold", + Text = beatmapSetInfo.Metadata.Author, + TextSize = 15, + Shadow = true, + }, + } + } + } + } + } + }); + } + + /// + /// The global Beatmap was changed. + /// + protected override void OnBeatmapChanged(WorkingBeatmap beatmap) + { + base.OnBeatmapChanged(beatmap); + + changeBackground(beatmap); + selectBeatmap(beatmap.BeatmapInfo); } From 57e7c7097d4c98dc60a5f54c5ff822b3c5be5cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Sun, 20 Nov 2016 12:16:54 +0100 Subject: [PATCH 2/5] Update framework and add rudimentary fading to song select screen. --- osu-framework | 2 +- .../Tests/TestCaseGamefield.cs | 8 ++----- .../Tests/TestCaseHitObjects.cs | 12 ++++------ .../Tests/TestCaseMusicController.cs | 9 +++----- .../Tests/TestCasePlayer.cs | 10 ++------ osu.Game/Screens/Play/PlaySongSelect.cs | 23 ++++++++++++++++--- osu.Game/Screens/Play/Player.cs | 9 +++----- 7 files changed, 35 insertions(+), 38 deletions(-) diff --git a/osu-framework b/osu-framework index a4f3010768..8afa4fa7ae 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit a4f301076810571bebe9595af7aeaa3c77ac0c59 +Subproject commit 8afa4fa7ae9bbd5f357f859b1cc944c78286751a diff --git a/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs b/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs index 113e165d6a..14c44bbb43 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs @@ -27,16 +27,12 @@ namespace osu.Desktop.VisualTests.Tests public override string Description => @"Showing hitobjects and what not."; - FramedClock localClock; - - protected override IFrameBasedClock Clock => localClock; - public override void Reset() { base.Reset(); //ensure we are at offset 0 - localClock = new FramedClock(); + Clock = new FramedClock(); List objects = new List(); @@ -93,7 +89,7 @@ namespace osu.Desktop.VisualTests.Tests protected override void Update() { base.Update(); - localClock.ProcessFrame(); + Clock.ProcessFrame(); } } } diff --git a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs index 2ea43ab175..31a1bc369e 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs @@ -19,21 +19,17 @@ namespace osu.Desktop.VisualTests.Tests { public override string Name => @"Hit Objects"; - IFrameBasedClock ourClock; - - protected override IFrameBasedClock Clock => ourClock; - public TestCaseHitObjects() { var swClock = new StopwatchClock(true) { Rate = 1 }; - ourClock = new FramedClock(swClock); + Clock = new FramedClock(swClock); } public override void Reset() { base.Reset(); - ourClock.ProcessFrame(); + Clock.ProcessFrame(); Container approachContainer = new Container { Depth = float.MaxValue, }; @@ -45,7 +41,7 @@ namespace osu.Desktop.VisualTests.Tests { var h = new HitCircle { - StartTime = ourClock.CurrentTime + 1000 + i * 80, + StartTime = Clock.CurrentTime + 1000 + i * 80, Position = new Vector2((i - count / 2) * 14), }; @@ -65,7 +61,7 @@ namespace osu.Desktop.VisualTests.Tests protected override void Update() { base.Update(); - ourClock.ProcessFrame(); + Clock.ProcessFrame(); } } } diff --git a/osu.Desktop.VisualTests/Tests/TestCaseMusicController.cs b/osu.Desktop.VisualTests/Tests/TestCaseMusicController.cs index 72ab3b7a7f..2be742580a 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseMusicController.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseMusicController.cs @@ -13,20 +13,17 @@ namespace osu.Desktop.VisualTests.Tests public override string Name => @"Music Controller"; public override string Description => @"Tests music controller ui."; - IFrameBasedClock ourClock; - protected override IFrameBasedClock Clock => ourClock; - protected MusicController mc; public TestCaseMusicController() { - ourClock = new FramedClock(); + Clock = new FramedClock(); } public override void Reset() { base.Reset(); - ourClock.ProcessFrame(); + Clock.ProcessFrame(); mc = new MusicController { Origin = Anchor.Centre, @@ -39,7 +36,7 @@ namespace osu.Desktop.VisualTests.Tests protected override void Update() { base.Update(); - ourClock.ProcessFrame(); + Clock.ProcessFrame(); } } } diff --git a/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs b/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs index 5a89d4bc8d..da21b38ec8 100644 --- a/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs +++ b/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs @@ -8,8 +8,6 @@ using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; using OpenTK; -using osu.Framework; -using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using osu.Game.Modes.Objects; using osu.Game.Modes.Osu.Objects; @@ -24,16 +22,12 @@ namespace osu.Desktop.VisualTests.Tests public override string Description => @"Showing everything to play the game."; - FramedClock localClock; - - protected override IFrameBasedClock Clock => localClock; - public override void Reset() { base.Reset(); //ensure we are at offset 0 - localClock = new FramedClock(); + Clock = new FramedClock(); var objects = new List(); @@ -75,7 +69,7 @@ namespace osu.Desktop.VisualTests.Tests protected override void Update() { base.Update(); - localClock.ProcessFrame(); + Clock.ProcessFrame(); } } } diff --git a/osu.Game/Screens/Play/PlaySongSelect.cs b/osu.Game/Screens/Play/PlaySongSelect.cs index 073c0b4f3b..9d5eca8bb3 100644 --- a/osu.Game/Screens/Play/PlaySongSelect.cs +++ b/osu.Game/Screens/Play/PlaySongSelect.cs @@ -103,6 +103,7 @@ namespace osu.Game.Screens.Play }, wedgedContainer = new Container { + Alpha = 0, Position = wedged_container_start_position, Size = wedged_container_size, Margin = new MarginPadding { Top = 20, Right = 20, }, @@ -179,17 +180,31 @@ namespace osu.Game.Screens.Play { base.OnEntering(last); ensurePlayingSelected(); - backgroundWedgesContainer.FadeInFromZero(250); changeBackground(Beatmap); + + Content.FadeInFromZero(250); } protected override void OnResuming(GameMode last) { changeBackground(Beatmap); - ensurePlayingSelected(); base.OnResuming(last); + + Content.FadeIn(250); + } + + protected override void OnSuspending(GameMode next) + { + Content.FadeOut(250); + base.OnSuspending(next); + } + + protected override bool OnExiting(GameMode next) + { + Content.FadeOut(100); + return base.OnExiting(next); } protected override void Dispose(bool isDisposing) @@ -232,6 +247,8 @@ namespace osu.Game.Screens.Play oldWedgedBeatmapInfo.Expire(); } + wedgedContainer.FadeIn(250); + BeatmapSetInfo beatmapSetInfo = beatmap.BeatmapSetInfo; BeatmapInfo beatmapInfo = beatmap.BeatmapInfo; wedgedContainer.Add(wedgedBeatmapInfo = new BufferedContainer @@ -252,7 +269,7 @@ namespace osu.Game.Screens.Play }, // We use a container, such that we can set the colour gradient to go across the // vertices of the masked container instead of the vertices of the (larger) sprite. - new Container + beatmap.Background == null ? new Container() : new Container { RelativeSizeAxes = Axes.Both, ColourInfo = ColourInfo.GradientVertical(Color4.White, new Color4(1f, 1f, 1f, 0.3f)), diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index c4641b9b6a..90abf55421 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -32,10 +32,7 @@ namespace osu.Game.Screens.Play public BeatmapInfo BeatmapInfo; public PlayMode PreferredPlayMode; - - protected override IFrameBasedClock Clock => playerClock; - - private InterpolatingFramedClock playerClock; + private IAdjustableClock sourceClock; private Ruleset ruleset; @@ -64,7 +61,7 @@ namespace osu.Game.Screens.Play } sourceClock = (IAdjustableClock)track ?? new StopwatchClock(); - playerClock = new InterpolatingFramedClock(sourceClock); + Clock = new InterpolatingFramedClock(sourceClock); Schedule(() => { @@ -118,7 +115,7 @@ namespace osu.Game.Screens.Play protected override void Update() { base.Update(); - playerClock.ProcessFrame(); + Clock.ProcessFrame(); } class PlayerInputManager : UserInputManager From 40805ad32c6907268217c0ec71edcddfbdf618a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Sun, 20 Nov 2016 12:29:38 +0100 Subject: [PATCH 3/5] Adjust size of wedged background overlay. --- osu.Game/Screens/Play/PlaySongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlaySongSelect.cs b/osu.Game/Screens/Play/PlaySongSelect.cs index 9d5eca8bb3..9c0db0e0bb 100644 --- a/osu.Game/Screens/Play/PlaySongSelect.cs +++ b/osu.Game/Screens/Play/PlaySongSelect.cs @@ -39,7 +39,7 @@ namespace osu.Game.Screens.Play private TrackManager trackManager; private Container backgroundWedgesContainer; - private static readonly Vector2 wedged_container_size = new Vector2(600, 300); + private static readonly Vector2 wedged_container_size = new Vector2(700, 225); private static readonly Vector2 wedged_container_shear = new Vector2(0.15f, 0); private static readonly Vector2 wedged_container_start_position = new Vector2(0, 50); private Container wedgedContainer; From c6d688898f54413c0e3f33b643f9f7d9ab199564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Sun, 20 Nov 2016 20:34:16 +0100 Subject: [PATCH 4/5] Initial implementation of a beatmap carousell and various minor improvements to song select. No big optimizations yet, but groundwork is laid out. --- osu-framework | 2 +- .../Tests/TestCasePlaySongSelect.cs | 2 +- osu.Game/Beatmaps/Drawable/BeatmapGroup.cs | 66 +++------- osu.Game/Beatmaps/Drawable/BeatmapPanel.cs | 17 ++- .../Beatmaps/Drawable/BeatmapSetHeader.cs | 81 +++++++++--- osu.Game/Beatmaps/Drawable/Panel.cs | 30 +++-- osu.Game/Screens/Menu/MainMenu.cs | 1 + osu.Game/Screens/Multiplayer/Match.cs | 1 + osu.Game/Screens/Select/CarousellContainer.cs | 124 ++++++++++++++++++ .../{Edit => Select}/EditSongSelect.cs | 3 +- .../MatchSongSelect.cs | 2 +- .../{Play => Select}/PlaySongSelect.cs | 94 +++---------- osu.Game/osu.Game.csproj | 7 +- 13 files changed, 268 insertions(+), 162 deletions(-) create mode 100644 osu.Game/Screens/Select/CarousellContainer.cs rename osu.Game/Screens/{Edit => Select}/EditSongSelect.cs (86%) rename osu.Game/Screens/{Multiplayer => Select}/MatchSongSelect.cs (87%) rename osu.Game/Screens/{Play => Select}/PlaySongSelect.cs (81%) diff --git a/osu-framework b/osu-framework index 8afa4fa7ae..611037f88b 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 8afa4fa7ae9bbd5f357f859b1cc944c78286751a +Subproject commit 611037f88bd2e64e40ca1a3a385c14fd0a012bf2 diff --git a/osu.Desktop.VisualTests/Tests/TestCasePlaySongSelect.cs b/osu.Desktop.VisualTests/Tests/TestCasePlaySongSelect.cs index d6e656e57f..244982ded3 100644 --- a/osu.Desktop.VisualTests/Tests/TestCasePlaySongSelect.cs +++ b/osu.Desktop.VisualTests/Tests/TestCasePlaySongSelect.cs @@ -6,7 +6,7 @@ using osu.Desktop.VisualTests.Platform; using osu.Framework.GameModes.Testing; using osu.Game.Database; using osu.Game.Modes; -using osu.Game.Screens.Play; +using osu.Game.Screens.Select; namespace osu.Desktop.VisualTests.Tests { diff --git a/osu.Game/Beatmaps/Drawable/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawable/BeatmapGroup.cs index c66a6ad259..2dc4218d39 100644 --- a/osu.Game/Beatmaps/Drawable/BeatmapGroup.cs +++ b/osu.Game/Beatmaps/Drawable/BeatmapGroup.cs @@ -17,7 +17,7 @@ using osu.Framework.Allocation; namespace osu.Game.Beatmaps.Drawable { - class BeatmapGroup : Container, IStateful + class BeatmapGroup : IStateful { public BeatmapPanel SelectedPanel; @@ -27,8 +27,7 @@ namespace osu.Game.Beatmaps.Drawable public Action SelectionChanged; private BeatmapSetInfo beatmapSet; - private BeatmapSetHeader header; - private FlowContainer difficulties; + public BeatmapSetHeader Header; private BeatmapGroupState state; @@ -43,24 +42,24 @@ namespace osu.Game.Beatmaps.Drawable switch (state) { case BeatmapGroupState.Expanded: - FadeTo(1, 250); - //if (!difficulties.Children.All(d => IsLoaded)) // Task.WhenAll(difficulties.Children.Select(d => d.Preload(Game))).ContinueWith(t => difficulties.Show()); //else - difficulties.Show(); + foreach (BeatmapPanel panel in BeatmapPanels) + panel.Show(); - header.State = PanelSelectedState.Selected; + Header.State = PanelSelectedState.Selected; if (SelectedPanel != null) SelectedPanel.State = PanelSelectedState.Selected; break; case BeatmapGroupState.Collapsed: - FadeTo(0.8f, 250); - - header.State = PanelSelectedState.NotSelected; + Header.State = PanelSelectedState.NotSelected; if (SelectedPanel != null) SelectedPanel.State = PanelSelectedState.NotSelected; - difficulties.Hide(); + + foreach (BeatmapPanel panel in BeatmapPanels) + panel.Hide(); + break; } } @@ -70,54 +69,21 @@ namespace osu.Game.Beatmaps.Drawable { this.beatmapSet = beatmapSet; - Alpha = 0; - AutoSizeAxes = Axes.Y; - RelativeSizeAxes = Axes.X; - - Children = new[] + Header = new BeatmapSetHeader(beatmapSet, working) { - new FlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FlowDirection.VerticalOnly, - Children = new Framework.Graphics.Drawable[] - { - header = new BeatmapSetHeader(beatmapSet, working) - { - GainedSelection = headerGainedSelection, - RelativeSizeAxes = Axes.X, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - }, - difficulties = new FlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Top = 5 }, - Padding = new MarginPadding { Left = 75 }, - Spacing = new Vector2(0, 5), - Direction = FlowDirection.VerticalOnly, - } - } - } + GainedSelection = headerGainedSelection, + RelativeSizeAxes = Axes.X, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, }; - } - [BackgroundDependencyLoader] - private void load(BaseGame game) - { BeatmapPanels = beatmapSet.Beatmaps.Select(b => new BeatmapPanel(b) { GainedSelection = panelGainedSelection, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, RelativeSizeAxes = Axes.X, - }).ToList(); - - //for the time being, let's completely load the difficulty panels in the background. - //this likely won't scale so well, but allows us to completely async the loading flow. - Task.WhenAll(BeatmapPanels.Select(panel => panel.Preload(game, p => difficulties.Add(panel)))).Wait(); + }).ToList(); } private void headerGainedSelection(BeatmapSetHeader panel) diff --git a/osu.Game/Beatmaps/Drawable/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawable/BeatmapPanel.cs index 7641afd25d..920538f935 100644 --- a/osu.Game/Beatmaps/Drawable/BeatmapPanel.cs +++ b/osu.Game/Beatmaps/Drawable/BeatmapPanel.cs @@ -11,12 +11,14 @@ using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using OpenTK; using OpenTK.Graphics; +using osu.Framework.Graphics.Colour; namespace osu.Game.Beatmaps.Drawable { class BeatmapPanel : Panel { public BeatmapInfo Beatmap; + private Sprite background; public Action GainedSelection; @@ -24,6 +26,17 @@ namespace osu.Game.Beatmaps.Drawable { base.Selected(); GainedSelection?.Invoke(this); + + background.ColourInfo = ColourInfo.GradientVertical( + new Color4(20, 43, 51, 255), + new Color4(40, 86, 102, 255)); + } + + protected override void Deselected() + { + base.Deselected(); + + background.Colour = new Color4(20, 43, 51, 255); } public BeatmapPanel(BeatmapInfo beatmap) @@ -33,11 +46,9 @@ namespace osu.Game.Beatmaps.Drawable Children = new Framework.Graphics.Drawable[] { - new Box + background = new Box { - Colour = new Color4(40, 86, 102, 255), // TODO: gradient RelativeSizeAxes = Axes.Both, - Size = Vector2.One, }, new FlowContainer { diff --git a/osu.Game/Beatmaps/Drawable/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawable/BeatmapSetHeader.cs index 38b0e57812..e42a6271c6 100644 --- a/osu.Game/Beatmaps/Drawable/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawable/BeatmapSetHeader.cs @@ -10,10 +10,10 @@ using osu.Game.Database; using osu.Game.Graphics; using OpenTK; using OpenTK.Graphics; -using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Game.Configuration; +using osu.Framework.Graphics.Colour; namespace osu.Game.Beatmaps.Drawable { @@ -28,15 +28,13 @@ namespace osu.Game.Beatmaps.Drawable protected override void Selected() { base.Selected(); - - Width = 1; + GainedSelection?.Invoke(this); } protected override void Deselected() { base.Deselected(); - Width = 0.8f; } [BackgroundDependencyLoader] @@ -66,36 +64,83 @@ namespace osu.Game.Beatmaps.Drawable this.beatmapSet = beatmapSet; Children = new Framework.Graphics.Drawable[] { - working.Background == null ? new Box{ RelativeSizeAxes = Axes.Both, Colour = new Color4(20, 20, 20, 255) } : new Sprite - { - Texture = working.Background, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(1366 / working.Background.Width * 0.6f), - Colour = new Color4(200, 200, 200, 255), + new BufferedContainer + { + CacheDrawnFrameBuffer = true, + RelativeSizeAxes = Axes.Both, + Children = new Framework.Graphics.Drawable[] + { + working.Background == null ? new Box{ RelativeSizeAxes = Axes.Both, Colour = new Color4(200, 200, 200, 255) } : new Sprite + { + Texture = working.Background, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(1366 / working.Background.Width * 0.6f), + }, + new FlowContainer + { + Direction = FlowDirection.HorizontalOnly, + RelativeSizeAxes = Axes.Both, + // This makes the gradient not be perfectly horizontal, but diagonal at a ~40° angle + Shear = new Vector2(0.8f, 0), + Alpha = 0.5f, + Children = new[] + { + // The left half with no gradient applied + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Width = 0.4f, + }, + // Piecewise-linear gradient with 3 segments to make it appear smoother + new Box + { + RelativeSizeAxes = Axes.Both, + ColourInfo = ColourInfo.GradientHorizontal(Color4.Black, new Color4(0f, 0f, 0f, 0.9f)), + Width = 0.05f, + }, + new Box + { + RelativeSizeAxes = Axes.Both, + ColourInfo = ColourInfo.GradientHorizontal(new Color4(0f, 0f, 0f, 0.9f), new Color4(0f, 0f, 0f, 0.1f)), + Width = 0.2f, + }, + new Box + { + RelativeSizeAxes = Axes.Both, + ColourInfo = ColourInfo.GradientHorizontal(new Color4(0f, 0f, 0f, 0.1f), new Color4(0, 0, 0, 0)), + Width = 0.05f, + }, + } + }, + } }, new FlowContainer { Direction = FlowDirection.VerticalOnly, - Spacing = new Vector2(0, 2), - Padding = new MarginPadding { Top = 10, Left = 15, Right = 10, Bottom = 10 }, + Padding = new MarginPadding { Top = 5, Left = 18, Right = 10, Bottom = 10 }, AutoSizeAxes = Axes.Both, Children = new[] { title = new SpriteText { - Font = @"Exo2.0-SemiBoldItalic", + Font = @"Exo2.0-BoldItalic", Text = beatmapSet.Metadata.Title, - TextSize = 22 + TextSize = 22, + Shadow = true, }, artist = new SpriteText { - Font = @"Exo2.0-MediumItalic", + Margin = new MarginPadding { Top = -1 }, + Font = @"Exo2.0-SemiBoldItalic", Text = beatmapSet.Metadata.Artist, - TextSize = 16 + TextSize = 17, + Shadow = true, }, new FlowContainer { + Margin = new MarginPadding { Top = 5 }, AutoSizeAxes = Axes.Both, Children = new[] { @@ -106,8 +151,6 @@ namespace osu.Game.Beatmaps.Drawable } } }; - - Deselected(); } } } \ No newline at end of file diff --git a/osu.Game/Beatmaps/Drawable/Panel.cs b/osu.Game/Beatmaps/Drawable/Panel.cs index 5e77e152ff..c51ef629de 100644 --- a/osu.Game/Beatmaps/Drawable/Panel.cs +++ b/osu.Game/Beatmaps/Drawable/Panel.cs @@ -26,8 +26,26 @@ namespace osu.Game.Beatmaps.Drawable BorderColour = new Color4(221, 255, 255, 255); RelativeSizeAxes = Axes.X; + } - Deselected(); + protected override void LoadComplete() + { + base.LoadComplete(); + applyState(); + FadeInFromZero(250); + } + + private void applyState() + { + switch (state) + { + case PanelSelectedState.NotSelected: + Deselected(); + break; + case PanelSelectedState.Selected: + Selected(); + break; + } } private PanelSelectedState state = PanelSelectedState.NotSelected; @@ -41,15 +59,7 @@ namespace osu.Game.Beatmaps.Drawable if (state == value) return; state = value; - switch (state) - { - case PanelSelectedState.NotSelected: - Deselected(); - break; - case PanelSelectedState.Selected: - Selected(); - break; - } + applyState(); } } diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 055a4baf9d..a6f8b51536 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -15,6 +15,7 @@ using osu.Game.Screens.Edit; using osu.Game.Screens.Multiplayer; using osu.Game.Screens.Play; using OpenTK; +using osu.Game.Screens.Select; namespace osu.Game.Screens.Menu { diff --git a/osu.Game/Screens/Multiplayer/Match.cs b/osu.Game/Screens/Multiplayer/Match.cs index 11d9ef4b8e..eea998e554 100644 --- a/osu.Game/Screens/Multiplayer/Match.cs +++ b/osu.Game/Screens/Multiplayer/Match.cs @@ -7,6 +7,7 @@ using osu.Framework.GameModes; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Play; using OpenTK.Graphics; +using osu.Game.Screens.Select; namespace osu.Game.Screens.Multiplayer { diff --git a/osu.Game/Screens/Select/CarousellContainer.cs b/osu.Game/Screens/Select/CarousellContainer.cs new file mode 100644 index 0000000000..4bde7838b2 --- /dev/null +++ b/osu.Game/Screens/Select/CarousellContainer.cs @@ -0,0 +1,124 @@ +//Copyright (c) 2007-2016 ppy Pty Ltd . +//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using osu.Framework.Caching; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Game.Beatmaps.Drawable; +using osu.Game.Database; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace osu.Game.Screens.Select +{ + class CarousellContainer : ScrollContainer + { + private Container scrollableContent; + private List groups = new List(); + public BeatmapGroup SelectedGroup { get; private set; } + + private Cached yPositions = new Cached(); + + public CarousellContainer() + { + Add(scrollableContent = new Container + { + Padding = new MarginPadding { Left = 25, Top = 25, Bottom = 25 }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }); + } + + public void AddGroup(BeatmapGroup group) + { + group.State = BeatmapGroupState.Collapsed; + + groups.Add(group); + + yPositions.Invalidate(); + } + + private void computeYPositions() + { + float currentY = 0; + foreach (BeatmapGroup group in groups) + { + group.Header.Position = new Vector2(group.Header.Position.X, currentY); + currentY += group.Header.DrawSize.Y + 5; + + if (group.State == BeatmapGroupState.Expanded) + { + foreach (BeatmapPanel panel in group.BeatmapPanels) + { + panel.Position = new Vector2(panel.Position.X, currentY); + currentY += panel.DrawSize.Y + 5; + } + } + } + } + + public void SelectBeatmap(BeatmapInfo beatmap) + { + foreach (BeatmapGroup group in groups) + { + var panel = group.BeatmapPanels.FirstOrDefault(p => p.Beatmap.Equals(beatmap)); + if (panel != null) + SelectGroup(group, panel); + } + } + + public void SelectGroup(BeatmapGroup group, BeatmapPanel panel) + { + if (SelectedGroup != null && SelectedGroup != group) + SelectedGroup.State = BeatmapGroupState.Collapsed; + + SelectedGroup = group; + panel.State = PanelSelectedState.Selected; + + yPositions.Invalidate(); + } + + protected override void UpdateLayout() + { + base.UpdateLayout(); + + if (!yPositions.EnsureValid()) + yPositions.Refresh(computeYPositions); + } + + protected override void Update() + { + base.Update(); + + scrollableContent.Clear(false); + + foreach (BeatmapGroup group in groups) + { + scrollableContent.Add(group.Header); + + if (group.State == BeatmapGroupState.Expanded) + foreach (BeatmapPanel panel in group.BeatmapPanels) + scrollableContent.Add(panel); + } + + foreach (Panel panel in scrollableContent.Children) + { + if (panel.Position.Y < 0) + continue; + + Vector2 panelPosLocal = panel.Position; + Vector2 panelPos = panel.ToSpaceOfOtherDrawable(panel.DrawSize / 2.0f, this); + + float halfHeight = DrawSize.Y / 2; + float dist = Math.Abs(panelPos.Y - halfHeight); + panel.Position = new Vector2( + (panel is BeatmapSetHeader && panel.State == PanelSelectedState.Selected ? 0 : 100) + dist * 0.1f, panelPosLocal.Y); + + panel.Alpha = MathHelper.Clamp(1.75f - 1.5f * dist / halfHeight, 0, 1); + } + } + } +} diff --git a/osu.Game/Screens/Edit/EditSongSelect.cs b/osu.Game/Screens/Select/EditSongSelect.cs similarity index 86% rename from osu.Game/Screens/Edit/EditSongSelect.cs rename to osu.Game/Screens/Select/EditSongSelect.cs index 323a92f3b5..df55719f9c 100644 --- a/osu.Game/Screens/Edit/EditSongSelect.cs +++ b/osu.Game/Screens/Select/EditSongSelect.cs @@ -4,8 +4,9 @@ using System; using System.Collections.Generic; using osu.Game.Screens.Backgrounds; +using osu.Game.Screens.Edit; -namespace osu.Game.Screens.Edit +namespace osu.Game.Screens.Select { class EditSongSelect : GameModeWhiteBox { diff --git a/osu.Game/Screens/Multiplayer/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs similarity index 87% rename from osu.Game/Screens/Multiplayer/MatchSongSelect.cs rename to osu.Game/Screens/Select/MatchSongSelect.cs index 442dea9f30..7735e70b55 100644 --- a/osu.Game/Screens/Multiplayer/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -3,7 +3,7 @@ using osu.Game.Screens.Backgrounds; -namespace osu.Game.Screens.Multiplayer +namespace osu.Game.Screens.Select { class MatchSongSelect : GameModeWhiteBox { diff --git a/osu.Game/Screens/Play/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs similarity index 81% rename from osu.Game/Screens/Play/PlaySongSelect.cs rename to osu.Game/Screens/Select/PlaySongSelect.cs index 9c0db0e0bb..f259b28bcf 100644 --- a/osu.Game/Screens/Play/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -22,20 +22,17 @@ using osu.Game.Screens.Backgrounds; using OpenTK; using OpenTK.Graphics; using osu.Framework.Graphics.Colour; +using osu.Game.Screens.Play; -namespace osu.Game.Screens.Play +namespace osu.Game.Screens.Select { public class PlaySongSelect : OsuGameMode { private Bindable playMode; private BeatmapDatabase database; - private BeatmapGroup selectedBeatmapGroup; - private BeatmapInfo selectedBeatmapInfo; - protected override BackgroundMode CreateBackground() => new BackgroundModeBeatmap(Beatmap); - private ScrollContainer scrollContainer; - private FlowContainer beatmapSetFlow; + private CarousellContainer carousell; private TrackManager trackManager; private Container backgroundWedgesContainer; @@ -83,23 +80,12 @@ namespace osu.Game.Screens.Play }, } }, - scrollContainer = new ScrollContainer + carousell = new CarousellContainer { RelativeSizeAxes = Axes.Y, Size = new Vector2(scrollWidth, 1), Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Children = new Drawable[] - { - beatmapSetFlow = new FlowContainer - { - Padding = new MarginPadding { Left = 25, Top = 25, Bottom = 25 + bottomToolHeight }, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FlowDirection.VerticalOnly, - Spacing = new Vector2(0, 5), - } - } }, wedgedContainer = new Container { @@ -146,7 +132,7 @@ namespace osu.Game.Screens.Play Colour = new Color4(238, 51, 153, 255), Action = () => Push(new Player { - BeatmapInfo = selectedBeatmapGroup.SelectedPanel.Beatmap, + BeatmapInfo = carousell.SelectedGroup.SelectedPanel.Beatmap, PreferredPlayMode = playMode.Value }) }, @@ -163,17 +149,17 @@ namespace osu.Game.Screens.Play playMode = game.PlayMode; playMode.ValueChanged += playMode_ValueChanged; // Temporary: - scrollContainer.Padding = new MarginPadding { Top = ToolbarPadding }; + carousell.Padding = new MarginPadding { Top = ToolbarPadding }; } if (database == null) database = beatmaps; - database.BeatmapSetAdded += s => Schedule(() => addBeatmapSet(s)); + database.BeatmapSetAdded += s => Schedule(() => addBeatmapSet(s, game)); trackManager = audio.Track; - Task.Factory.StartNew(addBeatmapSets); + Task.Factory.StartNew(() => addBeatmapSets(game)); } protected override void OnEntering(GameMode last) @@ -352,21 +338,7 @@ namespace osu.Game.Screens.Play private void selectBeatmap(BeatmapInfo beatmap) { - if (beatmap.Equals(selectedBeatmapInfo)) - return; - - //this is VERY temporary logic. - beatmapSetFlow.Children.Cast().Any(b => - { - var panel = b.BeatmapPanels.FirstOrDefault(p => p.Beatmap.Equals(beatmap)); - if (panel != null) - { - panel.State = PanelSelectedState.Selected; - return true; - } - - return false; - }); + carousell.SelectBeatmap(beatmap); } /// @@ -374,22 +346,10 @@ namespace osu.Game.Screens.Play /// private void selectionChanged(BeatmapGroup group, BeatmapInfo beatmap) { - selectedBeatmapInfo = beatmap; - if (!beatmap.Equals(Beatmap?.BeatmapInfo)) - { Beatmap = database.GetWorkingBeatmap(beatmap, Beatmap); - } ensurePlayingSelected(); - - if (selectedBeatmapGroup == group) - return; - - if (selectedBeatmapGroup != null) - selectedBeatmapGroup.State = BeatmapGroupState.Collapsed; - - selectedBeatmapGroup = group; } private async Task ensurePlayingSelected() @@ -408,7 +368,7 @@ namespace osu.Game.Screens.Play }); } - private void addBeatmapSet(BeatmapSetInfo beatmapSet) + private void addBeatmapSet(BeatmapSetInfo beatmapSet, OsuGame game) { beatmapSet = database.GetWithChildren(beatmapSet.BeatmapSetID); beatmapSet.Beatmaps.ForEach(b => database.GetChildren(b)); @@ -418,39 +378,27 @@ namespace osu.Game.Screens.Play var group = new BeatmapGroup(beatmapSet, working) { SelectionChanged = selectionChanged }; - group.Preload(Game, g => + //for the time being, let's completely load the difficulty panels in the background. + //this likely won't scale so well, but allows us to completely async the loading flow. + Task.WhenAll(group.BeatmapPanels.Select(panel => panel.Preload(game))).ContinueWith(task => Schedule(delegate { - beatmapSetFlow.Add(group); + carousell.AddGroup(group); if (Beatmap == null) - { - if (beatmapSetFlow.Children.Count() == 1) - { - group.State = BeatmapGroupState.Expanded; - return; - } - } + carousell.SelectBeatmap(beatmapSet.Beatmaps.First()); else { - if (selectedBeatmapInfo?.Equals(Beatmap.BeatmapInfo) != true) - { - var panel = group.BeatmapPanels.FirstOrDefault(p => p.Beatmap.Equals(Beatmap.BeatmapInfo)); - if (panel != null) - { - panel.State = PanelSelectedState.Selected; - return; - } - } + var panel = group.BeatmapPanels.FirstOrDefault(p => p.Beatmap.Equals(Beatmap.BeatmapInfo)); + if (panel != null) + carousell.SelectGroup(group, panel); } - - group.State = BeatmapGroupState.Collapsed; - }); + })); } - private void addBeatmapSets() + private void addBeatmapSets(OsuGame game) { foreach (var beatmapSet in database.Query()) - addBeatmapSet(beatmapSet); + addBeatmapSet(beatmapSet, game); } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8df8917e06..d193f6dd8a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -103,7 +103,8 @@ - + + @@ -114,11 +115,11 @@ - + - + From 318fe2f9d6af04ce1444a6fc64b5a25d0f52ebc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Sun, 20 Nov 2016 20:43:43 +0100 Subject: [PATCH 5/5] Fix broken VisualTests SongSelect. --- osu.Game/Screens/Select/PlaySongSelect.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index f259b28bcf..d5b66d5bd7 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -23,6 +23,7 @@ using OpenTK; using OpenTK.Graphics; using osu.Framework.Graphics.Colour; using osu.Game.Screens.Play; +using osu.Framework; namespace osu.Game.Screens.Select { @@ -142,11 +143,11 @@ namespace osu.Game.Screens.Select } [BackgroundDependencyLoader(permitNulls: true)] - private void load(BeatmapDatabase beatmaps, AudioManager audio, OsuGame game) + private void load(BeatmapDatabase beatmaps, AudioManager audio, BaseGame game, OsuGame osuGame) { - if (game != null) + if (osuGame != null) { - playMode = game.PlayMode; + playMode = osuGame.PlayMode; playMode.ValueChanged += playMode_ValueChanged; // Temporary: carousell.Padding = new MarginPadding { Top = ToolbarPadding }; @@ -368,7 +369,7 @@ namespace osu.Game.Screens.Select }); } - private void addBeatmapSet(BeatmapSetInfo beatmapSet, OsuGame game) + private void addBeatmapSet(BeatmapSetInfo beatmapSet, BaseGame game) { beatmapSet = database.GetWithChildren(beatmapSet.BeatmapSetID); beatmapSet.Beatmaps.ForEach(b => database.GetChildren(b)); @@ -395,7 +396,7 @@ namespace osu.Game.Screens.Select })); } - private void addBeatmapSets(OsuGame game) + private void addBeatmapSets(BaseGame game) { foreach (var beatmapSet in database.Query()) addBeatmapSet(beatmapSet, game);