diff --git a/osu.Android.props b/osu.Android.props index cfa3bc836f..0d3fafd19f 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs index f305b7255e..a5e2f02f31 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs @@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual.Ranking } } }, - new AccuracyCircle(score) + new AccuracyCircle(score, true) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index c70b4dd35b..635be60549 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -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 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 tickPlaybackRate = new Bindable(); + + 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()) - 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()) + rank = mod.AdjustRank(rank, score.Accuracy); + + return rank; + } + private double inverseEasing(Easing easing, double targetValue) { double test = 0; diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index f65aed3037..0a10eee644 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -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, diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index dd1ca379fb..b458d7c17f 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -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 { - /// - /// Delay before the default applause sound should be played, in order to match the grade display timing in . - /// - 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() diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index be10764c6a..2ee8ed527f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 751f60912a..7832aaaf2d 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - +