mirror of
https://github.com/ppy/osu
synced 2025-01-28 00:32:59 +00:00
Merge pull request #13330 from nekodex/results-screen-sfx
Add sound effects to the results screen
This commit is contained in:
commit
4a4a561ca4
@ -51,7 +51,7 @@
|
||||
<Reference Include="Java.Interop" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.525.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.604.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.609.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
}
|
||||
}
|
||||
},
|
||||
new AccuracyCircle(score)
|
||||
new AccuracyCircle(score, true)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
|
@ -5,14 +5,18 @@ using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Ranking.Expanded.Accuracy
|
||||
@ -79,13 +83,28 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
|
||||
private Container<RankBadge> badges;
|
||||
private RankText rankText;
|
||||
|
||||
public AccuracyCircle(ScoreInfo score)
|
||||
private PoolableSkinnableSample scoreTickSound;
|
||||
private PoolableSkinnableSample badgeTickSound;
|
||||
private PoolableSkinnableSample badgeMaxSound;
|
||||
private PoolableSkinnableSample swooshUpSound;
|
||||
private PoolableSkinnableSample rankImpactSound;
|
||||
private PoolableSkinnableSample rankApplauseSound;
|
||||
|
||||
private readonly Bindable<double> tickPlaybackRate = new Bindable<double>();
|
||||
|
||||
private double lastTickPlaybackTime;
|
||||
private bool isTicking;
|
||||
|
||||
private readonly bool withFlair;
|
||||
|
||||
public AccuracyCircle(ScoreInfo score, bool withFlair = false)
|
||||
{
|
||||
this.score = score;
|
||||
this.withFlair = withFlair;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
private void load(GameHost host)
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
@ -204,14 +223,19 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
|
||||
},
|
||||
rankText = new RankText(score.Rank)
|
||||
};
|
||||
}
|
||||
|
||||
private ScoreRank getRank(ScoreRank rank)
|
||||
{
|
||||
foreach (var mod in score.Mods.OfType<IApplicableToScoreProcessor>())
|
||||
rank = mod.AdjustRank(rank, score.Accuracy);
|
||||
|
||||
return rank;
|
||||
if (withFlair)
|
||||
{
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
rankImpactSound = new PoolableSkinnableSample(new SampleInfo(impactSampleName)),
|
||||
rankApplauseSound = new PoolableSkinnableSample(new SampleInfo(@"applause", applauseSampleName)),
|
||||
scoreTickSound = new PoolableSkinnableSample(new SampleInfo(@"Results/score-tick")),
|
||||
badgeTickSound = new PoolableSkinnableSample(new SampleInfo(@"Results/badge-dink")),
|
||||
badgeMaxSound = new PoolableSkinnableSample(new SampleInfo(@"Results/badge-dink-max")),
|
||||
swooshUpSound = new PoolableSkinnableSample(new SampleInfo(@"Results/swoosh-up")),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
@ -220,33 +244,170 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
|
||||
|
||||
this.ScaleTo(0).Then().ScaleTo(1, APPEAR_DURATION, Easing.OutQuint);
|
||||
|
||||
using (BeginDelayedSequence(RANK_CIRCLE_TRANSFORM_DELAY, true))
|
||||
if (withFlair)
|
||||
{
|
||||
const double swoosh_pre_delay = 443f;
|
||||
const double swoosh_volume = 0.4f;
|
||||
|
||||
this.Delay(swoosh_pre_delay).Schedule(() =>
|
||||
{
|
||||
swooshUpSound.VolumeTo(swoosh_volume);
|
||||
swooshUpSound.Play();
|
||||
});
|
||||
}
|
||||
|
||||
using (BeginDelayedSequence(RANK_CIRCLE_TRANSFORM_DELAY))
|
||||
innerMask.FillTo(1f, RANK_CIRCLE_TRANSFORM_DURATION, ACCURACY_TRANSFORM_EASING);
|
||||
|
||||
using (BeginDelayedSequence(ACCURACY_TRANSFORM_DELAY, true))
|
||||
using (BeginDelayedSequence(ACCURACY_TRANSFORM_DELAY))
|
||||
{
|
||||
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);
|
||||
|
||||
if (withFlair)
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
const double score_tick_debounce_rate_start = 18f;
|
||||
const double score_tick_debounce_rate_end = 300f;
|
||||
const double score_tick_volume_start = 0.6f;
|
||||
const double score_tick_volume_end = 1.0f;
|
||||
|
||||
this.TransformBindableTo(tickPlaybackRate, score_tick_debounce_rate_start);
|
||||
this.TransformBindableTo(tickPlaybackRate, score_tick_debounce_rate_end, ACCURACY_TRANSFORM_DURATION, Easing.OutSine);
|
||||
|
||||
scoreTickSound.FrequencyTo(1 + targetAccuracy, ACCURACY_TRANSFORM_DURATION, Easing.OutSine);
|
||||
scoreTickSound.VolumeTo(score_tick_volume_start).Then().VolumeTo(score_tick_volume_end, ACCURACY_TRANSFORM_DURATION, Easing.OutSine);
|
||||
|
||||
isTicking = true;
|
||||
});
|
||||
}
|
||||
|
||||
int badgeNum = 0;
|
||||
|
||||
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))
|
||||
using (BeginDelayedSequence(inverseEasing(ACCURACY_TRANSFORM_EASING, Math.Min(1 - virtual_ss_percentage, badge.Accuracy) / targetAccuracy) * ACCURACY_TRANSFORM_DURATION))
|
||||
{
|
||||
badge.Appear();
|
||||
|
||||
if (withFlair)
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
var dink = badgeNum < badges.Count - 1 ? badgeTickSound : badgeMaxSound;
|
||||
|
||||
dink.FrequencyTo(1 + badgeNum++ * 0.05);
|
||||
dink.Play();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using (BeginDelayedSequence(TEXT_APPEAR_DELAY, true))
|
||||
using (BeginDelayedSequence(TEXT_APPEAR_DELAY))
|
||||
{
|
||||
rankText.Appear();
|
||||
|
||||
if (!withFlair) return;
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
isTicking = false;
|
||||
rankImpactSound.Play();
|
||||
});
|
||||
|
||||
const double applause_pre_delay = 545f;
|
||||
const double applause_volume = 0.8f;
|
||||
|
||||
using (BeginDelayedSequence(applause_pre_delay))
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
rankApplauseSound.VolumeTo(applause_volume);
|
||||
rankApplauseSound.Play();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (isTicking && Clock.CurrentTime - lastTickPlaybackTime >= tickPlaybackRate.Value)
|
||||
{
|
||||
scoreTickSound?.Play();
|
||||
lastTickPlaybackTime = Clock.CurrentTime;
|
||||
}
|
||||
}
|
||||
|
||||
private string applauseSampleName
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (score.Rank)
|
||||
{
|
||||
default:
|
||||
case ScoreRank.D:
|
||||
return @"Results/applause-d";
|
||||
|
||||
case ScoreRank.C:
|
||||
return @"Results/applause-c";
|
||||
|
||||
case ScoreRank.B:
|
||||
return @"Results/applause-b";
|
||||
|
||||
case ScoreRank.A:
|
||||
return @"Results/applause-a";
|
||||
|
||||
case ScoreRank.S:
|
||||
case ScoreRank.SH:
|
||||
case ScoreRank.X:
|
||||
case ScoreRank.XH:
|
||||
return @"Results/applause-s";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string impactSampleName
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (score.Rank)
|
||||
{
|
||||
default:
|
||||
case ScoreRank.D:
|
||||
return @"Results/rank-impact-fail-d";
|
||||
|
||||
case ScoreRank.C:
|
||||
case ScoreRank.B:
|
||||
return @"Results/rank-impact-fail";
|
||||
|
||||
case ScoreRank.A:
|
||||
case ScoreRank.S:
|
||||
case ScoreRank.SH:
|
||||
return @"Results/rank-impact-pass";
|
||||
|
||||
case ScoreRank.X:
|
||||
case ScoreRank.XH:
|
||||
return @"Results/rank-impact-pass-ss";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ScoreRank getRank(ScoreRank rank)
|
||||
{
|
||||
foreach (var mod in score.Mods.OfType<IApplicableToScoreProcessor>())
|
||||
rank = mod.AdjustRank(rank, score.Accuracy);
|
||||
|
||||
return rank;
|
||||
}
|
||||
|
||||
private double inverseEasing(Easing easing, double targetValue)
|
||||
{
|
||||
double test = 0;
|
||||
|
@ -122,7 +122,7 @@ namespace osu.Game.Screens.Ranking.Expanded
|
||||
Margin = new MarginPadding { Top = 40 },
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 230,
|
||||
Child = new AccuracyCircle(score)
|
||||
Child = new AccuracyCircle(score, withFlair)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
|
@ -12,7 +12,6 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
@ -20,20 +19,13 @@ using osu.Game.Input.Bindings;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Ranking.Expanded.Accuracy;
|
||||
using osu.Game.Screens.Ranking.Statistics;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Ranking
|
||||
{
|
||||
public abstract class ResultsScreen : ScreenWithBeatmapBackground, IKeyBindingHandler<GlobalAction>
|
||||
{
|
||||
/// <summary>
|
||||
/// Delay before the default applause sound should be played, in order to match the grade display timing in <see cref="AccuracyCircle"/>.
|
||||
/// </summary>
|
||||
public const double APPLAUSE_DELAY = AccuracyCircle.ACCURACY_TRANSFORM_DELAY + AccuracyCircle.TEXT_APPEAR_DELAY + ScorePanel.RESIZE_DURATION + ScorePanel.TOP_LAYER_EXPAND_DELAY - 1440;
|
||||
|
||||
protected const float BACKGROUND_BLUR = 20;
|
||||
private static readonly float screen_height = 768 - TwoLayerButton.SIZE_EXTENDED.Y;
|
||||
|
||||
@ -64,8 +56,6 @@ namespace osu.Game.Screens.Ranking
|
||||
private readonly bool allowRetry;
|
||||
private readonly bool allowWatchingReplay;
|
||||
|
||||
private SkinnableSound applauseSound;
|
||||
|
||||
protected ResultsScreen(ScoreInfo score, bool allowRetry, bool allowWatchingReplay = true)
|
||||
{
|
||||
Score = score;
|
||||
@ -156,13 +146,6 @@ namespace osu.Game.Screens.Ranking
|
||||
bool shouldFlair = player != null && Score.Mods.All(m => m.UserPlayable);
|
||||
|
||||
ScorePanelList.AddScore(Score, shouldFlair);
|
||||
|
||||
if (shouldFlair)
|
||||
{
|
||||
AddInternal(applauseSound = Score.Rank >= ScoreRank.A
|
||||
? new SkinnableSound(new SampleInfo("Results/rankpass", "applause"))
|
||||
: new SkinnableSound(new SampleInfo("Results/rankfail")));
|
||||
}
|
||||
}
|
||||
|
||||
if (allowWatchingReplay)
|
||||
@ -200,9 +183,6 @@ namespace osu.Game.Screens.Ranking
|
||||
api.Queue(req);
|
||||
|
||||
statisticsPanel.State.BindValueChanged(onStatisticsStateChanged, true);
|
||||
|
||||
using (BeginDelayedSequence(APPLAUSE_DELAY))
|
||||
Schedule(() => applauseSound?.Play());
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
|
@ -35,7 +35,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.609.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.525.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.604.0" />
|
||||
<PackageReference Include="Sentry" Version="3.4.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.28.2" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
|
@ -71,7 +71,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.609.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.525.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.604.0" />
|
||||
</ItemGroup>
|
||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
||||
<PropertyGroup>
|
||||
|
Loading…
Reference in New Issue
Block a user