mirror of
https://github.com/ppy/osu.git
synced 2026-06-03 06:09:54 +08:00
Merge pull request #35053 from smoogipoo/matchmaking-player-list-modes
Add display styles to matchmaking player list
This commit is contained in:
@@ -53,6 +53,20 @@ namespace osu.Game.Tests.Visual.Matchmaking
|
||||
|
||||
WaitForJoined();
|
||||
|
||||
AddStep("join users", () =>
|
||||
{
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
MultiplayerClient.AddUser(new MultiplayerRoomUser(i)
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
Username = $"User {i}"
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
setupRequestHandler();
|
||||
|
||||
AddStep("load match", () =>
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
@@ -80,7 +81,7 @@ namespace osu.Game.Tests.Visual.Matchmaking
|
||||
|
||||
PickScreen screen = null!;
|
||||
|
||||
AddStep("add screen", () => LoadScreen(screen = new PickScreen()));
|
||||
AddStep("add screen", () => Child = new ScreenStack(screen = new PickScreen()));
|
||||
|
||||
AddStep("select maps", () =>
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking;
|
||||
using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Idle;
|
||||
using osu.Game.Screens.OnlinePlay.Matchmaking;
|
||||
using osu.Game.Tests.Visual.Multiplayer;
|
||||
using osu.Game.Users;
|
||||
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking;
|
||||
using osu.Game.Screens.OnlinePlay.Matchmaking;
|
||||
using osu.Game.Tests.Visual.Multiplayer;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Matchmaking
|
||||
{
|
||||
public partial class TestScenePlayerPanelList : MultiplayerTestScene
|
||||
{
|
||||
private PlayerPanelList list = null!;
|
||||
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
base.SetUpSteps();
|
||||
|
||||
AddStep("join room", () => JoinRoom(CreateDefaultRoom()));
|
||||
WaitForJoined();
|
||||
|
||||
AddStep("add list", () => Child = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Size = new Vector2(0.8f),
|
||||
Child = list = new PlayerPanelList()
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestChangeDisplayMode()
|
||||
{
|
||||
AddStep("join users", () =>
|
||||
{
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
MultiplayerClient.AddUser(new MultiplayerRoomUser(i)
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
Username = $"User {i}"
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
AddStep("change to split mode", () => list.DisplayStyle = PlayerPanelList.PanelDisplayStyle.Split);
|
||||
AddStep("change to grid mode", () => list.DisplayStyle = PlayerPanelList.PanelDisplayStyle.Grid);
|
||||
AddStep("change to hidden mode", () => list.DisplayStyle = PlayerPanelList.PanelDisplayStyle.Hidden);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddPanelsGrid()
|
||||
{
|
||||
AddStep("change to grid mode", () => list.DisplayStyle = PlayerPanelList.PanelDisplayStyle.Grid);
|
||||
|
||||
int userId = 0;
|
||||
|
||||
AddRepeatStep("join user", () =>
|
||||
{
|
||||
MultiplayerClient.AddUser(new MultiplayerRoomUser(userId)
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
Username = $"User {userId}"
|
||||
}
|
||||
});
|
||||
|
||||
userId++;
|
||||
}, 8);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddPanelsSplit()
|
||||
{
|
||||
AddStep("change to split mode", () => list.DisplayStyle = PlayerPanelList.PanelDisplayStyle.Split);
|
||||
|
||||
int userId = 0;
|
||||
|
||||
AddRepeatStep("join user", () =>
|
||||
{
|
||||
MultiplayerClient.AddUser(new MultiplayerRoomUser(userId)
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
Username = $"User {userId}"
|
||||
}
|
||||
});
|
||||
|
||||
userId++;
|
||||
}, 8);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ChangeRankings()
|
||||
{
|
||||
AddStep("join users", () =>
|
||||
{
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
MultiplayerClient.AddUser(new MultiplayerRoomUser(i)
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
Username = $"User {i}"
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
AddStep("set random placements", () =>
|
||||
{
|
||||
MultiplayerRoom room = MultiplayerClient.ServerRoom!;
|
||||
|
||||
int[] placements = Enumerable.Range(1, room.Users.Count).ToArray();
|
||||
Random.Shared.Shuffle(placements);
|
||||
|
||||
MatchmakingRoomState state = new MatchmakingRoomState();
|
||||
|
||||
for (int i = 0; i < room.Users.Count; i++)
|
||||
state.Users[room.Users[i].UserID].Placement = placements[i];
|
||||
|
||||
MultiplayerClient.ChangeMatchRoomState(state).WaitSafely();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
-33
@@ -14,10 +14,13 @@ using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Idle
|
||||
namespace osu.Game.Screens.OnlinePlay.Matchmaking
|
||||
{
|
||||
public partial class PlayerPanel : UserPanel
|
||||
{
|
||||
public static readonly Vector2 SIZE_HORIZONTAL = new Vector2(250, 100);
|
||||
public static readonly Vector2 SIZE_VERTICAL = new Vector2(150, 200);
|
||||
|
||||
public readonly MultiplayerRoomUser RoomUser;
|
||||
|
||||
[Resolved]
|
||||
@@ -32,6 +35,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Idle
|
||||
private MatchmakingAvatar avatar = null!;
|
||||
private OsuSpriteText username = null!;
|
||||
|
||||
private Container scaleContainer = null!;
|
||||
private Container mainContent = null!;
|
||||
|
||||
public bool Horizontal
|
||||
@@ -59,41 +63,47 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Idle
|
||||
Masking = true;
|
||||
CornerRadius = 10;
|
||||
|
||||
Add(mainContent = new Container
|
||||
Add(scaleContainer = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
Child = mainContent = new Container
|
||||
{
|
||||
avatar = new MatchmakingAvatar(User, isOwnUser: User.Id == api.LocalUser.Value.Id)
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(80),
|
||||
},
|
||||
rankText = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomCentre,
|
||||
Blending = BlendingParameters.Additive,
|
||||
Margin = new MarginPadding(4),
|
||||
Font = OsuFont.Style.Title.With(size: 70),
|
||||
},
|
||||
username = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
Text = User.Username,
|
||||
Font = OsuFont.Style.Heading1,
|
||||
},
|
||||
scoreText = new OsuSpriteText
|
||||
{
|
||||
Margin = new MarginPadding(10),
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
Font = OsuFont.Style.Heading2,
|
||||
Text = "0 pts"
|
||||
avatar = new MatchmakingAvatar(User, isOwnUser: User.Id == api.LocalUser.Value.Id)
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(80),
|
||||
},
|
||||
rankText = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomCentre,
|
||||
Blending = BlendingParameters.Additive,
|
||||
Margin = new MarginPadding(4),
|
||||
Font = OsuFont.Style.Title.With(size: 70),
|
||||
},
|
||||
username = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
Text = User.Username,
|
||||
Font = OsuFont.Style.Heading1,
|
||||
},
|
||||
scoreText = new OsuSpriteText
|
||||
{
|
||||
Margin = new MarginPadding(10),
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
Font = OsuFont.Style.Heading2,
|
||||
Text = "0 pts"
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -141,7 +151,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Idle
|
||||
double duration = instant ? 0 : 1000;
|
||||
|
||||
avatar.MoveTo(avatarPosition, duration, Easing.OutPow10);
|
||||
this.ResizeTo(horizontal ? new Vector2(250, 100) : new Vector2(150, 200), duration, Easing.OutPow10);
|
||||
this.ResizeTo(horizontal ? SIZE_HORIZONTAL : SIZE_VERTICAL, duration, Easing.OutPow10);
|
||||
|
||||
rankText.MoveTo(horizontal ? new Vector2(-40, -10) : new Vector2(-70, 0), duration, Easing.OutPow10);
|
||||
username.MoveTo(horizontal ? new Vector2(0, -46) : new Vector2(0, -86), duration, Easing.OutPow10);
|
||||
@@ -150,14 +160,14 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Idle
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
this.ScaleTo(1.02f, 1000, Easing.OutQuint);
|
||||
scaleContainer.ScaleTo(1.02f, 1000, Easing.OutQuint);
|
||||
mainContent.ScaleTo(1.03f, 1000, Easing.OutQuint);
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
this.ScaleTo(1f, 500, Easing.OutQuint);
|
||||
scaleContainer.ScaleTo(1f, 500, Easing.OutQuint);
|
||||
mainContent.ScaleTo(1, 500, Easing.OutQuint);
|
||||
|
||||
mainContent.MoveTo(Vector2.Zero, 500, Easing.OutElasticHalf);
|
||||
@@ -0,0 +1,305 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Matchmaking
|
||||
{
|
||||
public partial class PlayerPanelList : CompositeDrawable
|
||||
{
|
||||
[Resolved]
|
||||
private MultiplayerClient client { get; set; } = null!;
|
||||
|
||||
private Container<PlayerPanel> panels = null!;
|
||||
private PlayerPanelCellContainer gridLayout = null!;
|
||||
private PlayerPanelCellContainer splitLayoutLeft = null!;
|
||||
private PlayerPanelCellContainer splitLayoutRight = null!;
|
||||
|
||||
private PanelDisplayStyle displayStyle;
|
||||
private Drawable? displayArea;
|
||||
private bool isAnimatingToDisplayArea;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
gridLayout = new PlayerPanelCellContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(20, 5),
|
||||
},
|
||||
splitLayoutLeft = new PlayerPanelCellContainer
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(20, 5),
|
||||
},
|
||||
splitLayoutRight = new PlayerPanelCellContainer
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(20, 5),
|
||||
},
|
||||
panels = new Container<PlayerPanel>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
// Set position/size so we don't initially animate.
|
||||
Position = getFinalPosition();
|
||||
Size = getFinalSize();
|
||||
|
||||
client.MatchRoomStateChanged += onRoomStateChanged;
|
||||
client.UserJoined += onUserJoined;
|
||||
client.UserLeft += onUserLeft;
|
||||
|
||||
if (client.Room != null)
|
||||
{
|
||||
onRoomStateChanged(client.Room.MatchState);
|
||||
foreach (var user in client.Room.Users)
|
||||
onUserJoined(user);
|
||||
}
|
||||
|
||||
updateDisplay();
|
||||
}
|
||||
|
||||
public PanelDisplayStyle DisplayStyle
|
||||
{
|
||||
set
|
||||
{
|
||||
displayStyle = value;
|
||||
if (IsLoaded)
|
||||
updateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
public Drawable? DisplayArea
|
||||
{
|
||||
set
|
||||
{
|
||||
displayArea = value;
|
||||
isAnimatingToDisplayArea = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void onUserJoined(MultiplayerRoomUser user) => Scheduler.Add(() =>
|
||||
{
|
||||
panels.Add(new PlayerPanel(user)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Scale = new Vector2(0.8f)
|
||||
});
|
||||
|
||||
updateDisplay();
|
||||
});
|
||||
|
||||
private void onUserLeft(MultiplayerRoomUser user) => Scheduler.Add(() =>
|
||||
{
|
||||
panels.Single(p => p.RoomUser.Equals(user)).Expire();
|
||||
updateDisplay();
|
||||
});
|
||||
|
||||
private void onRoomStateChanged(MatchRoomState? state) => Scheduler.Add(updateDisplay);
|
||||
|
||||
private void updateDisplay()
|
||||
{
|
||||
gridLayout.ReleasePanels();
|
||||
splitLayoutLeft.ReleasePanels();
|
||||
splitLayoutRight.ReleasePanels();
|
||||
|
||||
switch (displayStyle)
|
||||
{
|
||||
case PanelDisplayStyle.Grid:
|
||||
foreach (var panel in panels)
|
||||
{
|
||||
panel.FadeTo(1, 200);
|
||||
panel.Horizontal = false;
|
||||
}
|
||||
|
||||
gridLayout.AcquirePanels(panels.ToArray());
|
||||
break;
|
||||
|
||||
case PanelDisplayStyle.Split:
|
||||
foreach (var panel in panels)
|
||||
{
|
||||
panel.FadeTo(1, 200);
|
||||
panel.Horizontal = true;
|
||||
}
|
||||
|
||||
int leftCount = (int)Math.Ceiling(panels.Count / 2f);
|
||||
|
||||
splitLayoutLeft.AcquirePanels(panels.Take(leftCount).ToArray());
|
||||
splitLayoutRight.AcquirePanels(panels.Skip(leftCount).ToArray());
|
||||
break;
|
||||
|
||||
case PanelDisplayStyle.Hidden:
|
||||
foreach (var panel in panels)
|
||||
panel.FadeTo(0, 200);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
var targetPos = getFinalPosition();
|
||||
var targetSize = getFinalSize();
|
||||
|
||||
double duration = isAnimatingToDisplayArea ? 60 : 0;
|
||||
|
||||
if (Time.Elapsed > 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.
|
||||
isAnimatingToDisplayArea &= !Precision.AlmostEquals(Size, targetSize, 0.5f);
|
||||
}
|
||||
|
||||
private Vector2 getFinalPosition()
|
||||
=> displayArea == null ? Vector2.Zero : Parent!.ToLocalSpace(displayArea.ScreenSpaceDrawQuad.TopLeft);
|
||||
|
||||
private Vector2 getFinalSize()
|
||||
=> displayArea == null ? Parent!.DrawSize : Parent!.ToLocalSpace(displayArea.ScreenSpaceDrawQuad.BottomRight) - Parent!.ToLocalSpace(displayArea.ScreenSpaceDrawQuad.TopLeft);
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
if (client.IsNotNull())
|
||||
{
|
||||
client.MatchRoomStateChanged -= onRoomStateChanged;
|
||||
client.UserJoined -= onUserJoined;
|
||||
client.UserLeft -= onUserLeft;
|
||||
}
|
||||
}
|
||||
|
||||
private partial class PlayerPanelCellContainer : FillFlowContainer<PlayerPanelCell>
|
||||
{
|
||||
[Resolved]
|
||||
private MultiplayerClient client { get; set; } = null!;
|
||||
|
||||
public void AcquirePanels(PlayerPanel[] panels)
|
||||
{
|
||||
while (Count < panels.Length)
|
||||
{
|
||||
Add(new PlayerPanelCell
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre
|
||||
});
|
||||
}
|
||||
|
||||
while (Count > panels.Length)
|
||||
Remove(Children[^1], true);
|
||||
|
||||
for (int i = 0; i < panels.Length; i++)
|
||||
{
|
||||
// We'll invalidate the layout position to represent the new placements and the re-flow will happen in UpdateAfterChildren().
|
||||
// But the cells expect their positions to be valid as they're updated, which won't be the case until the re-flow happens.
|
||||
int i2 = i;
|
||||
ScheduleAfterChildren(() => Children[i2].AcquirePanel(panels[i2]));
|
||||
|
||||
if (client.Room?.MatchState is not MatchmakingRoomState matchmakingState)
|
||||
continue;
|
||||
|
||||
if (matchmakingState.Users.UserDictionary.TryGetValue(panels[i].User.Id, out MatchmakingUser? user))
|
||||
SetLayoutPosition(Children[i], user.Placement);
|
||||
else
|
||||
SetLayoutPosition(Children[i], float.MaxValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleasePanels()
|
||||
{
|
||||
foreach (var panel in Children)
|
||||
panel.ReleasePanel();
|
||||
}
|
||||
}
|
||||
|
||||
private partial class PlayerPanelCell : Drawable
|
||||
{
|
||||
private PlayerPanel? panel;
|
||||
private bool isAnimating;
|
||||
|
||||
public void AcquirePanel(PlayerPanel panel)
|
||||
{
|
||||
this.panel = panel;
|
||||
isAnimating = true;
|
||||
}
|
||||
|
||||
public void ReleasePanel()
|
||||
{
|
||||
panel = null;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (panel == null)
|
||||
return;
|
||||
|
||||
Size = panel.Horizontal ? PlayerPanel.SIZE_HORIZONTAL : PlayerPanel.SIZE_VERTICAL;
|
||||
Size *= panel.Scale;
|
||||
|
||||
var targetPos = getFinalPosition();
|
||||
|
||||
double duration = isAnimating ? 60 : 0;
|
||||
|
||||
if (Time.Elapsed > 0)
|
||||
{
|
||||
panel.Position = new Vector2(
|
||||
(float)Interpolation.DampContinuously(panel.Position.X, targetPos.X, duration, Time.Elapsed),
|
||||
(float)Interpolation.DampContinuously(panel.Position.Y, targetPos.Y, duration, Time.Elapsed)
|
||||
);
|
||||
}
|
||||
|
||||
// If we don't track the animating state, the animation will also occur when resizing the window.
|
||||
isAnimating &= !Precision.AlmostEquals(panel.Position, targetPos, 0.5f);
|
||||
|
||||
Vector2 getFinalPosition()
|
||||
=> panel.Parent!.ToLocalSpace(ScreenSpaceDrawQuad.Centre) - panel.AnchorPosition;
|
||||
}
|
||||
}
|
||||
|
||||
public enum PanelDisplayStyle
|
||||
{
|
||||
Grid,
|
||||
Split,
|
||||
Hidden
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. 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.Screens;
|
||||
|
||||
@@ -9,14 +8,8 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Idle
|
||||
{
|
||||
public partial class IdleScreen : MatchmakingSubScreen
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChild = new PlayerPanelList
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
};
|
||||
}
|
||||
public override PlayerPanelList.PanelDisplayStyle PlayersDisplayStyle => PlayerPanelList.PanelDisplayStyle.Grid;
|
||||
public override Drawable PlayersDisplayArea => this;
|
||||
|
||||
public override void OnEntering(ScreenTransitionEvent e)
|
||||
{
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. 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.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Idle
|
||||
{
|
||||
public partial class PlayerPanelList : CompositeDrawable
|
||||
{
|
||||
[Resolved]
|
||||
private MultiplayerClient client { get; set; } = null!;
|
||||
|
||||
public bool Horizontal { get; init; }
|
||||
|
||||
private FillFlowContainer<PlayerPanel> panels = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChild = panels = new FillFlowContainer<PlayerPanel>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(20, 5),
|
||||
LayoutEasing = Easing.InOutQuint,
|
||||
LayoutDuration = 500
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
client.MatchRoomStateChanged += onRoomStateChanged;
|
||||
client.UserJoined += onUserJoined;
|
||||
client.UserLeft += onUserLeft;
|
||||
|
||||
if (client.Room != null)
|
||||
{
|
||||
onRoomStateChanged(client.Room.MatchState);
|
||||
foreach (var user in client.Room.Users)
|
||||
onUserJoined(user);
|
||||
}
|
||||
}
|
||||
|
||||
private void onUserJoined(MultiplayerRoomUser user) => Scheduler.Add(() =>
|
||||
{
|
||||
panels.Add(new PlayerPanel(user)
|
||||
{
|
||||
Horizontal = Horizontal,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
});
|
||||
|
||||
private void onUserLeft(MultiplayerRoomUser user) => Scheduler.Add(() =>
|
||||
{
|
||||
panels.Single(p => p.RoomUser.Equals(user)).Expire();
|
||||
});
|
||||
|
||||
private void onRoomStateChanged(MatchRoomState? state) => Scheduler.Add(() =>
|
||||
{
|
||||
if (state is not MatchmakingRoomState matchmakingState)
|
||||
return;
|
||||
|
||||
foreach (var panel in panels)
|
||||
{
|
||||
if (matchmakingState.Users.UserDictionary.TryGetValue(panel.User.Id, out MatchmakingUser? user))
|
||||
panels.SetLayoutPosition(panel, user.Placement);
|
||||
else
|
||||
panels.SetLayoutPosition(panel, float.MaxValue);
|
||||
}
|
||||
});
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
if (client.IsNotNull())
|
||||
{
|
||||
client.MatchRoomStateChanged -= onRoomStateChanged;
|
||||
client.UserJoined -= onUserJoined;
|
||||
client.UserLeft -= onUserLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Idle;
|
||||
using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick;
|
||||
using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Results;
|
||||
using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.RoundResults;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens
|
||||
{
|
||||
@@ -23,6 +22,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens
|
||||
private MultiplayerClient client { get; set; } = null!;
|
||||
|
||||
private ScreenStack screenStack = null!;
|
||||
private PlayerPanelList playersList = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
@@ -30,40 +30,28 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Padding = new MarginPadding(10);
|
||||
|
||||
InternalChild = new GridContainer
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RowDimensions = new[] { new Dimension(), new Dimension(GridSizeMode.AutoSize) },
|
||||
Content = new Drawable[][]
|
||||
new GridContainer
|
||||
{
|
||||
[
|
||||
new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
ColumnDimensions = new[] { new Dimension(), new Dimension(GridSizeMode.Absolute, 20), new Dimension(GridSizeMode.AutoSize) },
|
||||
Padding = new MarginPadding { Bottom = 20 },
|
||||
Content = new Drawable?[][]
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RowDimensions = new[] { new Dimension(), new Dimension(GridSizeMode.AutoSize) },
|
||||
Content = new Drawable[][]
|
||||
{
|
||||
[
|
||||
screenStack = new ScreenStack(),
|
||||
],
|
||||
[
|
||||
new StageDisplay
|
||||
{
|
||||
[
|
||||
screenStack = new ScreenStack(),
|
||||
null,
|
||||
new PlayerPanelList
|
||||
{
|
||||
Horizontal = true,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 250,
|
||||
Scale = new Vector2(0.8f),
|
||||
}
|
||||
]
|
||||
RelativeSizeAxes = Axes.X
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
new StageDisplay
|
||||
{
|
||||
RelativeSizeAxes = Axes.X
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
playersList = new PlayerPanelList
|
||||
{
|
||||
DisplayArea = this
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -72,12 +60,33 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
screenStack.ScreenPushed += onScreenPushed;
|
||||
screenStack.ScreenExited += onScreenExited;
|
||||
|
||||
screenStack.Push(new IdleScreen());
|
||||
|
||||
client.MatchRoomStateChanged += onMatchRoomStateChanged;
|
||||
onMatchRoomStateChanged(client.Room!.MatchState);
|
||||
}
|
||||
|
||||
private void onScreenPushed(IScreen lastScreen, IScreen newScreen)
|
||||
{
|
||||
if (newScreen is not MatchmakingSubScreen matchmakingSubScreen)
|
||||
return;
|
||||
|
||||
playersList.DisplayStyle = matchmakingSubScreen.PlayersDisplayStyle;
|
||||
playersList.DisplayArea = matchmakingSubScreen.PlayersDisplayArea;
|
||||
}
|
||||
|
||||
private void onScreenExited(IScreen lastScreen, IScreen newScreen)
|
||||
{
|
||||
if (newScreen is not MatchmakingSubScreen matchmakingSubScreen)
|
||||
return;
|
||||
|
||||
playersList.DisplayStyle = matchmakingSubScreen.PlayersDisplayStyle;
|
||||
playersList.DisplayArea = matchmakingSubScreen.PlayersDisplayArea;
|
||||
}
|
||||
|
||||
private void onMatchRoomStateChanged(MatchRoomState? state) => Scheduler.Add(() =>
|
||||
{
|
||||
if (state is not MatchmakingRoomState matchmakingState)
|
||||
|
||||
@@ -6,9 +6,12 @@ using osu.Framework.Screens;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens
|
||||
{
|
||||
public partial class MatchmakingSubScreen : Screen
|
||||
public abstract partial class MatchmakingSubScreen : Screen
|
||||
{
|
||||
public MatchmakingSubScreen()
|
||||
public abstract PlayerPanelList.PanelDisplayStyle PlayersDisplayStyle { get; }
|
||||
public abstract Drawable? PlayersDisplayArea { get; }
|
||||
|
||||
protected MatchmakingSubScreen()
|
||||
{
|
||||
RelativePositionAxes = Axes.X;
|
||||
}
|
||||
@@ -16,19 +19,19 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens
|
||||
public override void OnEntering(ScreenTransitionEvent e)
|
||||
{
|
||||
base.OnEntering(e);
|
||||
this.MoveToX(1).MoveToX(0, 200);
|
||||
this.FadeInFromZero(200);
|
||||
}
|
||||
|
||||
public override void OnSuspending(ScreenTransitionEvent e)
|
||||
{
|
||||
base.OnSuspending(e);
|
||||
this.MoveToX(-1, 200);
|
||||
this.FadeOutFromOne(200);
|
||||
}
|
||||
|
||||
public override void OnResuming(ScreenTransitionEvent e)
|
||||
{
|
||||
base.OnResuming(e);
|
||||
this.MoveToX(0, 200);
|
||||
this.FadeInFromZero(200);
|
||||
}
|
||||
|
||||
public override bool OnExiting(ScreenExitEvent e)
|
||||
@@ -36,7 +39,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens
|
||||
if (base.OnExiting(e))
|
||||
return true;
|
||||
|
||||
this.MoveToX(1, 200);
|
||||
this.FadeOutFromOne(200);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,23 +11,38 @@ using osu.Game.Online.Rooms;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick
|
||||
{
|
||||
public partial class PickScreen : OsuScreen
|
||||
public partial class PickScreen : MatchmakingSubScreen
|
||||
{
|
||||
private BeatmapSelectionGrid selectionGrid = null!;
|
||||
public override PlayerPanelList.PanelDisplayStyle PlayersDisplayStyle => PlayerPanelList.PanelDisplayStyle.Split;
|
||||
public override Drawable PlayersDisplayArea { get; }
|
||||
|
||||
private readonly BeatmapSelectionGrid selectionGrid;
|
||||
|
||||
[Resolved]
|
||||
private MultiplayerClient client { get; set; } = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
public PickScreen()
|
||||
{
|
||||
InternalChild = new Container
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = selectionGrid = new BeatmapSelectionGrid
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Horizontal = 200 },
|
||||
Child = selectionGrid = new BeatmapSelectionGrid
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Horizontal = 5 },
|
||||
Child = PlayersDisplayArea = Empty().With(d =>
|
||||
{
|
||||
d.RelativeSizeAxes = Axes.Both;
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Idle;
|
||||
using osu.Game.Utils;
|
||||
using osuTK;
|
||||
|
||||
@@ -21,15 +20,17 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Results
|
||||
{
|
||||
private const float grid_spacing = 5;
|
||||
|
||||
public override PlayerPanelList.PanelDisplayStyle PlayersDisplayStyle => PlayerPanelList.PanelDisplayStyle.Grid;
|
||||
public override Drawable PlayersDisplayArea { get; }
|
||||
|
||||
[Resolved]
|
||||
private MultiplayerClient client { get; set; } = null!;
|
||||
|
||||
private OsuSpriteText placementText = null!;
|
||||
private FillFlowContainer<UserStatisticPanel> userStatistics = null!;
|
||||
private FillFlowContainer<RoomStatisticPanel> roomStatistics = null!;
|
||||
private readonly OsuSpriteText placementText;
|
||||
private readonly FillFlowContainer<UserStatisticPanel> userStatistics;
|
||||
private readonly FillFlowContainer<RoomStatisticPanel> roomStatistics;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
public ResultsScreen()
|
||||
{
|
||||
InternalChild = new GridContainer
|
||||
{
|
||||
@@ -113,10 +114,10 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Results
|
||||
}
|
||||
},
|
||||
null,
|
||||
new PlayerPanelList
|
||||
PlayersDisplayArea = Empty().With(d =>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}
|
||||
d.RelativeSizeAxes = Axes.Both;
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.RoundResults
|
||||
{
|
||||
private const int panel_spacing = 5;
|
||||
|
||||
public override PlayerPanelList.PanelDisplayStyle PlayersDisplayStyle => PlayerPanelList.PanelDisplayStyle.Hidden;
|
||||
public override Drawable? PlayersDisplayArea => null;
|
||||
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; } = null!;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user