1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 09:07:52 +08:00

Merge pull request #11832 from peppy/leaderboard-compact-mode

Show compact leaderboard during gameplay to reduce distractions
This commit is contained in:
Dan Balasescu 2021-02-19 18:17:46 +09:00 committed by GitHub
commit 9fc57b2145
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 227 additions and 139 deletions

View File

@ -13,6 +13,7 @@ using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Database;
using osu.Game.Online;
using osu.Game.Online.API;
using osu.Game.Online.Spectator;
using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Osu.Scoring;
@ -50,6 +51,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
[SetUpSteps]
public override void SetUpSteps()
{
AddStep("set local user", () => ((DummyAPIAccess)API).LocalUser.Value = lookupCache.GetUserAsync(1).Result);
AddStep("create leaderboard", () =>
{
leaderboard?.Expire();
@ -85,6 +88,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
public void TestScoreUpdates()
{
AddRepeatStep("update state", () => streamingClient.RandomlyUpdateState(), 100);
AddToggleStep("switch compact mode", expanded => leaderboard.Expanded.Value = expanded);
}
[Test]

View File

@ -89,6 +89,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
Debug.Assert(client.Room != null);
}
protected override void LoadComplete()
{
base.LoadComplete();
((IBindable<bool>)leaderboard.Expanded).BindTo(IsBreakTime);
}
protected override void StartGameplay()
{
// block base call, but let the server know we are ready to start.

View File

@ -4,6 +4,7 @@
using System;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Bindables;
using osu.Framework.Caching;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -16,6 +17,8 @@ namespace osu.Game.Screens.Play.HUD
{
private readonly Cached sorting = new Cached();
public Bindable<bool> Expanded = new Bindable<bool>();
public GameplayLeaderboard()
{
Width = GameplayLeaderboardScore.EXTENDED_WIDTH + GameplayLeaderboardScore.SHEAR_WIDTH;
@ -47,8 +50,7 @@ namespace osu.Game.Screens.Play.HUD
{
var drawable = new GameplayLeaderboardScore(user, isTracked)
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Expanded = { BindTarget = Expanded },
};
base.Add(drawable);

View File

@ -20,16 +20,33 @@ namespace osu.Game.Screens.Play.HUD
{
public class GameplayLeaderboardScore : CompositeDrawable, ILeaderboardScore
{
public const float EXTENDED_WIDTH = 255f;
public const float EXTENDED_WIDTH = regular_width + top_player_left_width_extension;
private const float regular_width = 235f;
// a bit hand-wavy, but there's a lot of hard-coded paddings in each of the grid's internals.
private const float compact_width = 77.5f;
private const float top_player_left_width_extension = 20f;
public const float PANEL_HEIGHT = 35f;
public const float SHEAR_WIDTH = PANEL_HEIGHT * panel_shear;
private const float panel_shear = 0.15f;
private const float rank_text_width = 35f;
private const float score_components_width = 85f;
private const float avatar_size = 25f;
private const double panel_transition_duration = 500;
private const double text_transition_duration = 200;
public Bindable<bool> Expanded = new Bindable<bool>();
private OsuSpriteText positionText, scoreText, accuracyText, comboText, usernameText;
public BindableDouble TotalScore { get; } = new BindableDouble();
@ -63,8 +80,15 @@ namespace osu.Game.Screens.Play.HUD
private readonly bool trackedPlayer;
private Container mainFillContainer;
private Box centralFill;
private Container backgroundPaddingAdjustContainer;
private GridContainer gridContainer;
private Container scoreComponents;
/// <summary>
/// Creates a new <see cref="GameplayLeaderboardScore"/>.
/// </summary>
@ -75,7 +99,8 @@ namespace osu.Game.Screens.Play.HUD
User = user;
this.trackedPlayer = trackedPlayer;
Size = new Vector2(EXTENDED_WIDTH, PANEL_HEIGHT);
AutoSizeAxes = Axes.X;
Height = PANEL_HEIGHT;
}
[BackgroundDependencyLoader]
@ -85,147 +110,167 @@ namespace osu.Game.Screens.Play.HUD
InternalChildren = new Drawable[]
{
mainFillContainer = new Container
new Container
{
Width = regular_width,
AutoSizeAxes = Axes.X,
RelativeSizeAxes = Axes.Y,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Masking = true,
CornerRadius = 5f,
Shear = new Vector2(panel_shear, 0f),
Child = new Box
Margin = new MarginPadding { Left = top_player_left_width_extension },
Children = new Drawable[]
{
Alpha = 0.5f,
RelativeSizeAxes = Axes.Both,
}
},
new GridContainer
{
Width = regular_width,
RelativeSizeAxes = Axes.Y,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
ColumnDimensions = new[]
{
new Dimension(GridSizeMode.Absolute, 35f),
new Dimension(),
new Dimension(GridSizeMode.Absolute, 85f),
},
Content = new[]
{
new Drawable[]
backgroundPaddingAdjustContainer = new Container
{
positionText = new OsuSpriteText
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
Padding = new MarginPadding { Right = SHEAR_WIDTH / 2 },
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Colour = Color4.White,
Font = OsuFont.Torus.With(size: 14, weight: FontWeight.Bold),
Shadow = false,
},
new Container
{
Padding = new MarginPadding { Horizontal = SHEAR_WIDTH / 3 },
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
mainFillContainer = new Container
{
new Container
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 5f,
Shear = new Vector2(panel_shear, 0f),
Children = new Drawable[]
{
Masking = true,
CornerRadius = 5f,
Shear = new Vector2(panel_shear, 0f),
RelativeSizeAxes = Axes.Both,
Children = new[]
new Box
{
centralFill = new Box
{
Alpha = 0.5f,
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex("3399cc"),
},
}
},
new FillFlowContainer
{
Padding = new MarginPadding { Left = SHEAR_WIDTH },
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(4f, 0f),
Children = new Drawable[]
{
avatarContainer = new CircularContainer
{
Masking = true,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Size = new Vector2(25f),
Children = new Drawable[]
{
new Box
{
Name = "Placeholder while avatar loads",
Alpha = 0.3f,
RelativeSizeAxes = Axes.Both,
Colour = colours.Gray4,
}
}
},
usernameText = new OsuSpriteText
{
RelativeSizeAxes = Axes.X,
Width = 0.6f,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Colour = Color4.White,
Font = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold),
Text = User?.Username,
Truncate = true,
Shadow = false,
}
}
},
}
},
new Container
{
Padding = new MarginPadding { Top = 2f, Right = 17.5f, Bottom = 5f },
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Colour = Color4.White,
Children = new Drawable[]
{
scoreText = new OsuSpriteText
{
Spacing = new Vector2(-1f, 0f),
Font = OsuFont.Torus.With(size: 16, weight: FontWeight.SemiBold, fixedWidth: true),
Shadow = false,
},
accuracyText = new OsuSpriteText
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold, fixedWidth: true),
Spacing = new Vector2(-1f, 0f),
Shadow = false,
},
comboText = new OsuSpriteText
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Spacing = new Vector2(-1f, 0f),
Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold, fixedWidth: true),
Shadow = false,
Alpha = 0.5f,
RelativeSizeAxes = Axes.Both,
},
},
},
}
},
gridContainer = new GridContainer
{
RelativeSizeAxes = Axes.Y,
Width = compact_width, // will be updated by expanded state.
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
ColumnDimensions = new[]
{
new Dimension(GridSizeMode.Absolute, rank_text_width),
new Dimension(),
new Dimension(GridSizeMode.AutoSize, maxSize: score_components_width),
},
Content = new[]
{
new Drawable[]
{
positionText = new OsuSpriteText
{
Padding = new MarginPadding { Right = SHEAR_WIDTH / 2 },
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Colour = Color4.White,
Font = OsuFont.Torus.With(size: 14, weight: FontWeight.Bold),
Shadow = false,
},
new Container
{
Padding = new MarginPadding { Horizontal = SHEAR_WIDTH / 3 },
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Container
{
Masking = true,
CornerRadius = 5f,
Shear = new Vector2(panel_shear, 0f),
RelativeSizeAxes = Axes.Both,
Children = new[]
{
centralFill = new Box
{
Alpha = 0.5f,
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex("3399cc"),
},
}
},
new FillFlowContainer
{
Padding = new MarginPadding { Left = SHEAR_WIDTH },
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(4f, 0f),
Children = new Drawable[]
{
avatarContainer = new CircularContainer
{
Masking = true,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Size = new Vector2(avatar_size),
Children = new Drawable[]
{
new Box
{
Name = "Placeholder while avatar loads",
Alpha = 0.3f,
RelativeSizeAxes = Axes.Both,
Colour = colours.Gray4,
}
}
},
usernameText = new OsuSpriteText
{
RelativeSizeAxes = Axes.X,
Width = 0.6f,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Colour = Color4.White,
Font = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold),
Text = User?.Username,
Truncate = true,
Shadow = false,
}
}
},
}
},
scoreComponents = new Container
{
Padding = new MarginPadding { Top = 2f, Right = 17.5f, Bottom = 5f },
AlwaysPresent = true, // required to smoothly animate autosize after hidden early.
Masking = true,
RelativeSizeAxes = Axes.Y,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Colour = Color4.White,
Children = new Drawable[]
{
scoreText = new OsuSpriteText
{
Spacing = new Vector2(-1f, 0f),
Font = OsuFont.Torus.With(size: 16, weight: FontWeight.SemiBold, fixedWidth: true),
Shadow = false,
},
accuracyText = new OsuSpriteText
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold, fixedWidth: true),
Spacing = new Vector2(-1f, 0f),
Shadow = false,
},
comboText = new OsuSpriteText
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Spacing = new Vector2(-1f, 0f),
Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold, fixedWidth: true),
Shadow = false,
},
},
}
}
}
}
}
}
},
};
LoadComponentAsync(new DrawableAvatar(User), avatarContainer.Add);
@ -241,18 +286,43 @@ namespace osu.Game.Screens.Play.HUD
base.LoadComplete();
updateState();
Expanded.BindValueChanged(changeExpandedState, true);
FinishTransforms(true);
}
private const double panel_transition_duration = 500;
private void changeExpandedState(ValueChangedEvent<bool> expanded)
{
scoreComponents.ClearTransforms();
if (expanded.NewValue)
{
gridContainer.ResizeWidthTo(regular_width, panel_transition_duration, Easing.OutQuint);
scoreComponents.ResizeWidthTo(score_components_width, panel_transition_duration, Easing.OutQuint);
scoreComponents.FadeIn(panel_transition_duration, Easing.OutQuint);
usernameText.FadeIn(panel_transition_duration, Easing.OutQuint);
}
else
{
gridContainer.ResizeWidthTo(compact_width, panel_transition_duration, Easing.OutQuint);
scoreComponents.ResizeWidthTo(0, panel_transition_duration, Easing.OutQuint);
scoreComponents.FadeOut(text_transition_duration, Easing.OutQuint);
usernameText.FadeOut(text_transition_duration, Easing.OutQuint);
}
}
private void updateState()
{
bool widthExtension = false;
if (HasQuit.Value)
{
// we will probably want to display this in a better way once we have a design.
// and also show states other than quit.
mainFillContainer.ResizeWidthTo(regular_width, panel_transition_duration, Easing.OutElastic);
panelColour = Color4.Gray;
textColour = Color4.White;
return;
@ -260,22 +330,29 @@ namespace osu.Game.Screens.Play.HUD
if (scorePosition == 1)
{
mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, panel_transition_duration, Easing.OutElastic);
widthExtension = true;
panelColour = Color4Extensions.FromHex("7fcc33");
textColour = Color4.White;
}
else if (trackedPlayer)
{
mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, panel_transition_duration, Easing.OutElastic);
widthExtension = true;
panelColour = Color4Extensions.FromHex("ffd966");
textColour = Color4Extensions.FromHex("2e576b");
}
else
{
mainFillContainer.ResizeWidthTo(regular_width, panel_transition_duration, Easing.OutElastic);
panelColour = Color4Extensions.FromHex("3399cc");
textColour = Color4.White;
}
this.TransformTo(nameof(SizeContainerLeftPadding), widthExtension ? -top_player_left_width_extension : 0, panel_transition_duration, Easing.OutElastic);
}
public float SizeContainerLeftPadding
{
get => backgroundPaddingAdjustContainer.Padding.Left;
set => backgroundPaddingAdjustContainer.Padding = new MarginPadding { Left = value };
}
private Color4 panelColour
@ -287,8 +364,6 @@ namespace osu.Game.Screens.Play.HUD
}
}
private const double text_transition_duration = 200;
private Color4 textColour
{
set