mirror of
https://github.com/ppy/osu.git
synced 2026-05-27 21:40:42 +08:00
Implement background music for ranked play (#37166)
Using a bespoke music loop, fades in during the intro: https://github.com/user-attachments/assets/8db7e30c-2a7c-4fd0-8385-fa77a6e0a506 Ducks when hovering cards for previews, with debouncing to smooth it: https://github.com/user-attachments/assets/b3557c08-c675-4591-963c-95866d45107f --- - [x] depends on ppy/osu-resources#414 --------- Co-authored-by: Dean Herbert <pe@ppy.sh>
This commit is contained in:
committed by
GitHub
Unverified
parent
2d85966074
commit
c4f2c66fd6
@@ -22,6 +22,8 @@ namespace osu.Game.Audio
|
||||
|
||||
protected TrackManagerPreviewTrack? CurrentTrack;
|
||||
|
||||
public readonly BindableBool IsPlayingPreview = new BindableBool();
|
||||
|
||||
public PreviewTrackManager(IAdjustableAudioComponent mainTrackAdjustments)
|
||||
{
|
||||
this.mainTrackAdjustments = mainTrackAdjustments;
|
||||
@@ -47,6 +49,7 @@ namespace osu.Game.Audio
|
||||
CurrentTrack?.Stop();
|
||||
CurrentTrack = track;
|
||||
mainTrackAdjustments.AddAdjustment(AdjustableProperty.Volume, muteBindable);
|
||||
IsPlayingPreview.Value = true;
|
||||
});
|
||||
|
||||
track.Stopped += () => Schedule(() =>
|
||||
@@ -56,6 +59,7 @@ namespace osu.Game.Audio
|
||||
|
||||
CurrentTrack = null;
|
||||
mainTrackAdjustments.RemoveAdjustment(AdjustableProperty.Volume, muteBindable);
|
||||
IsPlayingPreview.Value = false;
|
||||
});
|
||||
|
||||
return track;
|
||||
|
||||
+16
-2
@@ -41,6 +41,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card
|
||||
protected override Container<Drawable> Content { get; }
|
||||
|
||||
private readonly Bindable<bool> trackRunning = new BindableBool();
|
||||
|
||||
private readonly Container overlayLayer;
|
||||
|
||||
private bool shouldBePlaying => Enabled.Value && IsHovered;
|
||||
@@ -114,7 +115,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card
|
||||
|
||||
overlayLayer.Add(new RippleVisualization(cardColours.Border)
|
||||
{
|
||||
TrackRunning = trackRunning.GetBoundCopy(),
|
||||
TrackRunning = { BindTarget = trackRunning }
|
||||
});
|
||||
|
||||
if (IsHovered)
|
||||
@@ -124,12 +125,25 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
if (previewTrack != null)
|
||||
previewTrack.Looping = true;
|
||||
|
||||
if (shouldBePlaying)
|
||||
{
|
||||
startPreviewIfAvailable();
|
||||
}
|
||||
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
if (previewTrack != null)
|
||||
previewTrack.Looping = false;
|
||||
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
|
||||
private void onTrackStarted() => Schedule(() => trackRunning.Value = true);
|
||||
|
||||
private void onTrackStopped() => Schedule(() => trackRunning.Value = false);
|
||||
@@ -193,7 +207,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card
|
||||
[Resolved]
|
||||
private SongPreviewParticleContainer? particleContainer { get; set; }
|
||||
|
||||
public required IBindable<bool> TrackRunning { get; init; }
|
||||
public readonly IBindable<bool> TrackRunning = new Bindable<bool>();
|
||||
|
||||
private readonly Color4 accentColour;
|
||||
private readonly Container rippleContainer;
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
// 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.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Audio;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Overlays;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components
|
||||
{
|
||||
public partial class BackgroundMusicManager : CompositeComponent
|
||||
{
|
||||
private const int hover_fade_duration = 250;
|
||||
|
||||
private ScheduledDelegate? globalTrackFadeDelegate;
|
||||
|
||||
private DrawableTrack bgm = null!;
|
||||
|
||||
private Bindable<bool> isPlayingPreview = null!;
|
||||
|
||||
[Resolved]
|
||||
private MusicController musicController { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private PreviewTrackManager previewTrackManager { get; set; } = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, OsuGameBase game)
|
||||
{
|
||||
AddInternal(bgm = new DrawableTrack(audio.Tracks.Get("rankedplay_bgm.ogg")));
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
isPlayingPreview = previewTrackManager.IsPlayingPreview.GetBoundCopy();
|
||||
isPlayingPreview.BindValueChanged(playing =>
|
||||
{
|
||||
bgm.VolumeTo(playing.NewValue ? 0 : 1, hover_fade_duration);
|
||||
});
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
if (bgm.IsRunning)
|
||||
return;
|
||||
|
||||
const int track_fade_duration = 3000;
|
||||
|
||||
// remove music control from player, to prevent overlapping music
|
||||
musicController.AllowTrackControl.Value = false;
|
||||
globalTrackFadeDelegate?.Cancel();
|
||||
|
||||
// cross-fade if global track is playing something
|
||||
if (musicController.IsPlaying)
|
||||
{
|
||||
var globalTrack = musicController.CurrentTrack;
|
||||
|
||||
globalTrack.VolumeTo(0, track_fade_duration, Easing.OutCubic);
|
||||
globalTrackFadeDelegate = Scheduler.AddDelayed(() =>
|
||||
{
|
||||
musicController.Stop();
|
||||
globalTrack.VolumeTo(1);
|
||||
}, track_fade_duration);
|
||||
}
|
||||
|
||||
bgm.VolumeTo(0)
|
||||
.VolumeTo(1, track_fade_duration, Easing.InCubic);
|
||||
|
||||
bgm.Looping = true;
|
||||
bgm.Start();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
globalTrackFadeDelegate?.Cancel();
|
||||
|
||||
bgm.Stop();
|
||||
bgm.Reset();
|
||||
|
||||
// return control of music to player and reset volume
|
||||
musicController.AllowTrackControl.Value = true;
|
||||
musicController.CurrentTrack.Volume.Value = 1;
|
||||
musicController.EnsurePlayingSomething();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// 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.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Allocation;
|
||||
@@ -15,7 +14,6 @@ using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay;
|
||||
using osu.Game.Overlays;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
|
||||
{
|
||||
@@ -36,9 +34,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private MusicController? musicController { get; set; }
|
||||
|
||||
private Sample? windupSample;
|
||||
private Sample? impactSample;
|
||||
private Sample? swooshSample;
|
||||
@@ -81,8 +76,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
|
||||
|
||||
private StarRatingSequence? starRatingAnimation;
|
||||
|
||||
private IDisposable? duckOperation;
|
||||
|
||||
public void PlayIntroSequence(UserWithRating player, UserWithRating opponent, double starRating)
|
||||
{
|
||||
double delay = 0;
|
||||
@@ -95,8 +88,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
|
||||
|
||||
vsScreen.Play(ref delay, out double impactDelay);
|
||||
|
||||
duckOperation = musicController?.Duck();
|
||||
|
||||
if (windupSample != null)
|
||||
{
|
||||
Scheduler.AddDelayed(() => windupSample?.Play(), impactDelay - windupSample.Length);
|
||||
@@ -113,16 +104,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
|
||||
{
|
||||
starRatingAnimation?.PopOut();
|
||||
|
||||
duckOperation?.Dispose();
|
||||
|
||||
this.Delay(500).FadeOut();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
duckOperation?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,9 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
[Cached]
|
||||
private readonly SongPreviewParticleContainer particleContainer;
|
||||
|
||||
[Cached]
|
||||
private BackgroundMusicManager backgroundMusic;
|
||||
|
||||
public RankedPlayScreen(MultiplayerRoom room)
|
||||
{
|
||||
this.room = room;
|
||||
@@ -129,6 +132,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
},
|
||||
overlayContainer = new CardDetailsOverlayContainer(),
|
||||
particleContainer = new SongPreviewParticleContainer(),
|
||||
backgroundMusic = new BackgroundMusicManager()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -224,6 +228,11 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
{
|
||||
chat.Appear();
|
||||
|
||||
if (stage is RankedPlayStage.GameplayWarmup or RankedPlayStage.Gameplay)
|
||||
backgroundMusic.Stop();
|
||||
else
|
||||
backgroundMusic.Play();
|
||||
|
||||
switch (stage)
|
||||
{
|
||||
case RankedPlayStage.RoundWarmup when matchInfo.CurrentRound == 1:
|
||||
@@ -278,6 +287,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
public override void OnSuspending(ScreenTransitionEvent e)
|
||||
{
|
||||
chat.Disappear();
|
||||
backgroundMusic.Stop();
|
||||
previewTrackManager.StopAnyPlaying(this);
|
||||
|
||||
base.OnSuspending(e);
|
||||
@@ -296,6 +306,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
|
||||
return true;
|
||||
}
|
||||
|
||||
backgroundMusic.Stop();
|
||||
previewTrackManager.StopAnyPlaying(this);
|
||||
|
||||
client.LeaveRoom().FireAndForget();
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="Realm" Version="20.1.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2026.318.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2026.331.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2026.402.0" />
|
||||
<PackageReference Include="Sentry" Version="6.2.0" />
|
||||
<!-- Held back due to 0.34.0 failing AOT compilation on ZstdSharp.dll dependency. -->
|
||||
<PackageReference Include="SharpCompress" Version="0.47.0" />
|
||||
|
||||
Reference in New Issue
Block a user