Improve animation and sizing of maximised screen display

This commit is contained in:
Dean Herbert 2023-07-26 18:56:41 +09:00
parent 1826819663
commit 84bc14c1dd
2 changed files with 53 additions and 41 deletions

View File

@ -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
/// </summary>
public partial class PlayerGrid : CompositeDrawable
{
public const float ANIMATION_DELAY = 400;
/// <summary>
/// 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.
/// </summary>
public const int MAX_PLAYERS = 16;
private const float player_spacing = 5;
private const float player_spacing = 6;
/// <summary>
/// The currently-maximised facade.
/// </summary>
public Drawable MaximisedFacade => maximisedFacade;
public Facade MaximisedFacade { get; }
private readonly Facade maximisedFacade;
private readonly Container paddingContainer;
private readonly FillFlowContainer<Facade> facadeContainer;
private readonly Container<Cell> cellContainer;
@ -48,12 +50,18 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
RelativeSizeAxes = Axes.Both,
Child = facadeContainer = new FillFlowContainer<Facade>
{
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<Cell> { 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()

View File

@ -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);
}
/// <summary>
@ -66,30 +80,16 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
/// </summary>
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)
{