1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-21 15:50:38 +08:00

Ranked play general UI/UX fixes (#37220)

This commit is contained in:
Dean Herbert
2026-04-07 15:33:29 +09:00
committed by GitHub
Unverified
parent ea0c04ae4f
commit e80e5f37ec
9 changed files with 167 additions and 274 deletions
@@ -9,12 +9,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
public partial class TrianglesPiece : Triangles
{
protected override bool CreateNewTriangles => false;
protected override float SpawnRatio => 0.5f;
public TrianglesPiece(int? seed = null)
: base(seed)
{
TriangleScale = 1.2f;
SpawnRatio = 0.5f;
HideAlphaDiscrepancies = false;
ClampAxes = Axes.None;
}
@@ -17,7 +17,6 @@ namespace osu.Game.Tests.Visual.RankedPlay
private readonly Bindable<Colour4> gradientOuter = new Bindable<Colour4>(Color4Extensions.FromHex("AC6D97"));
private readonly Bindable<Colour4> gradientInner = new Bindable<Colour4>(Color4Extensions.FromHex("544483"));
private readonly Bindable<Colour4> dots = new Bindable<Colour4>(Color4Extensions.FromHex("D56CF6"));
public TestSceneRankedPlayBackground()
{
@@ -40,11 +39,6 @@ namespace osu.Game.Tests.Visual.RankedPlay
Scale = new Vector2(0.4f),
Current = gradientInner,
},
new BasicColourPicker
{
Scale = new Vector2(0.4f),
Current = dots,
}
]
}
];
@@ -54,9 +48,8 @@ namespace osu.Game.Tests.Visual.RankedPlay
{
base.LoadComplete();
gradientOuter.BindValueChanged(e => background.GradientOutside = e.NewValue, true);
gradientInner.BindValueChanged(e => background.GradientInside = e.NewValue, true);
dots.BindValueChanged(e => background.DotsColour = e.NewValue, true);
gradientOuter.BindValueChanged(e => background.GradientBottom = e.NewValue, true);
gradientInner.BindValueChanged(e => background.GradientTop = e.NewValue, true);
}
}
}
+1 -1
View File
@@ -66,7 +66,7 @@ namespace osu.Game.Graphics.Backgrounds
/// <summary>
/// The amount of triangles we want compared to the default distribution.
/// </summary>
protected virtual float SpawnRatio => 1;
public float SpawnRatio { get; set; } = 1;
private readonly BindableFloat triangleScale = new BindableFloat(1f);
@@ -11,6 +11,7 @@ using osu.Framework.Caching;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Layout;
using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay;
using osu.Game.Online.RankedPlay;
using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card;
@@ -57,6 +58,8 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand
{
RelativeSizeAxes = Axes.Both,
});
AddLayout(layoutBacking);
}
protected override void Update()
@@ -188,7 +191,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand
#region Layout
private readonly Cached layoutBacking = new Cached();
private readonly LayoutValue layoutBacking = new LayoutValue(Invalidation.DrawSize | Invalidation.MiscGeometry);
private readonly Cached drawOrderBacking = new Cached();
/// <summary>
@@ -5,7 +5,6 @@ using System;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -16,6 +15,7 @@ using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
{
@@ -25,7 +25,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
private Container<StarRatingDisplay> starContainer = null!;
private Container centerContainer = null!;
private OsuSpriteText title = null!;
private OsuSpriteText creatingMapPool = null!;
private OsuSpriteText explainer = null!;
private Sample? tickSample;
@@ -38,73 +37,87 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
[BackgroundDependencyLoader]
private void load(OsuColour colour, AudioManager audio)
{
RelativeSizeAxes = Axes.X;
Width = 600;
AutoSizeAxes = Axes.Y;
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Alpha = 0;
Padding = new MarginPadding { Horizontal = 100 };
Masking = true;
CornerRadius = 10;
InternalChild = new FillFlowContainer
InternalChild = new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Children =
[
title = new OsuSpriteText
RelativeSizeAxes = Axes.X,
Children = new Drawable[]
{
new Box
{
Text = "Finding Match Rating...",
Font = OsuFont.Style.Title,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Colour = Color4.Black,
Alpha = 0.2f,
RelativeSizeAxes = Axes.Both,
},
creatingMapPool = new OsuSpriteText
{
Text = "Creating a mappool...",
Font = OsuFont.Style.Heading1,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Margin = new MarginPadding { Bottom = 30 },
Alpha = 0,
AlwaysPresent = true,
},
centerContainer = new Container
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
Height = 90,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding(30),
Spacing = new Vector2(10),
Direction = FillDirection.Vertical,
Children =
[
bars = new Container<Bar>
title = new OsuSpriteText
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = 30 },
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Text = "Refining star difficulty range...",
Padding = new MarginPadding { Bottom = 20 },
Font = OsuFont.Style.Title,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
},
]
},
starContainer = new Container<StarRatingDisplay>
{
RelativeSizeAxes = Axes.X,
Height = 20,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
},
explainer = new OsuSpriteText
{
Text = "Theres still a chance that you get maps outside of the selected match rating!",
Font = OsuFont.Style.Heading2,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Margin = new MarginPadding { Top = 20 },
Alpha = 0,
AlwaysPresent = true,
centerContainer = new Container
{
RelativeSizeAxes = Axes.X,
Height = 90,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Masking = true,
CornerRadius = 8,
Children =
[
new Box
{
Alpha = 0.4f,
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both,
},
bars = new Container<Bar>
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = 40, Horizontal = 3 },
},
]
},
starContainer = new Container<StarRatingDisplay>
{
RelativeSizeAxes = Axes.X,
Height = 20,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
},
explainer = new OsuSpriteText
{
Text = "Difficulty range is calculated to suit the two players.",
Padding = new MarginPadding { Top = 20 },
Font = OsuFont.Style.Heading2,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Alpha = 0,
AlwaysPresent = true,
}
],
}
],
}
};
for (int i = 0; i < 100; i++)
@@ -153,16 +166,15 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
private bool animateGaussianCurve;
[Resolved]
private OsuColour colours { get; set; } = null!;
public void Play(ref double delay, float starRating)
{
using (BeginDelayedSequence(delay))
{
popIn();
}
delay += 500;
using (BeginDelayedSequence(delay))
using (BeginDelayedSequence(delay += 500))
{
Schedule(() => animateGaussianCurve = true);
@@ -170,11 +182,12 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
this.TransformTo(nameof(starRating), starRating, 4000, new CubicBezierEasingFunction(easeIn: 0.3, easeOut: 0.5));
this.TransformTo(nameof(amplitude), 1f, 4000, new CubicBezierEasingFunction(easeIn: 0.1, easeOut: 0.8));
this.TransformTo(nameof(stdDev), 0.3f, 4500, new CubicBezierEasingFunction(easeIn: 0.2, easeOut: 0.7));
explainer.Delay(400)
.FadeIn(200);
}
delay += 5000;
using (BeginDelayedSequence(delay))
using (BeginDelayedSequence(delay += 5000))
{
Schedule(() =>
{
@@ -190,8 +203,8 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
AutoSizeAxes = Axes.Both,
RelativePositionAxes = Axes.X,
X = starRating * 0.1f,
Y = 24,
Colour = Color4Extensions.FromHex("#FFE280"),
Y = 34,
Colour = colours.ForStarDifficulty(starRating),
Spacing = new Vector2(4, 0),
Children =
[
@@ -218,14 +231,17 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
.ScaleTo(0)
.ScaleTo(1, 400, Easing.OutElasticQuarter);
title.Text = "Match rating found!";
title.Text = "Star rating has been decided!";
creatingMapPool.FadeIn(100);
explainer.Delay(1050).FadeIn(100);
Scheduler.AddDelayed(() =>
using (BeginDelayedSequence(1050))
{
noticeSample?.Play();
}, 1050);
explainer.FadeInFromZero(200);
Schedule(() =>
{
explainer.Text = "There's always a chance that you get maps outside this range";
noticeSample?.Play();
});
}
});
}
}
@@ -279,13 +295,15 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
if (!animateGaussianCurve)
return;
const float min_alpha = 0.4f;
foreach (var bar in bars)
{
float value = gaussianCurve(bar.StarRating, 1f, starRating, stdDev);
bar.Height = float.Lerp(0.1f, 1f, value * amplitude);
float targetAlpha = float.Clamp(0.35f + value * 20f, 0.35f, 1);
float targetAlpha = float.Clamp(min_alpha + value * 20f, min_alpha, 1);
bar.Alpha = float.Lerp(targetAlpha, bar.Alpha, (float)Math.Exp(-0.01f * Time.Elapsed));
}
@@ -294,7 +312,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
{
float value = gaussianCurve(child.X * 10f, 1f, starRating, stdDev);
float targetAlpha = float.Clamp(0.35f + value * 20f, 0.35f, 1);
float targetAlpha = float.Clamp(min_alpha + value * 20f, min_alpha, 1);
child.Alpha = float.Lerp(targetAlpha, child.Alpha, (float)Math.Exp(-0.01f * Time.Elapsed));
}
@@ -1,213 +1,81 @@
// 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 System.Runtime.InteropServices;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Graphics.Shaders;
using osu.Framework.Graphics.Shaders.Types;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Utils;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Backgrounds;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
{
public partial class RankedPlayBackground : CompositeDrawable, IBufferedDrawable
public partial class RankedPlayBackground : CompositeDrawable
{
public float GridSize = 10;
public Color4 GradientBottom = Color4Extensions.FromHex("#15061e");
public Color4 GradientTop = Color4Extensions.FromHex("#240d36");
public IShader? TextureShader { get; private set; }
public Color4 BackgroundColour => Color4.Black;
public DrawColourInfo? FrameBufferDrawColour => null;
public Vector2 FrameBufferScale => new Vector2(0.1f);
private BufferedContainer triangles1Buffered = null!;
private Box bgBox = null!;
private TrianglesV2 triangles2 = null!;
public Color4 GradientOutside = Color4Extensions.FromHex("AC6D97");
public Color4 GradientInside = Color4Extensions.FromHex("544483");
public Color4 DotsColour = Color4Extensions.FromHex("6b2980");
public RankedPlayBackground()
[BackgroundDependencyLoader]
private void load()
{
InternalChildren =
[
new Triangles
bgBox = new Box
{
RelativeSizeAxes = Axes.Both,
},
triangles1Buffered = new BufferedContainer
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Triangles
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(0.5f, 1),
SpawnRatio = 1.4f,
ClampAxes = Axes.Y,
Velocity = 0.5f,
TriangleScale = 4,
ColourLight = Color4.White,
ColourDark = Color4.White,
RelativeSizeAxes = Axes.Both,
},
}
},
triangles2 = new TrianglesV2
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(0.4f, 1),
SpawnRatio = 2,
ClampAxes = Axes.Y,
RelativeSizeAxes = Axes.Both,
},
];
}
[BackgroundDependencyLoader]
private void load(ShaderManager shaders)
public void FadeColours(Color4 top, Color4 bottom)
{
TextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, @"RankedPlayBackground");
this.TransformTo(nameof(GradientTop), top, 1500, Easing.OutQuint);
this.TransformTo(nameof(GradientBottom), bottom, 1500, Easing.OutQuint);
}
private readonly BufferedDrawNodeSharedData sharedData = new BufferedDrawNodeSharedData();
protected override void Update()
{
base.Update();
Invalidate(Invalidation.DrawNode);
}
protected override DrawNode CreateDrawNode() => new RankedPlayBackgroundDrawNode(this, sharedData);
protected override void Dispose(bool isDisposing)
{
sharedData.Dispose();
base.Dispose(isDisposing);
}
private class RankedPlayBackgroundDrawNode : BufferedDrawNode, ICompositeDrawNode
{
protected new RankedPlayBackground Source => (RankedPlayBackground)base.Source;
protected new CompositeDrawableDrawNode Child => (CompositeDrawableDrawNode)base.Child;
public RankedPlayBackgroundDrawNode(RankedPlayBackground source, BufferedDrawNodeSharedData sharedData)
: base(source, new CompositeDrawableDrawNode(source), sharedData)
{
}
private Vector2 drawSize;
private float time;
private float gridSize;
private Color4 gradientOutside;
private Color4 gradientInside;
private Color4 dotsColour;
private IUniformBuffer<RankedPlayBackgroundParameters>? shaderParameterBuffer;
public override void ApplyState()
{
base.ApplyState();
time = (float)(Source.Time.Current / 1000);
drawSize = Source.DrawSize;
gridSize = Source.GridSize;
gradientOutside = Source.GradientOutside;
gradientInside = Source.GradientInside;
dotsColour = Source.DotsColour;
}
protected override void BindUniformResources(IShader shader, IRenderer renderer)
{
shaderParameterBuffer ??= renderer.CreateUniformBuffer<RankedPlayBackgroundParameters>();
shaderParameterBuffer.Data = new RankedPlayBackgroundParameters
{
DrawSize = drawSize,
Time = time,
GridSize = gridSize,
GradientOutside = new Vector4(gradientOutside.R, gradientOutside.G, gradientOutside.B, gradientOutside.A),
GradientInside = new Vector4(gradientInside.R, gradientInside.G, gradientInside.B, gradientInside.A),
DotsColour = new Vector4(dotsColour.R, dotsColour.G, dotsColour.B, dotsColour.A),
};
shader.BindUniformBlock("m_RankedPlayBackgroundParameters", shaderParameterBuffer);
}
public List<DrawNode>? Children
{
get => Child.Children;
set => Child.Children = value;
}
public bool AddChildDrawNodes => RequiresRedraw;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private record struct RankedPlayBackgroundParameters
{
public UniformVector2 DrawSize;
public UniformFloat Time;
public UniformFloat GridSize;
public UniformVector4 GradientOutside;
public UniformVector4 GradientInside;
public UniformVector4 DotsColour;
}
}
public partial class Triangles : CompositeDrawable
{
private Texture triangleTexture = null!;
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
triangleTexture = textures.Get("Online/RankedPlay/triangle");
}
protected override void LoadComplete()
{
base.LoadComplete();
for (int i = 0; i < 20; i++)
{
AddInternal(new Triangle
{
Texture = triangleTexture,
RelativePositionAxes = Axes.Both,
X = RNG.NextSingle(),
Y = -0.2f + RNG.NextSingle() * 1.4f,
Origin = Anchor.Centre,
Rotation = RNG.NextSingle() * 360,
AngularVelocity = RNG.NextSingle() - 0.75f,
Size = new Vector2(100 + RNG.NextSingle() * 1000),
MovementSpeed = 0.25f + RNG.NextSingle() * 0.75f,
Alpha = 0.5f + RNG.NextSingle() * 0.5f,
});
}
}
public float ParticleVelocity = 1;
protected override void Update()
{
base.Update();
if (DrawHeight <= 0)
return;
float baseVelocity = 0.03f * ParticleVelocity / DrawHeight;
float elapsed = (float)Time.Elapsed;
foreach (var c in InternalChildren)
{
var triangle = (Triangle)c;
triangle.Y -= baseVelocity * elapsed * triangle.MovementSpeed;
triangle.Rotation += triangle.AngularVelocity * elapsed * 0.02f;
// wrap vertically
if (triangle.Y < -0.2f)
{
triangle.X = RNG.NextSingle();
triangle.Y = 1.2f;
triangle.Alpha = 0.5f + RNG.NextSingle() * 0.5f;
}
else if (triangle.Y > 1.2f)
{
triangle.X = RNG.NextSingle();
triangle.Y = -0.2f;
triangle.Alpha = 0.5f + RNG.NextSingle() * 0.5f;
}
}
}
private partial class Triangle : Sprite
{
public float MovementSpeed = 1;
public float AngularVelocity;
}
bgBox.Colour = ColourInfo.GradientVertical(GradientTop, GradientBottom);
triangles1Buffered.Colour = ColourInfo.GradientVertical(GradientTop.Lighten(0.2f), GradientBottom.Lighten(0.2f));
triangles2.Colour = GradientTop.Lighten(0.5f);
}
}
}
@@ -16,21 +16,29 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
{
public partial class RankedPlayBackgroundScreen : BackgroundScreen
{
public RankedPlayBackground Background { get; }
private RankedPlayBackground background { get; }
[Resolved]
private Bindable<WorkingBeatmap> beatmap { get; set; } = null!;
public Bindable<bool> ShowBeatmapBackground { get; } = new BindableBool();
public RankedPlayColourScheme? ColourScheme
{
set
{
if (value != null)
background.FadeColours(value.PrimaryDarker.Darken(0.5f), value.PrimaryDarkest.Darken(0.5f));
else
background.FadeColours(Color4Extensions.FromHex("#15061e"), Color4Extensions.FromHex("#240d36"));
}
}
public RankedPlayBackgroundScreen()
{
InternalChild = Background = new RankedPlayBackground
InternalChild = background = new RankedPlayBackground
{
RelativeSizeAxes = Axes.Both,
GradientOutside = Color4Extensions.FromHex("716BE0"),
GradientInside = Color4Extensions.FromHex("#71308F"),
DotsColour = Color4Extensions.FromHex("#CC46F6").Opacity(0.5f),
};
}
@@ -46,7 +46,9 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
public RankedPlaySubScreen? ActiveSubScreen { get; private set; }
protected override BackgroundScreen CreateBackground() => new RankedPlayBackgroundScreen
private RankedPlayBackgroundScreen rankedPlayBackground = null!;
protected override BackgroundScreen CreateBackground() => rankedPlayBackground = new RankedPlayBackgroundScreen
{
ShowBeatmapBackground = { BindTarget = showBeatmapBackground }
};
@@ -235,6 +237,12 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
PickingUser = pickingUser,
Multiplier = multiplier,
});
rankedPlayBackground.ColourScheme = colourScheme;
}
else
{
rankedPlayBackground.ColourScheme = null;
}
};
}
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
@@ -18,9 +17,8 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
private void load()
{
Masking = true;
CornerRadius = 6;
BorderThickness = 2;
BorderColour = colours.PrimaryDarkest.Darken(0.35f);
CornerRadius = 4;
CornerExponent = 4;
InternalChildren =
[
@@ -48,9 +46,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
Masking = true,
CornerRadius = 3,
Colour = ColourInfo.GradientHorizontal(Colour4.White, Colour4.White.Opacity(0)),
BorderThickness = 3,
BorderColour = ColourInfo.GradientVertical(Colour4.White, Colour4.White.Opacity(0)),
Alpha = 0.25f,
Blending = BlendingParameters.Additive,
Child = new Box
{