diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid.cs index 87072e8d9e..c88feb12bd 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { @@ -15,20 +16,21 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public partial class PlayerGrid : CompositeDrawable { + public const float ANIMATION_DELAY = 400; + /// /// A temporary limitation on the number of players, because only layouts up to 16 players are supported for a single screen. /// Todo: Can be removed in the future with scrolling support + performance improvements. /// public const int MAX_PLAYERS = 16; - private const float player_spacing = 5; + private const float player_spacing = 6; /// /// The currently-maximised facade. /// - public Drawable MaximisedFacade => maximisedFacade; + public Facade MaximisedFacade { get; } - private readonly Facade maximisedFacade; private readonly Container paddingContainer; private readonly FillFlowContainer facadeContainer; private readonly Container cellContainer; @@ -48,12 +50,18 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate RelativeSizeAxes = Axes.Both, Child = facadeContainer = new FillFlowContainer { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Spacing = new Vector2(player_spacing), } }, - maximisedFacade = new Facade { RelativeSizeAxes = Axes.Both } + MaximisedFacade = new Facade + { + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.8f), + } } }, cellContainer = new Container { RelativeSizeAxes = Axes.Both } @@ -91,26 +99,30 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private void toggleMaximisationState(Cell target) { - // Iterate through all cells to ensure only one is maximised at any time. - foreach (var i in cellContainer.ToList()) - { - if (i == target) - i.IsMaximised = !i.IsMaximised; - else - i.IsMaximised = false; + bool anyMaximised = target.IsMaximised = !target.IsMaximised; - if (i.IsMaximised) + // Iterate through all cells to ensure only one is maximised at any time. + foreach (var cell in cellContainer.ToList()) + { + if (cell != target) + cell.IsMaximised = false; + + if (cell.IsMaximised) { // Transfer cell to the maximised facade. - i.SetFacade(maximisedFacade); - cellContainer.ChangeChildDepth(i, maximisedInstanceDepth -= 0.001f); + cell.SetFacade(MaximisedFacade); + cellContainer.ChangeChildDepth(cell, maximisedInstanceDepth -= 0.001f); } else { // Transfer cell back to its original facade. - i.SetFacade(facadeContainer[i.FacadeIndex]); + cell.SetFacade(facadeContainer[cell.FacadeIndex]); } + + cell.FadeColour(anyMaximised && cell != target ? Color4.Gray : Color4.White, ANIMATION_DELAY, Easing.Out); } + + facadeContainer.ScaleTo(anyMaximised ? 0.95f : 1, ANIMATION_DELAY, Easing.OutQuint); } protected override void Update() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid_Cell.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid_Cell.cs index 4a8b8f49e1..d11e79d820 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid_Cell.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid_Cell.cs @@ -8,6 +8,7 @@ using JetBrains.Annotations; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; +using osu.Framework.Utils; using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate @@ -40,7 +41,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public bool IsMaximised; private Facade facade; - private bool isTracking = true; + + private bool isAnimating; public Cell(int facadeIndex, Drawable content) { @@ -54,11 +56,23 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { base.Update(); - if (isTracking) - { - Position = getFinalPosition(); - Size = getFinalSize(); - } + var targetPos = getFinalPosition(); + var targetSize = getFinalSize(); + + double duration = isAnimating ? 60 : 0; + + Position = new Vector2( + (float)Interpolation.DampContinuously(Position.X, targetPos.X, duration, Time.Elapsed), + (float)Interpolation.DampContinuously(Position.Y, targetPos.Y, duration, Time.Elapsed) + ); + + Size = new Vector2( + (float)Interpolation.DampContinuously(Size.X, targetSize.X, duration, Time.Elapsed), + (float)Interpolation.DampContinuously(Size.Y, targetSize.Y, duration, Time.Elapsed) + ); + + // If we don't track the animating state, the animation will also occur when resizing the window. + isAnimating &= !Precision.AlmostEquals(Position, targetPos, 0.01f); } /// @@ -66,30 +80,16 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public void SetFacade([NotNull] Facade newFacade) { - Facade lastFacade = facade; facade = newFacade; - - if (lastFacade == null || lastFacade == newFacade) - return; - - isTracking = false; - - this.MoveTo(getFinalPosition(), 400, Easing.OutQuint).ResizeTo(getFinalSize(), 400, Easing.OutQuint) - .Then() - .OnComplete(_ => - { - if (facade == newFacade) - isTracking = true; - }); + isAnimating = true; } - private Vector2 getFinalPosition() - { - var topLeft = Parent.ToLocalSpace(facade.ToScreenSpace(Vector2.Zero)); - return topLeft + facade.DrawSize / 2; - } + private Vector2 getFinalPosition() => + Parent.ToLocalSpace(facade.ScreenSpaceDrawQuad.Centre); - private Vector2 getFinalSize() => facade.DrawSize; + private Vector2 getFinalSize() => + Parent.ToLocalSpace(facade.ScreenSpaceDrawQuad.BottomRight) + - Parent.ToLocalSpace(facade.ScreenSpaceDrawQuad.TopLeft); protected override bool OnClick(ClickEvent e) {