1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-15 16:03:01 +08:00

Merge remote-tracking branch 'refs/remotes/Tom94/song-select-wedged-box'

# Conflicts:
#	osu-framework
This commit is contained in:
Dean Herbert 2016-11-21 12:07:07 +09:00
commit ac8c180168
20 changed files with 667 additions and 429 deletions

@ -1 +1 @@
Subproject commit 37d53e32e58104c8e743efad855019c39edeb6b2 Subproject commit 9ed3a191bf76ead6ff34ac468898a0119b8e5454

View File

@ -27,16 +27,12 @@ namespace osu.Desktop.VisualTests.Tests
public override string Description => @"Showing hitobjects and what not."; public override string Description => @"Showing hitobjects and what not.";
FramedClock localClock;
protected override IFrameBasedClock Clock => localClock;
public override void Reset() public override void Reset()
{ {
base.Reset(); base.Reset();
//ensure we are at offset 0 //ensure we are at offset 0
localClock = new FramedClock(); Clock = new FramedClock();
List<HitObject> objects = new List<HitObject>(); List<HitObject> objects = new List<HitObject>();
@ -93,7 +89,7 @@ namespace osu.Desktop.VisualTests.Tests
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
localClock.ProcessFrame(); Clock.ProcessFrame();
} }
} }
} }

View File

@ -19,21 +19,17 @@ namespace osu.Desktop.VisualTests.Tests
{ {
public override string Name => @"Hit Objects"; public override string Name => @"Hit Objects";
IFrameBasedClock ourClock;
protected override IFrameBasedClock Clock => ourClock;
public TestCaseHitObjects() public TestCaseHitObjects()
{ {
var swClock = new StopwatchClock(true) { Rate = 1 }; var swClock = new StopwatchClock(true) { Rate = 1 };
ourClock = new FramedClock(swClock); Clock = new FramedClock(swClock);
} }
public override void Reset() public override void Reset()
{ {
base.Reset(); base.Reset();
ourClock.ProcessFrame(); Clock.ProcessFrame();
Container approachContainer = new Container { Depth = float.MaxValue, }; Container approachContainer = new Container { Depth = float.MaxValue, };
@ -45,7 +41,7 @@ namespace osu.Desktop.VisualTests.Tests
{ {
var h = new HitCircle var h = new HitCircle
{ {
StartTime = ourClock.CurrentTime + 1000 + i * 80, StartTime = Clock.CurrentTime + 1000 + i * 80,
Position = new Vector2((i - count / 2) * 14), Position = new Vector2((i - count / 2) * 14),
}; };
@ -65,7 +61,7 @@ namespace osu.Desktop.VisualTests.Tests
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
ourClock.ProcessFrame(); Clock.ProcessFrame();
} }
} }
} }

View File

@ -13,20 +13,17 @@ namespace osu.Desktop.VisualTests.Tests
public override string Name => @"Music Controller"; public override string Name => @"Music Controller";
public override string Description => @"Tests music controller ui."; public override string Description => @"Tests music controller ui.";
IFrameBasedClock ourClock;
protected override IFrameBasedClock Clock => ourClock;
protected MusicController mc; protected MusicController mc;
public TestCaseMusicController() public TestCaseMusicController()
{ {
ourClock = new FramedClock(); Clock = new FramedClock();
} }
public override void Reset() public override void Reset()
{ {
base.Reset(); base.Reset();
ourClock.ProcessFrame(); Clock.ProcessFrame();
mc = new MusicController mc = new MusicController
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -39,7 +36,7 @@ namespace osu.Desktop.VisualTests.Tests
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
ourClock.ProcessFrame(); Clock.ProcessFrame();
} }
} }
} }

View File

