mirror of
https://github.com/osukey/osukey.git
synced 2025-08-03 22:56:36 +09:00
Implement the accuracy circle
This commit is contained in:
253
osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs
Normal file
253
osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs
Normal file
@ -0,0 +1,253 @@
|
||||
// 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 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.Utils;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Scoring;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Ranking.Expanded.Accuracy
|
||||
{
|
||||
/// <summary>
|
||||
/// The component that displays the player's accuracy on the results screen.
|
||||
/// </summary>
|
||||
public class AccuracyCircle : CompositeDrawable
|
||||
{
|
||||
/// <summary>
|
||||
/// Duration for the transforms causing this component to appear.
|
||||
/// </summary>
|
||||
public const double APPEAR_DURATION = 200;
|
||||
|
||||
/// <summary>
|
||||
/// Delay before the accuracy circle starts filling.
|
||||
/// </summary>
|
||||
public const double ACCURACY_TRANSFORM_DELAY = 450;
|
||||
|
||||
/// <summary>
|
||||
/// Duration for the accuracy circle fill.
|
||||
/// </summary>
|
||||
public const double ACCURACY_TRANSFORM_DURATION = 3000;
|
||||
|
||||
/// <summary>
|
||||
/// Delay after <see cref="ACCURACY_TRANSFORM_DURATION"/> for the rank text (A/B/C/D/S/SS) to appear.
|
||||
/// </summary>
|
||||
public const double TEXT_APPEAR_DELAY = ACCURACY_TRANSFORM_DURATION / 2;
|
||||
|
||||
/// <summary>
|
||||
/// Delay before the rank circles start filling.
|
||||
/// </summary>
|
||||
public const double RANK_CIRCLE_TRANSFORM_DELAY = 150;
|
||||
|
||||
/// <summary>
|
||||
/// Duration for the rank circle fills.
|
||||
/// </summary>
|
||||
public const double RANK_CIRCLE_TRANSFORM_DURATION = 800;
|
||||
|
||||
/// <summary>
|
||||
/// Relative width of the rank circles.
|
||||
/// </summary>
|
||||
public const float RANK_CIRCLE_RADIUS = 0.06f;
|
||||
|
||||
/// <summary>
|
||||
/// Relative width of the circle showing the accuracy.
|
||||
/// </summary>
|
||||
private const float accuracy_circle_radius = 0.2f;
|
||||
|
||||
/// <summary>
|
||||
/// SS is displayed as a 1% region, otherwise it would be invisible.
|
||||
/// </summary>
|
||||
private const double virtual_ss_percentage = 0.01;
|
||||
|
||||
/// <summary>
|
||||
/// The easing for the circle filling transforms.
|
||||
/// </summary>
|
||||
public static readonly Easing ACCURACY_TRANSFORM_EASING = Easing.OutPow10;
|
||||
|
||||
private readonly ScoreInfo score;
|
||||
|
||||
private SmoothCircularProgress accuracyCircle;
|
||||
private SmoothCircularProgress innerMask;
|
||||
private Container<RankBadge> badges;
|
||||
private RankText rankText;
|
||||
|
||||
public AccuracyCircle(ScoreInfo score)
|
||||
{
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new SmoothCircularProgress
|
||||
{
|
||||
Name = "Background circle",
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.Gray(47),
|
||||
Alpha = 0.5f,
|
||||
InnerRadius = accuracy_circle_radius + 0.01f, // Extends a little bit into the circle
|
||||
Current = { Value = 1 },
|
||||
},
|
||||
accuracyCircle = new SmoothCircularProgress
|
||||
{
|
||||
Name = "Accuracy circle",
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#7CF6FF"), Color4Extensions.FromHex("#BAFFA9")),
|
||||
InnerRadius = accuracy_circle_radius,
|
||||
},
|
||||
new BufferedContainer
|
||||
{
|
||||
Name = "Graded circles",
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Size = new Vector2(0.8f),
|
||||
Padding = new MarginPadding(2),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SmoothCircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#BE0089"),
|
||||
InnerRadius = RANK_CIRCLE_RADIUS,
|
||||
Current = { Value = 1 }
|
||||
},
|
||||
new SmoothCircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#0096A2"),
|
||||
InnerRadius = RANK_CIRCLE_RADIUS,
|
||||
Current = { Value = 1 - virtual_ss_percentage }
|
||||
},
|
||||
new SmoothCircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#72C904"),
|
||||
InnerRadius = RANK_CIRCLE_RADIUS,
|
||||
Current = { Value = 0.95f }
|
||||
},
|
||||
new SmoothCircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#D99D03"),
|
||||
InnerRadius = RANK_CIRCLE_RADIUS,
|
||||
Current = { Value = 0.9f }
|
||||
},
|
||||
new SmoothCircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#EA7948"),
|
||||
InnerRadius = RANK_CIRCLE_RADIUS,
|
||||
Current = { Value = 0.8f }
|
||||
},
|
||||
new SmoothCircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#FF5858"),
|
||||
InnerRadius = RANK_CIRCLE_RADIUS,
|
||||
Current = { Value = 0.7f }
|
||||
},
|
||||
new RankNotch(0),
|
||||
new RankNotch((float)(1 - virtual_ss_percentage)),
|
||||
new RankNotch(0.95f),
|
||||
new RankNotch(0.9f),
|
||||
new RankNotch(0.8f),
|
||||
new RankNotch(0.7f),
|
||||
new BufferedContainer
|
||||
{
|
||||
Name = "Graded circle mask",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding(1),
|
||||
Blending = new BlendingParameters
|
||||
{
|
||||
Source = BlendingType.DstColor,
|
||||
Destination = BlendingType.OneMinusSrcAlpha,
|
||||
SourceAlpha = BlendingType.One,
|
||||
DestinationAlpha = BlendingType.SrcAlpha
|
||||
},
|
||||
Child = innerMask = new SmoothCircularProgress
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
InnerRadius = RANK_CIRCLE_RADIUS - 0.01f,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
badges = new Container<RankBadge>
|
||||
{
|
||||
Name = "Rank badges",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Vertical = -15, Horizontal = -20 },
|
||||
Children = new[]
|
||||
{
|
||||
new RankBadge(1f, ScoreRank.X),
|
||||
new RankBadge(0.95f, ScoreRank.S),
|
||||
new RankBadge(0.9f, ScoreRank.A),
|
||||
new RankBadge(0.8f, ScoreRank.B),
|
||||
new RankBadge(0.7f, ScoreRank.C),
|
||||
}
|
||||
},
|
||||
rankText = new RankText(score.Rank)
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
this.ScaleTo(0).Then().ScaleTo(1, APPEAR_DURATION, Easing.OutQuint);
|
||||
|
||||
using (BeginDelayedSequence(RANK_CIRCLE_TRANSFORM_DELAY, true))
|
||||
innerMask.FillTo(1f, RANK_CIRCLE_TRANSFORM_DURATION, ACCURACY_TRANSFORM_EASING);
|
||||
|
||||
using (BeginDelayedSequence(ACCURACY_TRANSFORM_DELAY, true))
|
||||
{
|
||||
double targetAccuracy = score.Rank == ScoreRank.X || score.Rank == ScoreRank.XH ? 1 : Math.Min(1 - virtual_ss_percentage, score.Accuracy);
|
||||
|
||||
accuracyCircle.FillTo(targetAccuracy, ACCURACY_TRANSFORM_DURATION, ACCURACY_TRANSFORM_EASING);
|
||||
|
||||
foreach (var badge in badges)
|
||||
{
|
||||
if (badge.Accuracy > score.Accuracy)
|
||||
continue;
|
||||
|
||||
using (BeginDelayedSequence(inverseEasing(ACCURACY_TRANSFORM_EASING, badge.Accuracy / targetAccuracy) * ACCURACY_TRANSFORM_DURATION, true))
|
||||
badge.Appear();
|
||||
}
|
||||
|
||||
using (BeginDelayedSequence(TEXT_APPEAR_DELAY, true))
|
||||
rankText.Appear();
|
||||
}
|
||||
}
|
||||
|
||||
private double inverseEasing(Easing easing, double targetValue)
|
||||
{
|
||||
double test = 0;
|
||||
double result = 0;
|
||||
int count = 2;
|
||||
|
||||
while (Math.Abs(result - targetValue) > 0.005)
|
||||
{
|
||||
int dir = Math.Sign(targetValue - result);
|
||||
|
||||
test += dir * 1.0 / count;
|
||||
result = Interpolation.ApplyEasing(easing, test);
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return test;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user