1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-14 02:13:21 +08:00

Merge pull request #15122 from peppy/fail-animation-update

Add new fail animation to better match new sound effects
This commit is contained in:
Bartłomiej Dach 2021-10-15 20:23:09 +02:00 committed by GitHub
commit e925c416cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 104 additions and 51 deletions

View File

@ -12,6 +12,7 @@ using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Utils;
using osu.Game.Audio.Effects;
using osu.Game.Beatmaps;
@ -25,14 +26,17 @@ namespace osu.Game.Screens.Play
/// Manage the animation to be applied when a player fails.
/// Single use and automatically disposed after use.
/// </summary>
public class FailAnimation : CompositeDrawable
public class FailAnimation : Container
{
public Action OnComplete;
private readonly DrawableRuleset drawableRuleset;
private readonly BindableDouble trackFreq = new BindableDouble(1);
private Container filters;
private Box failFlash;
private Track track;
private AudioFilter failLowPassFilter;
@ -42,9 +46,18 @@ namespace osu.Game.Screens.Play
private Sample failSample;
protected override Container<Drawable> Content { get; } = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
};
public FailAnimation(DrawableRuleset drawableRuleset)
{
this.drawableRuleset = drawableRuleset;
RelativeSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
@ -53,8 +66,26 @@ namespace osu.Game.Screens.Play
track = beatmap.Value.Track;
failSample = audio.Samples.Get(@"Gameplay/failsound");
AddInternal(failLowPassFilter = new AudioFilter(audio.TrackMixer));
AddInternal(failHighPassFilter = new AudioFilter(audio.TrackMixer, BQFType.HighPass));
AddRangeInternal(new Drawable[]
{
filters = new Container
{
Children = new Drawable[]
{
failLowPassFilter = new AudioFilter(audio.TrackMixer),
failHighPassFilter = new AudioFilter(audio.TrackMixer, BQFType.HighPass),
},
},
Content,
failFlash = new Box
{
Colour = Color4.Red,
RelativeSizeAxes = Axes.Both,
Blending = BlendingParameters.Additive,
Depth = float.MinValue,
Alpha = 0
},
});
}
private bool started;
@ -81,8 +112,30 @@ namespace osu.Game.Screens.Play
track.AddAdjustment(AdjustableProperty.Frequency, trackFreq);
applyToPlayfield(drawableRuleset.Playfield);
drawableRuleset.Playfield.HitObjectContainer.FlashColour(Color4.Red, 500);
drawableRuleset.Playfield.HitObjectContainer.FadeOut(duration / 2);
failFlash.FadeOutFromOne(1000);
Content.Masking = true;
Content.Add(new Box
{
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both,
Depth = float.MaxValue
});
Content.ScaleTo(0.85f, duration, Easing.OutQuart);
Content.RotateTo(1, duration, Easing.OutQuart);
Content.FadeColour(Color4.Gray, duration);
}
public void RemoveFilters()
{
RemoveInternal(filters);
filters.Dispose();
track?.RemoveAdjustment(AdjustableProperty.Frequency, trackFreq);
}
protected override void Update()
@ -131,11 +184,5 @@ namespace osu.Game.Screens.Play
obj.MoveTo(originalPosition + new Vector2(0, 400), duration);
}
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
track?.RemoveAdjustment(AdjustableProperty.Frequency, trackFreq);
}
}
}

View File