@ -6,7 +6,7 @@ using osu.Desktop.VisualTests.Platform;
using osu.Framework.GameModes.Testing; using osu.Framework.GameModes.Testing;
using osu.Game.Database; using osu.Game.Database;
using osu.Game.Modes; using osu.Game.Modes;
using osu.Game.Screens.Play; using osu.Game.Screens.Select;
namespace osu.Desktop.VisualTests.Tests namespace osu.Desktop.VisualTests.Tests
{ {

View File

@ -8,8 +8,6 @@ using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Formats;
using OpenTK; using OpenTK;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Modes.Objects; using osu.Game.Modes.Objects;
using osu.Game.Modes.Osu.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."; public override string Description => @"Showing everything to play the game.";
FramedClock localClock;
protected override IFrameBasedClock Clock => localClock;
public override void Reset() public override void Reset()
{ {
base.Reset(); base.Reset();
//ensure we are at offset 0 //ensure we are at offset 0
localClock = new FramedClock(); Clock = new FramedClock();
var objects = new List<HitObject>(); var objects = new List<HitObject>();
@ -75,7 +69,7 @@ namespace osu.Desktop.VisualTests.Tests
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
localClock.ProcessFrame(); Clock.ProcessFrame();
} }
} }
} }

View File

@ -17,7 +17,7 @@ using osu.Framework.Allocation;
namespace osu.Game.Beatmaps.Drawable namespace osu.Game.Beatmaps.Drawable
{ {
class BeatmapGroup : Container, IStateful<BeatmapGroupState> class BeatmapGroup : IStateful<BeatmapGroupState>
{ {
public BeatmapPanel SelectedPanel; public BeatmapPanel SelectedPanel;
@ -27,8 +27,7 @@ namespace osu.Game.Beatmaps.Drawable
public Action<BeatmapGroup, BeatmapInfo> SelectionChanged; public Action<BeatmapGroup, BeatmapInfo> SelectionChanged;
private BeatmapSetInfo beatmapSet; private BeatmapSetInfo beatmapSet;
private BeatmapSetHeader header; public BeatmapSetHeader Header;
private FlowContainer difficulties;
private BeatmapGroupState state; private BeatmapGroupState state;
@ -43,24 +42,24 @@ namespace osu.Game.Beatmaps.Drawable
switch (state) switch (state)
{ {
case BeatmapGroupState.Expanded: case BeatmapGroupState.Expanded:
FadeTo(1, 250);
//if (!difficulties.Children.All(d => IsLoaded)) //if (!difficulties.Children.All(d => IsLoaded))
// Task.WhenAll(difficulties.Children.Select(d => d.Preload(Game))).ContinueWith(t => difficulties.Show()); // Task.WhenAll(difficulties.Children.Select(d => d.Preload(Game))).ContinueWith(t => difficulties.Show());
//else //else
difficulties.Show(); foreach (BeatmapPanel panel in BeatmapPanels)
panel.Show();
header.State = PanelSelectedState.Selected; Header.State = PanelSelectedState.Selected;
if (SelectedPanel != null) if (SelectedPanel != null)
SelectedPanel.State = PanelSelectedState.Selected; SelectedPanel.State = PanelSelectedState.Selected;
break; break;
case BeatmapGroupState.Collapsed: case BeatmapGroupState.Collapsed:
FadeTo(0.8f, 250); Header.State = PanelSelectedState.NotSelected;
header.State = PanelSelectedState.NotSelected;
if (SelectedPanel != null) if (SelectedPanel != null)
SelectedPanel.State = PanelSelectedState.NotSelected; SelectedPanel.State = PanelSelectedState.NotSelected;
difficulties.Hide();
foreach (BeatmapPanel panel in BeatmapPanels)
panel.Hide();
break; break;
} }
} }
@ -70,54 +69,21 @@ namespace osu.Game.Beatmaps.Drawable
{ {
this.beatmapSet = beatmapSet; this.beatmapSet = beatmapSet;
Alpha = 0; Header = new BeatmapSetHeader(beatmapSet, working)
AutoSizeAxes = Axes.Y;
RelativeSizeAxes = Axes.X;
Children = new[]
{ {
new FlowContainer GainedSelection = headerGainedSelection,
{ RelativeSizeAxes = Axes.X,
RelativeSizeAxes = Axes.X, Anchor = Anchor.TopRight,
AutoSizeAxes = Axes.Y, Origin = Anchor.TopRight,
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,
}
}
}
}; };
}
[BackgroundDependencyLoader]
private void load(BaseGame game)
{
BeatmapPanels = beatmapSet.Beatmaps.Select(b => new BeatmapPanel(b) BeatmapPanels = beatmapSet.Beatmaps.Select(b => new BeatmapPanel(b)
{ {
GainedSelection = panelGainedSelection, GainedSelection = panelGainedSelection,
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
}).ToList(); }).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();
} }
private void headerGainedSelection(BeatmapSetHeader panel) private void headerGainedSelection(BeatmapSetHeader panel)

