mirror of
https://github.com/ppy/osu.git
synced 2026-05-13 20:33:35 +08:00
Improvements to discard screen UX (#37245)
Just an initial grab bag to keep these PRs small. ### Avoid showing countdown update when at discard screen This is needless. We already have the `DiscardFinish` stage which has a short countdown. Playing this change to the user creates unnecessary confusion. ### Allow stage caption text to be changed at any point Also remove custom colour support. We'll handle this internally in a better way in the future. ### Better explain why we're waiting after discarding our own cards
This commit is contained in:
committed by
GitHub
Unverified
parent
93b7c3324d
commit
9c43739228
+56
-52
@@ -14,6 +14,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay;
|
||||
using osu.Game.Online.RankedPlay;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@@ -37,6 +38,40 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components
|
||||
private DateTimeOffset countdownStartTime;
|
||||
private DateTimeOffset countdownEndTime;
|
||||
|
||||
private RankedPlayStage? activeStage;
|
||||
|
||||
private LocalisableString heading;
|
||||
|
||||
/// <summary>
|
||||
/// Heading text to be displayed indicating the purpose of the current stage.
|
||||
/// </summary>
|
||||
public LocalisableString Heading
|
||||
{
|
||||
get => heading;
|
||||
set
|
||||
{
|
||||
heading = value;
|
||||
if (headingText != null)
|
||||
headingText.Text = value;
|
||||
}
|
||||
}
|
||||
|
||||
private LocalisableString caption;
|
||||
|
||||
/// <summary>
|
||||
/// Subtitle text to be displayed indicating the action a user should take in the current stage.
|
||||
/// </summary>
|
||||
public LocalisableString Caption
|
||||
{
|
||||
get => caption;
|
||||
set
|
||||
{
|
||||
caption = value;
|
||||
if (captionText != null)
|
||||
captionText.Text = value;
|
||||
}
|
||||
}
|
||||
|
||||
public RankedPlayStageDisplay(RankedPlayColourScheme colourScheme)
|
||||
{
|
||||
this.colourScheme = colourScheme;
|
||||
@@ -152,7 +187,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components
|
||||
Left = 10
|
||||
},
|
||||
UseFullGlyphHeight = false,
|
||||
Text = "00:27:123",
|
||||
Font = OsuFont.TorusAlternate.With(size: 16, fixedWidth: true, weight: FontWeight.SemiBold)
|
||||
}
|
||||
]
|
||||
@@ -164,61 +198,12 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components
|
||||
Top = 80,
|
||||
Left = 20
|
||||
},
|
||||
Colour = CaptionColour ?? colourScheme.Primary,
|
||||
Text = Caption,
|
||||
Font = OsuFont.TorusAlternate.With(size: 24, weight: FontWeight.SemiBold)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private LocalisableString heading;
|
||||
|
||||
/// <summary>
|
||||
/// Heading text to be displayed indicating the purpose of the current stage.
|
||||
/// </summary>
|
||||
public LocalisableString Heading
|
||||
{
|
||||
get => heading;
|
||||
set
|
||||
{
|
||||
heading = value;
|
||||
if (headingText != null)
|
||||
headingText.Text = value;
|
||||
}
|
||||
}
|
||||
|
||||
private LocalisableString caption;
|
||||
|
||||
/// <summary>
|
||||
/// Subtitle text to be displayed indicating the action a user should take in the current stage.
|
||||
/// </summary>
|
||||
public LocalisableString Caption
|
||||
{
|
||||
get => caption;
|
||||
set
|
||||
{
|
||||
caption = value;
|
||||
if (captionText != null)
|
||||
captionText.Text = value;
|
||||
}
|
||||
}
|
||||
|
||||
private Color4? captionColour;
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the default caption colour from the colour scheme with a custom one.
|
||||
/// </summary>
|
||||
public Color4? CaptionColour
|
||||
{
|
||||
get => captionColour;
|
||||
set
|
||||
{
|
||||
captionColour = value;
|
||||
if (captionText != null)
|
||||
captionText.Colour = value ?? colourScheme.Primary;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
@@ -254,18 +239,37 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components
|
||||
|
||||
private void onCountdownStarted(MultiplayerCountdown countdown) => Scheduler.Add(() =>
|
||||
{
|
||||
if (countdown is not RankedPlayStageCountdown)
|
||||
if (countdown is not RankedPlayStageCountdown stageCountdown)
|
||||
return;
|
||||
|
||||
switch (stageCountdown.Stage)
|
||||
{
|
||||
case RankedPlayStage.CardDiscard:
|
||||
// Discard stage ends when both players have discarded, but adds a 3 second delay before completing.
|
||||
// Showing this in the countdown just creates visual noise, so let's handle internally.
|
||||
if (activeStage == stageCountdown.Stage)
|
||||
return;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
activeStage = stageCountdown.Stage;
|
||||
countdownStartTime = DateTimeOffset.Now;
|
||||
countdownEndTime = DateTimeOffset.Now + countdown.TimeRemaining;
|
||||
});
|
||||
|
||||
private void onCountdownStopped(MultiplayerCountdown countdown) => Scheduler.Add(() =>
|
||||
{
|
||||
if (countdown is not RankedPlayStageCountdown)
|
||||
if (countdown is not RankedPlayStageCountdown stageCountdown)
|
||||
return;
|
||||
|
||||
switch (stageCountdown.Stage)
|
||||
{
|
||||
// See above special case handling.
|
||||
case RankedPlayStage.CardDiscard:
|
||||
return;
|
||||
}
|
||||
|
||||
countdownEndTime = DateTimeOffset.Now;
|
||||
});
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
@@ -23,7 +24,6 @@ using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card;
|
||||
using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components;
|
||||
using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
{
|
||||
@@ -36,7 +36,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
|
||||
public override bool ShowStageOverlay => true;
|
||||
public override LocalisableString StageHeading => "Discard Phase";
|
||||
protected override LocalisableString StageCaption => "Replace cards from your hand";
|
||||
|
||||
private PlayerHandOfCards playerHand = null!;
|
||||
private ShearedButton discardButton = null!;
|
||||
@@ -62,9 +61,11 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
private DateTimeOffset stageEndTime;
|
||||
private TimeSpan stageDuration;
|
||||
|
||||
private ScheduledDelegate? waitingOpponentTextUpdate;
|
||||
|
||||
public DiscardScreen()
|
||||
{
|
||||
StageDisplay.CaptionColour = Color4.White;
|
||||
StageCaption = "Replace cards from your hand";
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@@ -233,6 +234,12 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
playerHand.SelectionMode = HandSelectionMode.Disabled;
|
||||
|
||||
hasDiscardedCards = true;
|
||||
|
||||
StageCaption = string.Empty;
|
||||
|
||||
// A bit awkward, but we're delaying this until we're mostly sure the opponent is still discarding.
|
||||
// See the countdown reset logic for DiscardStage which gives 3 seconds for animation.
|
||||
waitingOpponentTextUpdate = Scheduler.AddDelayed(() => StageCaption = "Waiting for your opponent...", 3200);
|
||||
}
|
||||
|
||||
private readonly List<RankedPlayCardWithPlaylistItem> discardedCards = new List<RankedPlayCardWithPlaylistItem>();
|
||||
@@ -313,6 +320,9 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
|
||||
double presentationTime = Math.Max(earliestPresentationTime, Time.Current);
|
||||
Scheduler.AddDelayed(presentRemainingCards, presentationTime - Time.Current);
|
||||
|
||||
waitingOpponentTextUpdate?.Cancel();
|
||||
StageCaption = string.Empty;
|
||||
}
|
||||
|
||||
private void presentRemainingCards()
|
||||
|
||||
@@ -28,7 +28,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
public Action<bool>? ExitRequested { get; init; }
|
||||
|
||||
public override LocalisableString StageHeading => "Results";
|
||||
protected override LocalisableString StageCaption => string.Empty;
|
||||
|
||||
[Resolved]
|
||||
private RankedPlayMatchInfo matchInfo { get; set; } = null!;
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
public partial class GameplayScreen : RankedPlaySubScreen
|
||||
{
|
||||
public override LocalisableString StageHeading => "Gameplay";
|
||||
protected override LocalisableString StageCaption => string.Empty;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
|
||||
@@ -33,7 +33,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
public override bool ShowBeatmapBackground => true;
|
||||
|
||||
public override LocalisableString StageHeading => "Gameplay";
|
||||
protected override LocalisableString StageCaption => string.Empty;
|
||||
|
||||
[Cached(typeof(IBindable<SongSelect.BeatmapSetLookupResult?>))]
|
||||
private readonly Bindable<SongSelect.BeatmapSetLookupResult?> lastLookupResult = new Bindable<SongSelect.BeatmapSetLookupResult?>();
|
||||
|
||||
@@ -20,7 +20,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
|
||||
public partial class IntroScreen : RankedPlaySubScreen
|
||||
{
|
||||
public override LocalisableString StageHeading => string.Empty;
|
||||
protected override LocalisableString StageCaption => string.Empty;
|
||||
|
||||
public IntroScreen()
|
||||
{
|
||||
|
||||
@@ -25,7 +25,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
|
||||
public override bool ShowStageOverlay => true;
|
||||
public override LocalisableString StageHeading => "Pick Phase";
|
||||
protected override LocalisableString StageCaption => "Waiting for your opponent...";
|
||||
|
||||
protected override RankedPlayColourScheme ColourScheme => RankedPlayColourScheme.RED;
|
||||
|
||||
@@ -40,6 +39,11 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
private const int card_play_samples = 2;
|
||||
private Sample?[]? cardPlaySamples;
|
||||
|
||||
public OpponentPickScreen()
|
||||
{
|
||||
StageCaption = "Waiting for your opponent...";
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
|
||||
@@ -31,7 +31,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
public override bool ShowStageOverlay => true;
|
||||
|
||||
public override LocalisableString StageHeading => "Pick Phase";
|
||||
protected override LocalisableString StageCaption => "It's your turn to play a card!";
|
||||
|
||||
private PlayerHandOfCards playerHand = null!;
|
||||
private OpponentHandOfCards opponentHand = null!;
|
||||
@@ -46,7 +45,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
|
||||
private Sample? timeRunningOutSample;
|
||||
private SampleChannel? timeRunningOutSampleChannel;
|
||||
private Sample? timeUpBuzzerSample;
|
||||
|
||||
private DateTimeOffset stageEndTime;
|
||||
private TimeSpan stageDuration;
|
||||
@@ -56,6 +54,11 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
/// </summary>
|
||||
private bool hasPlayedCard;
|
||||
|
||||
public PickScreen()
|
||||
{
|
||||
StageCaption = "It's your turn to play a card!";
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
@@ -103,7 +106,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
cardPlaySamples[i] = audio.Samples.Get($@"Multiplayer/Matchmaking/Ranked/card-play-{1 + i}");
|
||||
|
||||
timeRunningOutSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Ranked/time-running-out");
|
||||
timeUpBuzzerSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Ranked/time-up");
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
@@ -209,14 +211,11 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
|
||||
private void onCountdownStopped(MultiplayerCountdown countdown) => Scheduler.Add(() =>
|
||||
{
|
||||
if (countdown is not RankedPlayStageCountdown stageCountdown)
|
||||
if (countdown is not RankedPlayStageCountdown)
|
||||
return;
|
||||
|
||||
stageEndTime = DateTimeOffset.Now;
|
||||
stageDuration = TimeSpan.Zero;
|
||||
|
||||
if (stageCountdown.Stage == RankedPlayStage.CardPlay && !hasPlayedCard)
|
||||
timeUpBuzzerSample?.Play();
|
||||
});
|
||||
|
||||
private void onPlayButtonClicked()
|
||||
|
||||
@@ -37,7 +37,11 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
/// <summary>
|
||||
/// Subtitle text to be displayed indicating the action a user should take in the current stage.
|
||||
/// </summary>
|
||||
protected abstract LocalisableString StageCaption { get; }
|
||||
protected LocalisableString StageCaption
|
||||
{
|
||||
get => StageDisplay.Caption;
|
||||
set => StageDisplay.Caption = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The colour scheme commonly used for components of this screen.
|
||||
@@ -79,7 +83,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
StageDisplay = new RankedPlayStageDisplay(ColourScheme)
|
||||
{
|
||||
Heading = StageHeading,
|
||||
Caption = StageCaption,
|
||||
Margin = new MarginPadding { Top = 60 },
|
||||
State = { BindTarget = CountdownVisibility }
|
||||
},
|
||||
|
||||
@@ -40,7 +40,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
public partial class ResultsScreen : RankedPlaySubScreen
|
||||
{
|
||||
public override LocalisableString StageHeading => "Results";
|
||||
protected override LocalisableString StageCaption => string.Empty;
|
||||
|
||||
public override bool ShowBeatmapBackground => true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user