mirror of
https://github.com/ppy/osu.git
synced 2024-12-05 10:23:20 +08:00
Merge branch 'master' into results-top-content
This commit is contained in:
commit
75695938e2
@ -52,6 +52,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.315.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.314.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.317.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -417,7 +417,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
[Test]
|
||||
public async Task TestImportWithDuplicateHashes()
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportNestedStructure)))
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestImportWithDuplicateHashes)))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
155
osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs
Normal file
155
osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs
Normal file
@ -0,0 +1,155 @@
|
||||
// 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.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking.Expanded.Accuracy;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
public class TestSceneAccuracyCircle : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(AccuracyCircle),
|
||||
typeof(RankBadge),
|
||||
typeof(RankNotch),
|
||||
typeof(RankText),
|
||||
typeof(SmoothCircularProgress)
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestDRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.5;
|
||||
score.Rank = ScoreRank.D;
|
||||
|
||||
addCircleStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.75;
|
||||
score.Rank = ScoreRank.C;
|
||||
|
||||
addCircleStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.85;
|
||||
score.Rank = ScoreRank.B;
|
||||
|
||||
addCircleStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestARank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.925;
|
||||
score.Rank = ScoreRank.A;
|
||||
|
||||
addCircleStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.975;
|
||||
score.Rank = ScoreRank.S;
|
||||
|
||||
addCircleStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAlmostSSRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 0.9999;
|
||||
score.Rank = ScoreRank.S;
|
||||
|
||||
addCircleStep(score);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSSRank()
|
||||
{
|
||||
var score = createScore();
|
||||
score.Accuracy = 1;
|
||||
score.Rank = ScoreRank.X;
|
||||
|
||||
addCircleStep(score);
|
||||
}
|
||||
|
||||
private void addCircleStep(ScoreInfo score) => AddStep("add panel", () =>
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(500, 700),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#555"), Color4Extensions.FromHex("#333"))
|
||||
}
|
||||
}
|
||||
},
|
||||
new AccuracyCircle(score)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(230)
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
private ScoreInfo createScore() => new ScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
Id = 2,
|
||||
Username = "peppy",
|
||||
},
|
||||
Beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo,
|
||||
Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() },
|
||||
TotalScore = 2845370,
|
||||
Accuracy = 0.95,
|
||||
MaxCombo = 999,
|
||||
Rank = ScoreRank.S,
|
||||
Date = DateTimeOffset.Now,
|
||||
Statistics =
|
||||
{
|
||||
{ HitResult.Miss, 1 },
|
||||
{ HitResult.Meh, 50 },
|
||||
{ HitResult.Good, 100 },
|
||||
{ HitResult.Great, 300 },
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
// 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.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Tournament.Components;
|
||||
using osu.Game.Tournament.Models;
|
||||
|
||||
namespace osu.Game.Tournament.Tests.Components
|
||||
{
|
||||
public class TestSceneRoundDisplay : TournamentTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(DrawableTournamentHeaderText),
|
||||
typeof(DrawableTournamentHeaderLogo),
|
||||
};
|
||||
|
||||
public TestSceneRoundDisplay()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new RoundDisplay(new TournamentMatch
|
||||
{
|
||||
Round =
|
||||
{
|
||||
Value = new TournamentRound
|
||||
{
|
||||
Name = { Value = "Test Round" }
|
||||
}
|
||||
}
|
||||
})
|
||||
{
|
||||
Margin = new MarginPadding(20)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -11,9 +11,13 @@ namespace osu.Game.Tournament.Components
|
||||
{
|
||||
public class DrawableTournamentHeaderText : CompositeDrawable
|
||||
{
|
||||
public DrawableTournamentHeaderText()
|
||||
public DrawableTournamentHeaderText(bool center = true)
|
||||
{
|
||||
InternalChild = new TextSprite();
|
||||
InternalChild = new TextSprite
|
||||
{
|
||||
Anchor = center ? Anchor.Centre : Anchor.TopLeft,
|
||||
Origin = center ? Anchor.Centre : Anchor.TopLeft,
|
||||
};
|
||||
|
||||
Height = 22;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
@ -27,9 +31,6 @@ namespace osu.Game.Tournament.Components
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
FillMode = FillMode.Fit;
|
||||
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
Texture = textures.Get("header-text");
|
||||
}
|
||||
}
|
||||
|
@ -12,19 +12,27 @@ namespace osu.Game.Tournament.Components
|
||||
{
|
||||
public RoundDisplay(TournamentMatch match)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new DrawableTournamentHeaderText(),
|
||||
new DrawableTournamentHeaderText(false)
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
},
|
||||
new TournamentSpriteText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Text = match.Round.Value?.Name.Value ?? "Unknown Round",
|
||||
Font = OsuFont.Torus.With(size: 26, weight: FontWeight.SemiBold)
|
||||
},
|
||||
|
@ -35,7 +35,9 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
|
||||
private void load(LadderInfo ladder)
|
||||
{
|
||||
currentMatch.BindTo(ladder.CurrentMatch);
|
||||
currentMatch.BindValueChanged(matchChanged, true);
|
||||
currentMatch.BindValueChanged(matchChanged);
|
||||
|
||||
updateMatch();
|
||||
}
|
||||
|
||||
private void matchChanged(ValueChangedEvent<TournamentMatch> match)
|
||||
@ -43,10 +45,19 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
|
||||
currentTeamScore.UnbindBindings();
|
||||
currentTeam.UnbindBindings();
|
||||
|
||||
if (match.NewValue != null)
|
||||
Scheduler.AddOnce(updateMatch);
|
||||
}
|
||||
|
||||
private void updateMatch()
|
||||
{
|
||||
var match = currentMatch.Value;
|
||||
|
||||
if (match != null)
|
||||
{
|
||||
currentTeamScore.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1Score : match.NewValue.Team2Score);
|
||||
currentTeam.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1 : match.NewValue.Team2);
|
||||
match.StartMatch();
|
||||
|
||||
currentTeamScore.BindTo(teamColour == TeamColour.Red ? match.Team1Score : match.Team2Score);
|
||||
currentTeam.BindTo(teamColour == TeamColour.Red ? match.Team1 : match.Team2);
|
||||
}
|
||||
|
||||
// team may change to same team, which means score is not in a good state.
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Scoring;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Graphics
|
||||
@ -37,6 +38,35 @@ namespace osu.Game.Graphics
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the colour for a <see cref="ScoreRank"/>.
|
||||
/// </summary>
|
||||
public static Color4 ForRank(ScoreRank rank)
|
||||
{
|
||||
switch (rank)
|
||||
{
|
||||
case ScoreRank.XH:
|
||||
case ScoreRank.X:
|
||||
return Color4Extensions.FromHex(@"ce1c9d");
|
||||
|
||||
case ScoreRank.SH:
|
||||
case ScoreRank.S:
|
||||
return Color4Extensions.FromHex(@"00a8b5");
|
||||
|
||||
case ScoreRank.A:
|
||||
return Color4Extensions.FromHex(@"7cce14");
|
||||
|
||||
case ScoreRank.B:
|
||||
return Color4Extensions.FromHex(@"e3b130");
|
||||
|
||||
case ScoreRank.C:
|
||||
return Color4Extensions.FromHex(@"f18252");
|
||||
|
||||
default:
|
||||
return Color4Extensions.FromHex(@"e95353");
|
||||
}
|
||||
}
|
||||
|
||||
// See https://github.com/ppy/osu-web/blob/master/resources/assets/less/colors.less
|
||||
public readonly Color4 PurpleLighter = Color4Extensions.FromHex(@"eeeeff");
|
||||
public readonly Color4 PurpleLight = Color4Extensions.FromHex(@"aa88ff");
|
||||
|
@ -136,5 +136,10 @@ namespace osu.Game.Graphics
|
||||
/// Equivalent to weight 700.
|
||||
/// </summary>
|
||||
Bold = 700,
|
||||
|
||||
/// <summary>
|
||||
/// Equivalent to weight 900.
|
||||
/// </summary>
|
||||
Black = 900
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,18 @@ namespace osu.Game.Graphics.Sprites
|
||||
set => blurredText.Colour = value;
|
||||
}
|
||||
|
||||
public Vector2 Spacing
|
||||
{
|
||||
get => spriteText.Spacing;
|
||||
set => spriteText.Spacing = blurredText.Spacing = value;
|
||||
}
|
||||
|
||||
public bool UseFullGlyphHeight
|
||||
{
|
||||
get => spriteText.UseFullGlyphHeight;
|
||||
set => spriteText.UseFullGlyphHeight = blurredText.UseFullGlyphHeight = value;
|
||||
}
|
||||
|
||||
public GlowingSpriteText()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Online.Leaderboards
|
||||
FillMode = FillMode.Fit;
|
||||
FillAspectRatio = 2;
|
||||
|
||||
var rankColour = getRankColour();
|
||||
var rankColour = OsuColour.ForRank(rank);
|
||||
InternalChild = new DrawSizePreservingFillContainer
|
||||
{
|
||||
TargetDrawSize = new Vector2(64, 32),
|
||||
@ -59,7 +59,7 @@ namespace osu.Game.Online.Leaderboards
|
||||
Padding = new MarginPadding { Top = 5 },
|
||||
Colour = getRankNameColour(),
|
||||
Font = OsuFont.Numeric.With(size: 25),
|
||||
Text = getRankName(),
|
||||
Text = GetRankName(rank),
|
||||
ShadowColour = Color4.Black.Opacity(0.3f),
|
||||
ShadowOffset = new Vector2(0, 0.08f),
|
||||
Shadow = true,
|
||||
@ -69,36 +69,7 @@ namespace osu.Game.Online.Leaderboards
|
||||
};
|
||||
}
|
||||
|
||||
private string getRankName() => rank.GetDescription().TrimEnd('+');
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the grade background colour.
|
||||
/// </summary>
|
||||
private Color4 getRankColour()
|
||||
{
|
||||
switch (rank)
|
||||
{
|
||||
case ScoreRank.XH:
|
||||
case ScoreRank.X:
|
||||
return Color4Extensions.FromHex(@"ce1c9d");
|
||||
|
||||
case ScoreRank.SH:
|
||||
case ScoreRank.S:
|
||||
return Color4Extensions.FromHex(@"00a8b5");
|
||||
|
||||
case ScoreRank.A:
|
||||
return Color4Extensions.FromHex(@"7cce14");
|
||||
|
||||
case ScoreRank.B:
|
||||
return Color4Extensions.FromHex(@"e3b130");
|
||||
|
||||
case ScoreRank.C:
|
||||
return Color4Extensions.FromHex(@"f18252");
|
||||
|
||||
default:
|
||||
return Color4Extensions.FromHex(@"e95353");
|
||||
}
|
||||
}
|
||||
public static string GetRankName(ScoreRank rank) => rank.GetDescription().TrimEnd('+');
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the grade text colour.
|
||||
|
@ -401,14 +401,18 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
protected virtual ScoreInfo CreateScore()
|
||||
{
|
||||
var score = DrawableRuleset.ReplayScore?.ScoreInfo ?? new ScoreInfo
|
||||
var score = new ScoreInfo
|
||||
{
|
||||
Beatmap = Beatmap.Value.BeatmapInfo,
|
||||
Ruleset = rulesetInfo,
|
||||
Mods = Mods.Value.ToArray(),
|
||||
User = api.LocalUser.Value,
|
||||
};
|
||||
|
||||
if (DrawableRuleset.ReplayScore != null)
|
||||
score.User = DrawableRuleset.ReplayScore.ScoreInfo?.User ?? new GuestUser();
|
||||
else
|
||||
score.User = api.LocalUser.Value;
|
||||
|
||||
ScoreProcessor.PopulateScore(score);
|
||||
|
||||
return score;
|
||||
|
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, Math.Min(1 - virtual_ss_percentage, 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;
|
||||
}
|
||||
}
|
||||
}
|
99
osu.Game/Screens/Ranking/Expanded/Accuracy/RankBadge.cs
Normal file
99
osu.Game/Screens/Ranking/Expanded/Accuracy/RankBadge.cs
Normal file
@ -0,0 +1,99 @@
|
||||
// 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.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Online.Leaderboards;
|
||||
using osu.Game.Scoring;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Ranking.Expanded.Accuracy
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains a <see cref="DrawableRank"/> that is positioned around the <see cref="AccuracyCircle"/>.
|
||||
/// </summary>
|
||||
public class RankBadge : CompositeDrawable
|
||||
{
|
||||
/// <summary>
|
||||
/// The accuracy value corresponding to the <see cref="ScoreRank"/> displayed by this badge.
|
||||
/// </summary>
|
||||
public readonly float Accuracy;
|
||||
|
||||
private readonly ScoreRank rank;
|
||||
|
||||
private Drawable rankContainer;
|
||||
private Drawable overlay;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="RankBadge"/>.
|
||||
/// </summary>
|
||||
/// <param name="accuracy">The accuracy value corresponding to <paramref name="rank"/>.</param>
|
||||
/// <param name="rank">The <see cref="ScoreRank"/> to be displayed in this <see cref="RankBadge"/>.</param>
|
||||
public RankBadge(float accuracy, ScoreRank rank)
|
||||
{
|
||||
Accuracy = accuracy;
|
||||
this.rank = rank;
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Alpha = 0;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChild = rankContainer = new Container
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(28, 14),
|
||||
Children = new[]
|
||||
{
|
||||
new DrawableRank(rank),
|
||||
overlay = new CircularContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Blending = BlendingParameters.Additive,
|
||||
Masking = true,
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Colour = OsuColour.ForRank(rank).Opacity(0.2f),
|
||||
Radius = 10,
|
||||
},
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows this <see cref="RankBadge"/>.
|
||||
/// </summary>
|
||||
public void Appear()
|
||||
{
|
||||
this.FadeIn(50);
|
||||
overlay.FadeIn().FadeOut(500, Easing.In);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
// Starts at -90deg (top) and moves counter-clockwise by the accuracy
|
||||
rankContainer.Position = circlePosition(-MathF.PI / 2 - (1 - Accuracy) * MathF.PI * 2);
|
||||
}
|
||||
|
||||
private Vector2 circlePosition(float t)
|
||||
=> DrawSize / 2 + new Vector2(MathF.Cos(t), MathF.Sin(t)) * DrawSize / 2;
|
||||
}
|
||||
}
|
49
osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs
Normal file
49
osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs
Normal file
@ -0,0 +1,49 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Ranking.Expanded.Accuracy
|
||||
{
|
||||
/// <summary>
|
||||
/// A solid "notch" of the <see cref="AccuracyCircle"/> that appears at the ends of the rank circles to add separation.
|
||||
/// </summary>
|
||||
public class RankNotch : CompositeDrawable
|
||||
{
|
||||
private readonly float position;
|
||||
|
||||
public RankNotch(float position)
|
||||
{
|
||||
this.position = position;
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChild = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Rotation = position * 360f,
|
||||
Child = new Box
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Height = AccuracyCircle.RANK_CIRCLE_RADIUS,
|
||||
Width = 1f,
|
||||
Colour = OsuColour.Gray(0.3f),
|
||||
EdgeSmoothness = new Vector2(1f)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
137
osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs
Normal file
137
osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs
Normal file
@ -0,0 +1,137 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.Leaderboards;
|
||||
using osu.Game.Scoring;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Ranking.Expanded.Accuracy
|
||||
{
|
||||
/// <summary>
|
||||
/// The text that appears in the middle of the <see cref="AccuracyCircle"/> displaying the user's rank.
|
||||
/// </summary>
|
||||
public class RankText : CompositeDrawable
|
||||
{
|
||||
private readonly ScoreRank rank;
|
||||
|
||||
private BufferedContainer flash;
|
||||
private BufferedContainer superFlash;
|
||||
private GlowingSpriteText rankText;
|
||||
|
||||
public RankText(ScoreRank rank)
|
||||
{
|
||||
this.rank = rank;
|
||||
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
Alpha = 0;
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
rankText = new GlowingSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
GlowColour = OsuColour.ForRank(rank),
|
||||
Spacing = new Vector2(-15, 0),
|
||||
Text = DrawableRank.GetRankName(rank),
|
||||
Font = OsuFont.Numeric.With(size: 76),
|
||||
UseFullGlyphHeight = false
|
||||
},
|
||||
superFlash = new BufferedContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
BlurSigma = new Vector2(85),
|
||||
Size = new Vector2(600),
|
||||
CacheDrawnFrameBuffer = true,
|
||||
Blending = BlendingParameters.Additive,
|
||||
Alpha = 0,
|
||||
Children = new[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.White,
|
||||
Size = new Vector2(150),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
},
|
||||
},
|
||||
flash = new BufferedContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
BlurSigma = new Vector2(35),
|
||||
BypassAutoSizeAxes = Axes.Both,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
CacheDrawnFrameBuffer = true,
|
||||
Blending = BlendingParameters.Additive,
|
||||
Alpha = 0,
|
||||
Size = new Vector2(2f), // increase buffer size to allow for scale
|
||||
Scale = new Vector2(1.8f),
|
||||
Children = new[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Spacing = new Vector2(-15, 0),
|
||||
Text = DrawableRank.GetRankName(rank),
|
||||
Font = OsuFont.Numeric.With(size: 76),
|
||||
UseFullGlyphHeight = false,
|
||||
Shadow = false
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public void Appear()
|
||||
{
|
||||
this.FadeIn();
|
||||
|
||||
if (rank < ScoreRank.A)
|
||||
{
|
||||
this
|
||||
.MoveToOffset(new Vector2(0, -20))
|
||||
.MoveToOffset(new Vector2(0, 20), 200, Easing.OutBounce);
|
||||
|
||||
if (rank <= ScoreRank.D)
|
||||
{
|
||||
this.Delay(700)
|
||||
.RotateTo(5, 150, Easing.In)
|
||||
.MoveToOffset(new Vector2(0, 3), 150, Easing.In);
|
||||
}
|
||||
|
||||
this.FadeInFromZero(200, Easing.OutQuint);
|
||||
return;
|
||||
}
|
||||
|
||||
flash.Colour = OsuColour.ForRank(rank);
|
||||
flash.FadeIn().Then().FadeOut(1200, Easing.OutQuint);
|
||||
|
||||
if (rank >= ScoreRank.S)
|
||||
rankText.ScaleTo(1.05f).ScaleTo(1, 3000, Easing.OutQuint);
|
||||
|
||||
if (rank >= ScoreRank.X)
|
||||
{
|
||||
flash.FadeIn().Then().FadeOut(3000);
|
||||
superFlash.FadeIn().Then().FadeOut(800, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
// 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 osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Ranking.Expanded.Accuracy
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains a <see cref="CircularProgress"/> with smoothened edges.
|
||||
/// </summary>
|
||||
public class SmoothCircularProgress : CompositeDrawable
|
||||
{
|
||||
public Bindable<double> Current
|
||||
{
|
||||
get => progress.Current;
|
||||
set => progress.Current = value;
|
||||
}
|
||||
|
||||
public float InnerRadius
|
||||
{
|
||||
get => progress.InnerRadius;
|
||||
set
|
||||
{
|
||||
progress.InnerRadius = value;
|
||||
innerSmoothingContainer.Size = new Vector2(1 - value);
|
||||
smoothingWedge.Height = value / 2;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly CircularProgress progress;
|
||||
private readonly Container innerSmoothingContainer;
|
||||
private readonly Drawable smoothingWedge;
|
||||
|
||||
public SmoothCircularProgress()
|
||||
{
|
||||
Container smoothingWedgeContainer;
|
||||
|
||||
InternalChild = new BufferedContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
progress = new CircularProgress { RelativeSizeAxes = Axes.Both },
|
||||
smoothingWedgeContainer = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = smoothingWedge = new Box
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 1f,
|
||||
EdgeSmoothness = new Vector2(2, 0),
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding(-1),
|
||||
Child = new CircularContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
BorderThickness = 2,
|
||||
Masking = true,
|
||||
BorderColour = OsuColour.Gray(0.5f).Opacity(0.75f),
|
||||
Blending = new BlendingParameters
|
||||
{
|
||||
AlphaEquation = BlendingEquation.ReverseSubtract,
|
||||
},
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true
|
||||
}
|
||||
}
|
||||
},
|
||||
innerSmoothingContainer = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Size = Vector2.Zero,
|
||||
Padding = new MarginPadding(-1),
|
||||
Child = new CircularContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
BorderThickness = 2,
|
||||
BorderColour = OsuColour.Gray(0.5f).Opacity(0.75f),
|
||||
Masking = true,
|
||||
Blending = new BlendingParameters
|
||||
{
|
||||
AlphaEquation = BlendingEquation.ReverseSubtract,
|
||||
},
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
Current.BindValueChanged(c =>
|
||||
{
|
||||
smoothingWedgeContainer.Alpha = c.NewValue > 0 ? 1 : 0;
|
||||
smoothingWedgeContainer.Rotation = (float)(360 * c.NewValue);
|
||||
}, true);
|
||||
}
|
||||
|
||||
public TransformSequence<CircularProgress> FillTo(double newValue, double duration = 0, Easing easing = Easing.None)
|
||||
=> progress.FillTo(newValue, duration, easing);
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.315.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.314.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.317.0" />
|
||||
<PackageReference Include="Sentry" Version="2.1.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
|
@ -71,7 +71,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.315.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.314.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.317.0" />
|
||||
</ItemGroup>
|
||||
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
||||
<ItemGroup Label="Transitive Dependencies">
|
||||
@ -79,7 +79,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.314.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.317.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user