View File

@ -11,12 +11,14 @@ using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Graphics.Colour;
namespace osu.Game.Beatmaps.Drawable namespace osu.Game.Beatmaps.Drawable
{ {
class BeatmapPanel : Panel class BeatmapPanel : Panel
{ {
public BeatmapInfo Beatmap; public BeatmapInfo Beatmap;
private Sprite background;
public Action<BeatmapPanel> GainedSelection; public Action<BeatmapPanel> GainedSelection;
@ -24,6 +26,17 @@ namespace osu.Game.Beatmaps.Drawable
{ {
base.Selected(); base.Selected();
GainedSelection?.Invoke(this); 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) public BeatmapPanel(BeatmapInfo beatmap)
@ -33,11 +46,9 @@ namespace osu.Game.Beatmaps.Drawable
Children = new Framework.Graphics.Drawable[] Children = new Framework.Graphics.Drawable[]
{ {
new Box background = new Box
{ {
Colour = new Color4(40, 86, 102, 255), // TODO: gradient
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Size = Vector2.One,
}, },
new FlowContainer new FlowContainer
{ {

View File

@ -10,10 +10,10 @@ using osu.Game.Database;
using osu.Game.Graphics; using osu.Game.Graphics;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Framework.Graphics.Colour;
namespace osu.Game.Beatmaps.Drawable namespace osu.Game.Beatmaps.Drawable
{ {
@ -28,15 +28,13 @@ namespace osu.Game.Beatmaps.Drawable
protected override void Selected() protected override void Selected()
{ {
base.Selected(); base.Selected();
Width = 1;
GainedSelection?.Invoke(this); GainedSelection?.Invoke(this);
} }
protected override void Deselected() protected override void Deselected()
{ {
base.Deselected(); base.Deselected();
Width = 0.8f;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -66,36 +64,83 @@ namespace osu.Game.Beatmaps.Drawable
this.beatmapSet = beatmapSet; this.beatmapSet = beatmapSet;
Children = new Framework.Graphics.Drawable[] Children = new Framework.Graphics.Drawable[]
{ {
working.Background == null ? new Box{ RelativeSizeAxes = Axes.Both, Colour = new Color4(20, 20, 20, 255) } : new Sprite new BufferedContainer
{ {
Texture = working.Background, CacheDrawnFrameBuffer = true,
Anchor = Anchor.Centre, RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre, Children = new Framework.Graphics.Drawable[]
Scale = new Vector2(1366 / working.Background.Width * 0.6f), {
Colour = new Color4(200, 200, 200, 255), 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 new FlowContainer
{ {
Direction = FlowDirection.VerticalOnly, Direction = FlowDirection.VerticalOnly,
Spacing = new Vector2(0, 2), Padding = new MarginPadding { Top = 5, Left = 18, Right = 10, Bottom = 10 },
Padding = new MarginPadding { Top = 10, Left = 15, Right = 10, Bottom = 10 },
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Children = new[] Children = new[]
{ {
title = new SpriteText title = new SpriteText
{ {
Font = @"Exo2.0-SemiBoldItalic", Font = @"Exo2.0-BoldItalic",
Text = beatmapSet.Metadata.Title, Text = beatmapSet.Metadata.Title,
TextSize = 22 TextSize = 22,
Shadow = true,
}, },
artist = new SpriteText artist = new SpriteText
{ {
Font = @"Exo2.0-MediumItalic", Margin = new MarginPadding { Top = -1 },
Font = @"Exo2.0-SemiBoldItalic",
Text = beatmapSet.Metadata.Artist, Text = beatmapSet.Metadata.Artist,
TextSize = 16 TextSize = 17,
Shadow = true,
}, },
new FlowContainer new FlowContainer
{ {
Margin = new MarginPadding { Top = 5 },
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Children = new[] Children = new[]
{ {
@ -106,8 +151,6 @@ namespace osu.Game.Beatmaps.Drawable
} }
} }
}; };
Deselected();
} }
} }
} }

View File

@ -26,8 +26,26 @@ namespace osu.Game.Beatmaps.Drawable
BorderColour = new Color4(221, 255, 255, 255); BorderColour = new Color4(221, 255, 255, 255);
RelativeSizeAxes = Axes.X; 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; private PanelSelectedState state = PanelSelectedState.NotSelected;
@ -41,15 +59,7 @@ namespace osu.Game.Beatmaps.Drawable
if (state == value) return; if (state == value) return;
state = value; state = value;
switch (state) applyState();
{
case PanelSelectedState.NotSelected:
Deselected();
break;
case PanelSelectedState.Selected:
Selected();
break;
}
} }
} }

View File

@ -39,7 +39,7 @@ namespace osu.Game.Screens.Backgrounds
{ {
oldBackground.Depth = 1; oldBackground.Depth = 1;
oldBackground.Flush(); oldBackground.Flush();
oldBackground.FadeOut(500); oldBackground.FadeOut(250);
oldBackground.Expire(); oldBackground.Expire();
background.BlurSigma = oldBackground.BlurSigma; background.BlurSigma = oldBackground.BlurSigma;
@ -63,11 +63,6 @@ namespace osu.Game.Screens.Backgrounds
background?.BlurTo(sigma, duration, EasingTypes.OutExpo); background?.BlurTo(sigma, duration, EasingTypes.OutExpo);
} }
protected override void Update()
{
base.Update();
}
public override bool Equals(BackgroundMode other) public override bool Equals(BackgroundMode other)
{ {
return base.Equals(other) && beatmap == ((BackgroundModeBeatmap)other).Beatmap; return base.Equals(other) && beatmap == ((BackgroundModeBeatmap)other).Beatmap;

View File

@ -15,6 +15,7 @@ using osu.Game.Screens.Edit;
using osu.Game.Screens.Multiplayer; using osu.Game.Screens.Multiplayer;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using OpenTK; using OpenTK;
using osu.Game.Screens.Select;
namespace osu.Game.Screens.Menu namespace osu.Game.Screens.Menu
{ {

View File

@ -7,6 +7,7 @@ using osu.Framework.GameModes;
using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Backgrounds;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Game.Screens.Select;
namespace osu.Game.Screens.Multiplayer namespace osu.Game.Screens.Multiplayer
{ {

View File

@ -1,300 +0,0 @@
//Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Configuration;
using osu.Framework.GameModes;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawable;
using osu.Game.Database;
using osu.Game.Modes;
using osu.Game.Screens.Backgrounds;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Screens.Play
{
public class PlaySongSelect : OsuGameMode
{
private Bindable<PlayMode> playMode;
private BeatmapDatabase database;
private BeatmapGroup selectedBeatmapGroup;
private BeatmapInfo selectedBeatmapInfo;
protected override BackgroundMode CreateBackground() => new BackgroundModeBeatmap(Beatmap);
private ScrollContainer scrollContainer;
private FlowContainer beatmapSetFlow;
private TrackManager trackManager;
private Container wedgeContainer;
private static readonly Vector2 BACKGROUND_BLUR = new Vector2(20);
/// <param name="database">Optionally provide a database to use instead of the OsuGame one.</param>
public PlaySongSelect(BeatmapDatabase database = null)
{
this.database = database;
const float scrollWidth = 640;
const float bottomToolHeight = 50;
Children = new Drawable[]
{
wedgeContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Size = Vector2.One,
Padding = new MarginPadding { Right = scrollWidth - 200 },
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Size = new Vector2(1, 0.5f),
Colour = new Color4(0, 0, 0, 0.5f),
Shear = new Vector2(0.15f, 0),
EdgeSmoothness = new Vector2(2, 0),
},
new Box
{
RelativeSizeAxes = Axes.Both,
RelativePositionAxes = Axes.Y,
Size = new Vector2(1, -0.5f),
Position = new Vector2(0, 1),
Colour = new Color4(0, 0, 0, 0.5f),
Shear = new Vector2(-0.15f, 0),
EdgeSmoothness = new Vector2(2, 0),
},
}
},
scrollContainer = new ScrollContainer
{
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),
}
}
},
new Container
{
RelativeSizeAxes = Axes.X,
Height = bottomToolHeight,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Size = Vector2.One,
Colour = new Color4(0, 0, 0, 0.5f),
},
new Button
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
RelativeSizeAxes = Axes.Y,
Width = 100,
Text = "Play",
Colour = new Color4(238, 51, 153, 255),
Action = () => Push(new Player
{
BeatmapInfo = selectedBeatmapGroup.SelectedPanel.Beatmap,
PreferredPlayMode = playMode.Value
})
},
}
}
};
}
[BackgroundDependencyLoader(permitNulls: true)]
private void load(BeatmapDatabase beatmaps, AudioManager audio, OsuGame game)
{
if (game != null)
{
playMode = game.PlayMode;
playMode.ValueChanged += playMode_ValueChanged;
// Temporary:
scrollContainer.Padding = new MarginPadding { Top = ToolbarPadding };
}
if (database == null)
database = beatmaps;
database.BeatmapSetAdded += s => Schedule(() => addBeatmapSet(s));
trackManager = audio.Track;
Task.Factory.StartNew(addBeatmapSets);
}
protected override void OnEntering(GameMode last)
{
base.OnEntering(last);
ensurePlayingSelected();
wedgeContainer.FadeInFromZero(250);
(Background as BackgroundModeBeatmap)?.BlurTo(BACKGROUND_BLUR, 1000);
}
protected override void OnResuming(GameMode last)
{
(Background as BackgroundModeBeatmap)?.BlurTo(BACKGROUND_BLUR, 1000);
ensurePlayingSelected();
base.OnResuming(last);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (playMode != null)
playMode.ValueChanged -= playMode_ValueChanged;
}
private void playMode_ValueChanged(object sender, EventArgs e)
{
}
/// <summary>
/// The global Beatmap was changed.
/// </summary>
protected override void OnBeatmapChanged(WorkingBeatmap beatmap)
{
base.OnBeatmapChanged(beatmap);
var backgroundModeBeatmap = Background as BackgroundModeBeatmap;
if (backgroundModeBeatmap != null)
{
backgroundModeBeatmap.Beatmap = beatmap;
// TODO: Remove this once we have non-nullable Beatmap
(Background as BackgroundModeBeatmap)?.BlurTo(BACKGROUND_BLUR, 1000);
}
selectBeatmap(beatmap.BeatmapInfo);
}
private void selectBeatmap(BeatmapInfo beatmap)
{
if (beatmap.Equals(selectedBeatmapInfo))
return;
//this is VERY temporary logic.
beatmapSetFlow.Children.Cast<BeatmapGroup>().Any(b =>
{
var panel = b.BeatmapPanels.FirstOrDefault(p => p.Beatmap.Equals(beatmap));
if (panel != null)
{
panel.State = PanelSelectedState.Selected;
return true;
}
return false;
});
}
/// <summary>
/// selection has been changed as the result of interaction with the carousel.
/// </summary>
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()
{
AudioTrack track = null;
await Task.Run(() => track = Beatmap?.Track);
Schedule(delegate
{
if (track != null)
{
trackManager.SetExclusive(track);
track.Start();
}
});
}
private void addBeatmapSet(BeatmapSetInfo beatmapSet)
{
beatmapSet = database.GetWithChildren<BeatmapSetInfo>(beatmapSet.BeatmapSetID);
beatmapSet.Beatmaps.ForEach(b => database.GetChildren(b));
beatmapSet.Beatmaps = beatmapSet.Beatmaps.OrderBy(b => b.BaseDifficulty.OverallDifficulty).ToList();
var working = database.GetWorkingBeatmap(beatmapSet.Beatmaps.FirstOrDefault());
var group = new BeatmapGroup(beatmapSet, working) { SelectionChanged = selectionChanged };
group.Preload(Game, g =>
{
beatmapSetFlow.Add(group);
if (Beatmap == null)
{
if (beatmapSetFlow.Children.Count() == 1)
{
group.State = BeatmapGroupState.Expanded;
return;
}
}
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;
}
}
}
group.State = BeatmapGroupState.Collapsed;
});
}
private void addBeatmapSets()
{
foreach (var beatmapSet in database.Query<BeatmapSetInfo>())
addBeatmapSet(beatmapSet);
}
}
}

View File

@ -32,10 +32,7 @@ namespace osu.Game.Screens.Play
public BeatmapInfo BeatmapInfo; public BeatmapInfo BeatmapInfo;
public PlayMode PreferredPlayMode; public PlayMode PreferredPlayMode;
protected override IFrameBasedClock Clock => playerClock;
private InterpolatingFramedClock playerClock;
private IAdjustableClock sourceClock; private IAdjustableClock sourceClock;
private Ruleset ruleset; private Ruleset ruleset;
@ -64,7 +61,7 @@ namespace osu.Game.Screens.Play
} }
sourceClock = (IAdjustableClock)track ?? new StopwatchClock(); sourceClock = (IAdjustableClock)track ?? new StopwatchClock();
playerClock = new InterpolatingFramedClock(sourceClock); Clock = new InterpolatingFramedClock(sourceClock);
Schedule(() => Schedule(() =>
{ {
@ -118,7 +115,7 @@ namespace osu.Game.Screens.Play
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
playerClock.ProcessFrame(); Clock.ProcessFrame();
} }
class PlayerInputManager : UserInputManager class PlayerInputManager : UserInputManager

View File

@ -0,0 +1,124 @@
//Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
//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<Panel> scrollableContent;
private List<BeatmapGroup> groups = new List<BeatmapGroup>();
public BeatmapGroup SelectedGroup { get; private set; }
private Cached yPositions = new Cached();
public CarousellContainer()
{
Add(scrollableContent = new Container<Panel>
{
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);
}
}
}
}

View File

@ -4,8 +4,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Backgrounds;
using osu.Game.Screens.Edit;
namespace osu.Game.Screens.Edit namespace osu.Game.Screens.Select
{ {
class EditSongSelect : GameModeWhiteBox class EditSongSelect : GameModeWhiteBox
{ {

View File

@ -3,7 +3,7 @@
using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Backgrounds;
namespace osu.Game.Screens.Multiplayer namespace osu.Game.Screens.Select
{ {
class MatchSongSelect : GameModeWhiteBox class MatchSongSelect : GameModeWhiteBox
{ {

View File

@ -0,0 +1,405 @@
//Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Configuration;
using osu.Framework.GameModes;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawable;
using osu.Game.Database;
using osu.Game.Modes;
using osu.Game.Screens.Backgrounds;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Game.Screens.Play;
using osu.Framework;
namespace osu.Game.Screens.Select
{
public class PlaySongSelect : OsuGameMode
{
private Bindable<PlayMode> playMode;
private BeatmapDatabase database;
protected override BackgroundMode CreateBackground() => new BackgroundModeBeatmap(Beatmap);
private CarousellContainer carousell;
private TrackManager trackManager;
private Container backgroundWedgesContainer;
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;
private Container wedgedBeatmapInfo;
private static readonly Vector2 BACKGROUND_BLUR = new Vector2(20);
/// <param name="database">Optionally provide a database to use instead of the OsuGame one.</param>
public PlaySongSelect(BeatmapDatabase database = null)
{
this.database = database;
const float scrollWidth = 640;
const float bottomToolHeight = 50;
Children = new Drawable[]
{
backgroundWedgesContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Size = Vector2.One,
Padding = new MarginPadding { Right = scrollWidth },
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Size = new Vector2(1, 0.5f),
Colour = new Color4(0, 0, 0, 0.5f),
Shear = new Vector2(0.15f, 0),
EdgeSmoothness = new Vector2(2, 0),
},
new Box
{
RelativeSizeAxes = Axes.Both,
RelativePositionAxes = Axes.Y,
Size = new Vector2(1, -0.5f),
Position = new Vector2(0, 1),
Colour = new Color4(0, 0, 0, 0.5f),
Shear = new Vector2(-0.15f, 0),
EdgeSmoothness = new Vector2(2, 0),
},
}
},
carousell = new CarousellContainer
{
RelativeSizeAxes = Axes.Y,
Size = new Vector2(scrollWidth, 1),
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
},
wedgedContainer = new Container
{
Alpha = 0,
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,
Height = bottomToolHeight,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Size = Vector2.One,
Colour = new Color4(0, 0, 0, 0.5f),
},
new Button
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
RelativeSizeAxes = Axes.Y,
Width = 100,
Text = "Play",
Colour = new Color4(238, 51, 153, 255),
Action = () => Push(new Player
{
BeatmapInfo = carousell.SelectedGroup.SelectedPanel.Beatmap,
PreferredPlayMode = playMode.Value
})
},
}
}
};
}
[BackgroundDependencyLoader(permitNulls: true)]
private void load(BeatmapDatabase beatmaps, AudioManager audio, BaseGame game, OsuGame osuGame)
{
if (osuGame != null)
{
playMode = osuGame.PlayMode;
playMode.ValueChanged += playMode_ValueChanged;
// Temporary:
carousell.Padding = new MarginPadding { Top = ToolbarPadding };
}
if (database == null)
database = beatmaps;
database.BeatmapSetAdded += s => Schedule(() => addBeatmapSet(s, game));
trackManager = audio.Track;
Task.Factory.StartNew(() => addBeatmapSets(game));
}
protected override void OnEntering(GameMode last)
{
base.OnEntering(last);
ensurePlayingSelected();
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)
{
base.Dispose(isDisposing);
if (playMode != null)
playMode.ValueChanged -= playMode_ValueChanged;
}
private void playMode_ValueChanged(object sender, EventArgs e)
{
}
private void changeBackground(WorkingBeatmap beatmap)
{
if (beatmap == null)
return;
var backgroundModeBeatmap = Background as BackgroundModeBeatmap;
if (backgroundModeBeatmap != null)
{
backgroundModeBeatmap.Beatmap = beatmap;
// TODO: Remove this once we have non-nullable Beatmap
(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();
}
wedgedContainer.FadeIn(250);
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.
beatmap.Background == null ? new Container() : 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,
},
}
}
}
}
}
});
}
/// <summary>
/// The global Beatmap was changed.
/// </summary>
protected override void OnBeatmapChanged(WorkingBeatmap beatmap)
{
base.OnBeatmapChanged(beatmap);
changeBackground(beatmap);
selectBeatmap(beatmap.BeatmapInfo);
}
private void selectBeatmap(BeatmapInfo beatmap)
{
carousell.SelectBeatmap(beatmap);
}
/// <summary>
/// selection has been changed as the result of interaction with the carousel.
/// </summary>
private void selectionChanged(BeatmapGroup group, BeatmapInfo beatmap)
{
if (!beatmap.Equals(Beatmap?.BeatmapInfo))
Beatmap = database.GetWorkingBeatmap(beatmap, Beatmap);
ensurePlayingSelected();
}
private async Task ensurePlayingSelected()
{
AudioTrack track = null;
await Task.Run(() => track = Beatmap?.Track);
Schedule(delegate
{
if (track != null)
{
trackManager.SetExclusive(track);
track.Start();
}
});
}
private void addBeatmapSet(BeatmapSetInfo beatmapSet, BaseGame game)
{
beatmapSet = database.GetWithChildren<BeatmapSetInfo>(beatmapSet.BeatmapSetID);
beatmapSet.Beatmaps.ForEach(b => database.GetChildren(b));
beatmapSet.Beatmaps = beatmapSet.Beatmaps.OrderBy(b => b.BaseDifficulty.OverallDifficulty).ToList();
var working = database.GetWorkingBeatmap(beatmapSet.Beatmaps.FirstOrDefault());
var group = new BeatmapGroup(beatmapSet, working) { SelectionChanged = selectionChanged };
//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
{
carousell.AddGroup(group);
if (Beatmap == null)
carousell.SelectBeatmap(beatmapSet.Beatmaps.First());
else
{
var panel = group.BeatmapPanels.FirstOrDefault(p => p.Beatmap.Equals(Beatmap.BeatmapInfo));
if (panel != null)
carousell.SelectGroup(group, panel);
}
}));
}
private void addBeatmapSets(BaseGame game)
{
foreach (var beatmapSet in database.Query<BeatmapSetInfo>())
addBeatmapSet(beatmapSet, game);
}
}
}

