mirror of
https://github.com/ppy/osu.git
synced 2026-06-03 02:31:25 +08:00
Add bottom 'ornament' overlay to ranked play (#37288)
This commit adds an always present overlay to all ranked play screens, meant to indicate to the user that a ranked play session in currently in progress. This has been largely inspired by the pre-shader argon healthbar code. It shouldn't have the same performance concerns, however, since the paths are only calculated once when loading the drawable (and eventually when it is resized, if ever). `RankedPlayScreen`: <img width="1838" height="1353" alt="image" src="https://github.com/user-attachments/assets/c621d759-a88f-49f0-b0df-3a6da90eca65" /> Gameplay: <img width="1838" height="1353" alt="image" src="https://github.com/user-attachments/assets/ee848d06-3878-4cbb-bd4b-de2c4bcfa688" /> Currently the drawable overlaps with some components, but it will be resolved in later pull requests. --------- Co-authored-by: Dean Herbert <pe@ppy.sh>
This commit is contained in:
committed by
GitHub
Unverified
parent
ac620ee375
commit
16a2a96bcf
@@ -137,7 +137,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
|
||||
vsText.ScaleTo(0.4f, 1300, Easing.OutExpo);
|
||||
}
|
||||
|
||||
delay += 850;
|
||||
delay += delay_first;
|
||||
|
||||
impactDelay = delay;
|
||||
|
||||
@@ -187,9 +187,14 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
|
||||
this.Delay(3200).FadeOut(300).Expire();
|
||||
}
|
||||
|
||||
delay += 3350;
|
||||
delay += delay_final;
|
||||
}
|
||||
|
||||
private const double delay_first = 850;
|
||||
private const double delay_final = 3350;
|
||||
|
||||
public const double INTRO_LENGTH = delay_first + delay_final;
|
||||
|
||||
private partial class UserDisplay : CompositeDrawable
|
||||
{
|
||||
public UserDisplay(UserWithRating user, Anchor contentAnchor)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// 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.Diagnostics;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
@@ -67,6 +68,9 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
[Resolved]
|
||||
private IDialogOverlay dialogOverlay { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private IOverlayManager overlayManager { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private AudioManager audio { get; set; } = null!;
|
||||
|
||||
@@ -85,6 +89,9 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
private readonly Container<RankedPlaySubScreen> screenContainer;
|
||||
private readonly RankedPlayChatDisplay chat;
|
||||
|
||||
private RankedPlayBottomOrnament ornament = null!;
|
||||
private IDisposable? ornamentOverlayRegistration;
|
||||
|
||||
private IBindable<RankedPlayStage> stage = null!;
|
||||
|
||||
private Sample? sampleStart;
|
||||
@@ -158,6 +165,12 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
{
|
||||
stage = matchInfo.Stage.GetBoundCopy();
|
||||
sampleStart = audio.Samples.Get(@"SongSelect/confirm-selection");
|
||||
|
||||
LoadComponent(ornament = new RankedPlayBottomOrnament
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
});
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
@@ -168,6 +181,8 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
client.UserStateChanged += onUserStateChanged;
|
||||
client.LoadRequested += onLoadRequested;
|
||||
|
||||
Scheduler.AddDelayed(() => ornament.Show(), VsSequence.INTRO_LENGTH);
|
||||
|
||||
int localUserId = api.LocalUser.Value.OnlineID;
|
||||
int opponentUserId = ((RankedPlayRoomState)client.Room!.MatchState!).Users.Keys.Single(it => it != localUserId);
|
||||
|
||||
@@ -195,6 +210,8 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
},
|
||||
]);
|
||||
|
||||
ornamentOverlayRegistration = overlayManager.RegisterBlockingOverlay(ornament);
|
||||
|
||||
stage.BindValueChanged(e => onStageChanged(e.NewValue));
|
||||
}
|
||||
|
||||
@@ -356,6 +373,9 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
|
||||
client.LeaveRoom().FireAndForget();
|
||||
|
||||
ornamentOverlayRegistration?.Dispose();
|
||||
ornamentOverlayRegistration = null;
|
||||
|
||||
if (retryRequested)
|
||||
controller?.RejoinQueue();
|
||||
|
||||
@@ -406,6 +426,9 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
client.UserStateChanged -= onUserStateChanged;
|
||||
client.LoadRequested -= onLoadRequested;
|
||||
|
||||
ornamentOverlayRegistration?.Dispose();
|
||||
ornamentOverlayRegistration = null;
|
||||
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
// 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.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Extensions.LocalisationExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Lines;
|
||||
using osu.Framework.Layout;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Matchmaking
|
||||
{
|
||||
/// <summary>
|
||||
/// A small component intended to be always present at the bottom of all ranked play screens
|
||||
/// to indicate a ranked play session is in progress.
|
||||
/// </summary>
|
||||
public partial class RankedPlayBottomOrnament : OverlayContainer
|
||||
{
|
||||
private const int width = 400;
|
||||
private const int height = 24;
|
||||
|
||||
protected override bool BlockPositionalInput => false;
|
||||
|
||||
private Path pathLeft = null!;
|
||||
private Path pathRight = null!;
|
||||
|
||||
private Path pathCenter = null!;
|
||||
private Path pathCenterWide = null!;
|
||||
|
||||
private readonly LayoutValue layout = new LayoutValue(Invalidation.DrawSize);
|
||||
|
||||
protected override bool StartHidden => true;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
Alpha = 0;
|
||||
|
||||
Masking = true;
|
||||
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Colour = Color4Extensions.FromHex("#15061e").Opacity(0.8f),
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = height * 2,
|
||||
Roundness = height * 2,
|
||||
Offset = new Vector2(0, height / 2f),
|
||||
};
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 10,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
pathLeft = new SmoothPath
|
||||
{
|
||||
AutoSizeAxes = Axes.None,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
PathRadius = 1,
|
||||
},
|
||||
pathCenter = new SmoothPath
|
||||
{
|
||||
AutoSizeAxes = Axes.None,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
PathRadius = 1,
|
||||
},
|
||||
pathCenterWide = new SmoothPath
|
||||
{
|
||||
AutoSizeAxes = Axes.None,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
PathRadius = 2,
|
||||
},
|
||||
pathRight = new SmoothPath
|
||||
{
|
||||
AutoSizeAxes = Axes.None,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
PathRadius = 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Y = 4,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Font = OsuFont.Torus.With(size: 10, weight: FontWeight.Bold),
|
||||
Spacing = new Vector2(3, 0),
|
||||
Text = ButtonSystemStrings.RankedPlay.ToUpper(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private void recomputePaths()
|
||||
{
|
||||
const int top = 2; // to account for the middle segment being twice as wide
|
||||
const int bottom = 10;
|
||||
const int curve_smoothness = 5;
|
||||
|
||||
pathCenter.AddVertex(new Vector2(30, top));
|
||||
pathCenter.AddVertex(new Vector2(DrawWidth - 30, top));
|
||||
|
||||
pathCenterWide.AddVertex(new Vector2(60, top));
|
||||
pathCenterWide.AddVertex(new Vector2(DrawWidth - 60, top));
|
||||
|
||||
const int left_start = 0;
|
||||
const int left_corner = 10;
|
||||
const int left_end = 20;
|
||||
|
||||
List<Vector2> vertices = new List<Vector2>();
|
||||
var diagonalDirLeft = (new Vector2(left_start, bottom) - new Vector2(left_corner, top)).Normalized();
|
||||
|
||||
var sliderPathLeft = new SliderPath(new[]
|
||||
{
|
||||
new PathControlPoint(new Vector2(left_start, bottom), PathType.LINEAR),
|
||||
new PathControlPoint(new Vector2(left_corner, top) + diagonalDirLeft * curve_smoothness, PathType.BEZIER),
|
||||
new PathControlPoint(new Vector2(left_corner, top)),
|
||||
new PathControlPoint(new Vector2(left_end, top), PathType.LINEAR),
|
||||
});
|
||||
|
||||
sliderPathLeft.GetPathToProgress(vertices, 0.0, 1.0);
|
||||
pathLeft.Vertices = vertices;
|
||||
|
||||
float rightStart = DrawWidth;
|
||||
float rightCorner = rightStart - 10;
|
||||
float rightEnd = rightStart - 20;
|
||||
|
||||
var diagonalDirRight = (new Vector2(rightStart, bottom) - new Vector2(rightCorner, top)).Normalized();
|
||||
var sliderPathRight = new SliderPath(new[]
|
||||
{
|
||||
new PathControlPoint(new Vector2(rightStart, bottom), PathType.LINEAR),
|
||||
new PathControlPoint(new Vector2(rightCorner, top) + diagonalDirRight * curve_smoothness, PathType.BEZIER),
|
||||
new PathControlPoint(new Vector2(rightCorner, top)),
|
||||
new PathControlPoint(new Vector2(rightEnd, top), PathType.LINEAR),
|
||||
});
|
||||
|
||||
sliderPathRight.GetPathToProgress(vertices, 0.0, 1.0);
|
||||
pathRight.Vertices = vertices;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (!layout.IsValid)
|
||||
{
|
||||
recomputePaths();
|
||||
layout.Validate();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
this.FadeIn(500, Easing.OutQuint);
|
||||
// TODO: animate this better.
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
this.FadeOut(500, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user