@ -230,17 +230,53 @@ namespace osu.Game.Screens.Play
// this is intentionally done in two stages to ensure things are in a loaded state before exposing the ruleset to skin sources.
GameplayClockContainer.Add(rulesetSkinProvider);
rulesetSkinProvider.AddRange(new[]
rulesetSkinProvider.AddRange(new Drawable[]
{
// underlay and gameplay should have access to the skinning sources.
createUnderlayComponents(),
createGameplayComponents(Beatmap.Value, playableBeatmap)
failAnimationLayer = new FailAnimation(DrawableRuleset)
{
OnComplete = onFailComplete,
Children = new[]
{
// underlay and gameplay should have access to the skinning sources.
createUnderlayComponents(),
createGameplayComponents(Beatmap.Value, playableBeatmap)
}
},
FailOverlay = new FailOverlay
{
OnRetry = Restart,
OnQuit = () => PerformExit(true),
},
new HotkeyExitOverlay
{
Action = () =>
{
if (!this.IsCurrentScreen()) return;
fadeOut(true);
PerformExit(false);
},
},
});
if (Configuration.AllowRestart)
{
rulesetSkinProvider.Add(new HotkeyRetryOverlay
{
Action = () =>
{
if (!this.IsCurrentScreen()) return;
fadeOut(true);
Restart();
},
});
}
// add the overlay components as a separate step as they proxy some elements from the above underlay/gameplay components.
// also give the overlays the ruleset skin provider to allow rulesets to potentially override HUD elements (used to disable combo counters etc.)
// we may want to limit this in the future to disallow rulesets from outright replacing elements the user expects to be there.
rulesetSkinProvider.Add(createOverlayComponents(Beatmap.Value));
failAnimationLayer.Add(createOverlayComponents(Beatmap.Value));
if (!DrawableRuleset.AllowGameplayOverlays)
{
@ -375,11 +411,6 @@ namespace osu.Game.Screens.Play
RequestSkip = () => progressToResults(false),
Alpha = 0
},
FailOverlay = new FailOverlay
{
OnRetry = Restart,
OnQuit = () => PerformExit(true),
},
PauseOverlay = new PauseOverlay
{
OnResume = Resume,
@ -387,18 +418,7 @@ namespace osu.Game.Screens.Play
OnRetry = Restart,
OnQuit = () => PerformExit(true),
},
new HotkeyExitOverlay
{
Action = () =>
{
if (!this.IsCurrentScreen()) return;
fadeOut(true);
PerformExit(false);
},
},
failAnimation = new FailAnimation(DrawableRuleset) { OnComplete = onFailComplete, },
}
},
};
if (!Configuration.AllowSkipping || !DrawableRuleset.AllowGameplayOverlays)
@ -410,20 +430,6 @@ namespace osu.Game.Screens.Play
if (GameplayClockContainer is MasterGameplayClockContainer master)
HUDOverlay.PlayerSettingsOverlay.PlaybackSettings.UserPlaybackRate.BindTarget = master.UserPlaybackRate;
if (Configuration.AllowRestart)
{
container.Add(new HotkeyRetryOverlay
{
Action = () =>
{
if (!this.IsCurrentScreen()) return;
fadeOut(true);
Restart();
},
});
}
return container;
}
@ -541,7 +547,7 @@ namespace osu.Game.Screens.Play
// if the fail animation is currently in progress, accelerate it (it will show the pause dialog on completion).
if (ValidForResume && HasFailed)
{
failAnimation.FinishTransforms(true);
failAnimationLayer.FinishTransforms(true);
return;
}
@ -766,7 +772,7 @@ namespace osu.Game.Screens.Play
protected FailOverlay FailOverlay { get; private set; }
private FailAnimation failAnimation;
private FailAnimation failAnimationLayer;
private bool onFail()
{
@ -782,7 +788,7 @@ namespace osu.Game.Screens.Play
if (PauseOverlay.State.Value == Visibility.Visible)
PauseOverlay.Hide();
failAnimation.Start();
failAnimationLayer.Start();
if (GameplayState.Mods.OfType<IApplicableFailOverride>().Any(m => m.RestartOnFail))
Restart();
@ -956,7 +962,7 @@ namespace osu.Game.Screens.Play
public override bool OnExiting(IScreen next)
{
screenSuspension?.RemoveAndDisposeImmediately();
failAnimation?.RemoveAndDisposeImmediately();
failAnimationLayer?.RemoveFilters();
// if arriving here and the results screen preparation task hasn't run, it's safe to say the user has not completed the beatmap.
if (prepareScoreForDisplayTask == null)