View File

@ -103,7 +103,8 @@
<Compile Include="Screens\Multiplayer\Lobby.cs" /> <Compile Include="Screens\Multiplayer\Lobby.cs" />
<Compile Include="Screens\Multiplayer\Match.cs" /> <Compile Include="Screens\Multiplayer\Match.cs" />
<Compile Include="Screens\Multiplayer\MatchCreate.cs" /> <Compile Include="Screens\Multiplayer\MatchCreate.cs" />
<Compile Include="Screens\Multiplayer\MatchSongSelect.cs" /> <Compile Include="Screens\Select\CarousellContainer.cs" />
<Compile Include="Screens\Select\MatchSongSelect.cs" />
<Compile Include="Screens\OsuGameMode.cs" /> <Compile Include="Screens\OsuGameMode.cs" />
<Compile Include="Screens\Play\ModSelect.cs" /> <Compile Include="Screens\Play\ModSelect.cs" />
<Compile Include="Beatmaps\Drawable\BeatmapGroup.cs" /> <Compile Include="Beatmaps\Drawable\BeatmapGroup.cs" />
@ -114,11 +115,11 @@
<Compile Include="Modes\Ruleset.cs" /> <Compile Include="Modes\Ruleset.cs" />
<Compile Include="Screens\Ranking\Results.cs" /> <Compile Include="Screens\Ranking\Results.cs" />
<Compile Include="Screens\Direct\OnlineListing.cs" /> <Compile Include="Screens\Direct\OnlineListing.cs" />
<Compile Include="Screens\Play\PlaySongSelect.cs" /> <Compile Include="Screens\Select\PlaySongSelect.cs" />
<Compile Include="Modes\UI\HitRenderer.cs" /> <Compile Include="Modes\UI\HitRenderer.cs" />
<Compile Include="Modes\UI\Playfield.cs" /> <Compile Include="Modes\UI\Playfield.cs" />
<Compile Include="Modes\UI\ScoreOverlay.cs" /> <Compile Include="Modes\UI\ScoreOverlay.cs" />
<Compile Include="Screens\Edit\EditSongSelect.cs" /> <Compile Include="Screens\Select\EditSongSelect.cs" />
<Compile Include="Modes\UI\ComboCounter.cs" /> <Compile Include="Modes\UI\ComboCounter.cs" />
<Compile Include="Modes\UI\ComboResultCounter.cs" /> <Compile Include="Modes\UI\ComboResultCounter.cs" />
<Compile Include="Graphics\UserInterface\RollingCounter.cs" /> <Compile Include="Graphics\UserInterface\RollingCounter.cs" />