updated AudioManager to handle multiple sublayers
							parent
							
								
									96eac1c640
								
							
						
					
					
						commit
						ffe6c50e93
					
				|  | @ -0,0 +1,118 @@ | |||
| using Godot; | ||||
| using System.Collections.Generic; | ||||
| 
 | ||||
| namespace SupaLidlGame.Audio; | ||||
| 
 | ||||
| public sealed partial class AudioManager : Node | ||||
| { | ||||
|     private ManagedAudioPlayer _ambientPlayer; | ||||
| 
 | ||||
|     private List<ManagedAudioPlayer> _bgPlayers; | ||||
| 
 | ||||
|     public enum Layer | ||||
|     { | ||||
|         Ambient, | ||||
|         Background | ||||
|     } | ||||
| 
 | ||||
|     public AudioManager() | ||||
|     { | ||||
|         _bgPlayers = new(); | ||||
|         for (int i = 0; i < 4; i++) | ||||
|         { | ||||
|             _bgPlayers.Add(null); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public ManagedAudioPlayer CreateAudioPlayer(AudioStream stream) | ||||
|     { | ||||
|         var player = new ManagedAudioPlayer(); | ||||
|         player.Stream = stream; | ||||
|         AddChild(player); | ||||
|         return player; | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// Plays ambient audio. Ambient audio will play alongside the current | ||||
|     /// background audio and will replace the current ambient audio. | ||||
|     /// </summary> | ||||
|     public void PlayAmbient(AudioStream stream, float fade = 1) | ||||
|     { | ||||
|         if (IsPlayerValid(_ambientPlayer)) | ||||
|         { | ||||
|             _ambientPlayer.FadeOut(fade, true); | ||||
|         } | ||||
|         _ambientPlayer = CreateAudioPlayer(stream); | ||||
|         _ambientPlayer.Play(); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// Plays background audio. Background audio will play if no sublayer above | ||||
|     /// is playing, pause all sublayers below, and replace the current sublayer | ||||
|     /// if it is playing. | ||||
|     /// </summary> | ||||
|     public void PlayBackground(AudioStream stream, int sublayer = 0, float fade = 1) | ||||
|     { | ||||
|         // stop current sublayer if playing | ||||
|         if (IsPlayerValid(_bgPlayers[sublayer])) | ||||
|         { | ||||
|             _bgPlayers[sublayer].FadeOut(fade, true); | ||||
|         } | ||||
|         _bgPlayers[sublayer] = CreateAudioPlayer(stream); | ||||
| 
 | ||||
|         // pause all sublayers below this | ||||
|         for (int i = 0; i < sublayer; i++) | ||||
|         { | ||||
|             if (IsPlayerValid(_bgPlayers[i])) | ||||
|             { | ||||
|                 if (!_bgPlayers[i].StreamPaused) | ||||
|                 { | ||||
|                     _bgPlayers[i]?.FadeOut(fade, pause: true); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // if a sublayer above is not playing then play | ||||
|         if (!IsSublayerAboveValid(sublayer)) | ||||
|         { | ||||
|             _bgPlayers[sublayer].Play(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void StopBackground(int sublayer, float fade = 1) | ||||
|     { | ||||
|         // kill current sublayer | ||||
|         _bgPlayers[sublayer]?.FadeOut(fade, true); | ||||
| 
 | ||||
|         // if sublayer above is not plyaing, play lowest sublayer | ||||
|         if (!IsSublayerAboveValid(sublayer)) | ||||
|         { | ||||
|             for (int i = sublayer - 1; i >= 0; i--) | ||||
|             { | ||||
|                 if (IsPlayerValid(_bgPlayers[i])) | ||||
|                 { | ||||
|                     _bgPlayers[i].FadeIn(fade, unpause: true); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private bool IsSublayerAboveValid(int sublayer) | ||||
|     { | ||||
|         for (int i = sublayer + 1; i < 4; i++) | ||||
|         { | ||||
|             if (IsPlayerValid(_bgPlayers[i])) | ||||
|             { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     private bool IsPlayerValid(ManagedAudioPlayer player) | ||||
|     { | ||||
|         return player is not null && IsInstanceValid(player) && !player.IsDead; | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,45 @@ | |||
| using Godot; | ||||
| 
 | ||||
| namespace SupaLidlGame.Audio; | ||||
| 
 | ||||
| public sealed partial class ManagedAudioPlayer : AudioStreamPlayer | ||||
| { | ||||
|     private Tween _tween; | ||||
| 
 | ||||
|     public bool IsDead { get; set; } | ||||
| 
 | ||||
|     private Tween GetNewTween() | ||||
|     { | ||||
|         if (_tween is not null && IsInstanceValid(_tween)) | ||||
|         { | ||||
|             _tween.Kill(); | ||||
|         } | ||||
| 
 | ||||
|         return _tween = GetTree().CreateTween().BindNode(this); | ||||
|     } | ||||
| 
 | ||||
|     public void FadeOut(float time, bool kill = false, bool pause = false) | ||||
|     { | ||||
|         GetNewTween(); | ||||
|         _tween.TweenProperty(this, "volume_db", -80, time); | ||||
|         if (kill) | ||||
|         { | ||||
|             IsDead = true; | ||||
|             _tween.TweenCallback(Callable.From(QueueFree)); | ||||
|         } | ||||
|         else if (pause) | ||||
|         { | ||||
|             _tween.TweenCallback(Callable.From(() => StreamPaused = true)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void FadeIn(float time, bool unpause = false) | ||||
|     { | ||||
|         GetNewTween(); | ||||
|         _tween.TweenProperty(this, "volume_db", 0, time); | ||||
|         if (unpause) | ||||
|         { | ||||
|             _tween.TweenCallback(Callable.From(() => StreamPaused = false)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -1,191 +0,0 @@ | |||
| using Godot; | ||||
| using System.Collections.Generic; | ||||
| 
 | ||||
| namespace SupaLidlGame.Utils; | ||||
| 
 | ||||
| public sealed partial class AudioManager : Node | ||||
| { | ||||
|     public enum Layer | ||||
|     { | ||||
|         Ambient, | ||||
|         BackgroundMusic, | ||||
|         ActiveMusic, | ||||
|     }; | ||||
| 
 | ||||
|     //private Array<AudioStreamPlayer> _players; | ||||
| 
 | ||||
|     private Dictionary<Layer, AudioStreamPlayer> _players; | ||||
| 
 | ||||
|     public override void _Ready() | ||||
|     { | ||||
|         _players = new Dictionary<Layer, AudioStreamPlayer>(); | ||||
|         _players.Add(Layer.Ambient, null); | ||||
|         _players.Add(Layer.BackgroundMusic, null); | ||||
|         _players.Add(Layer.ActiveMusic, null); | ||||
|     } | ||||
| 
 | ||||
|     public void PlayAmbient(AudioStream stream) | ||||
|     { | ||||
|         StopPlayback(Layer.Ambient); | ||||
|         _players[Layer.Ambient] = CreateAudioStreamPlayer(stream); | ||||
|         FadeIn(_players[Layer.Ambient]); | ||||
|     } | ||||
| 
 | ||||
|     public void PlayBackground(AudioStream stream) | ||||
|     { | ||||
|         StopPlayback(Layer.BackgroundMusic); | ||||
|         _players[Layer.BackgroundMusic] = CreateAudioStreamPlayer(stream); | ||||
|         if (!IsLayerValid(Layer.ActiveMusic)) | ||||
|         { | ||||
|             FadeIn(_players[Layer.BackgroundMusic]); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void StopBackground() | ||||
|     { | ||||
|         StopPlayback(Layer.BackgroundMusic); | ||||
|     } | ||||
| 
 | ||||
|     public void PlayActive(AudioStream stream) | ||||
|     { | ||||
|         _players[Layer.ActiveMusic] = CreateAudioStreamPlayer(stream); | ||||
|         _players[Layer.ActiveMusic].Play(); | ||||
|         if (IsLayerValid(Layer.BackgroundMusic)) | ||||
|         { | ||||
|             Pause(Layer.BackgroundMusic); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void StopActive() | ||||
|     { | ||||
|         StopPlayback(Layer.ActiveMusic); | ||||
|         if (IsLayerValid(Layer.BackgroundMusic)) | ||||
|         { | ||||
|             if (_players[Layer.BackgroundMusic].StreamPaused) | ||||
|             { | ||||
|                 Unpause(Layer.BackgroundMusic); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 _players[Layer.BackgroundMusic].Play(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void Play(AudioStream stream, Layer layer) | ||||
|     { | ||||
|         switch (layer) | ||||
|         { | ||||
|             case Layer.Ambient: | ||||
|                 PlayAmbient(stream); | ||||
|                 break; | ||||
|             case Layer.BackgroundMusic: | ||||
|                 PlayBackground(stream); | ||||
|                 break; | ||||
|             case Layer.ActiveMusic: | ||||
|                 PlayActive(stream); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void Stop(Layer layer) | ||||
|     { | ||||
|         switch (layer) | ||||
|         { | ||||
|             case Layer.Ambient: | ||||
|             case Layer.BackgroundMusic: | ||||
|                 StopPlayback(layer); | ||||
|                 break; | ||||
|             case Layer.ActiveMusic: | ||||
|                 StopActive(); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void Pause(Layer layer) | ||||
|     { | ||||
|         var player = _players[layer]; | ||||
| 
 | ||||
|         if (player is null || !IsInstanceValid(player)) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         FadeOut(player, pause: true); | ||||
|     } | ||||
| 
 | ||||
|     private void Unpause(Layer layer) | ||||
|     { | ||||
|         var player = _players[layer]; | ||||
| 
 | ||||
|         if (player is null || !IsInstanceValid(player)) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         FadeIn(player, unpause: true); | ||||
|     } | ||||
| 
 | ||||
|     private void StopPlayback(Layer layer) | ||||
|     { | ||||
|         var player = _players[layer]; | ||||
| 
 | ||||
|         if (player is null || !IsInstanceValid(player)) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         FadeOut(player, kill: true); | ||||
|         _players[layer] = null; | ||||
|     } | ||||
| 
 | ||||
|     private AudioStreamPlayer CreateAudioStreamPlayer(AudioStream stream) | ||||
|     { | ||||
|         var player = new AudioStreamPlayer(); | ||||
|         AddChild(player); | ||||
|         player.Stream = stream; | ||||
|         return player; | ||||
|     } | ||||
| 
 | ||||
|     private void FadeOut( | ||||
|         AudioStreamPlayer player, | ||||
|         double time = 1.0, | ||||
|         bool kill = false, | ||||
|         bool pause = false) | ||||
|     { | ||||
|         var tween = player.GetTree().CreateTween().BindNode(player); | ||||
|         tween.TweenProperty(player, "volume_db", 0, time); | ||||
|         if (kill) | ||||
|         { | ||||
|             tween.TweenCallback(Callable.From(player.QueueFree)); | ||||
|         } | ||||
|         else if (pause) | ||||
|         { | ||||
|             tween.TweenCallback( | ||||
|                 Callable.From(() => player.StreamPaused = true)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void FadeIn(AudioStreamPlayer player, | ||||
|             double time = 1.0, | ||||
|             bool unpause = false) | ||||
|     { | ||||
|         if (unpause) | ||||
|         { | ||||
|             player.StreamPaused = false; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             player.Play(); | ||||
|         } | ||||
|         player.VolumeDb = 0; | ||||
|         var tween = player.GetTree().CreateTween().BindNode(player); | ||||
|         tween.TweenProperty(player, "volume_db", 1, time); | ||||
|     } | ||||
| 
 | ||||
|     public bool IsLayerValid(Layer layer) | ||||
|     { | ||||
|         var player = _players[layer]; | ||||
|         return player is not null && IsInstanceValid(player); | ||||
|     } | ||||
| } | ||||
|  | @ -1,4 +1,5 @@ | |||
| using Godot; | ||||
| using SupaLidlGame.Audio; | ||||
| using SupaLidlGame.Characters; | ||||
| using SupaLidlGame.Extensions; | ||||
| using SupaLidlGame.Scenes; | ||||
|  | @ -123,13 +124,13 @@ public partial class World : Node | |||
|             return; | ||||
|         } | ||||
|         CurrentBoss = boss; | ||||
|         GetNode<AudioManager>("/root/AudioManager").PlayActive(boss.Music); | ||||
|         GetNode<AudioManager>("/root/AudioManager").PlayBackground(boss.Music, 2); | ||||
|     } | ||||
| 
 | ||||
|     private void DeregisterBoss(Boss boss) | ||||
|     { | ||||
|         CurrentBoss = null; | ||||
|         GetNode<AudioManager>("/root/AudioManager").StopActive(); | ||||
|         GetNode<AudioManager>("/root/AudioManager").StopBackground(2); | ||||
|     } | ||||
| 
 | ||||
|     private void LoadMap(Map map) | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ GlobalState="*res://State/Global/GlobalState.cs" | |||
| EventBus="*res://Events/EventBus.cs" | ||||
| BaseUI="*res://UI/Base.tscn" | ||||
| World="*res://Scenes/Level.tscn" | ||||
| AudioManager="*res://Utils/AudioManager.cs" | ||||
| AudioManager="*res://Audio/AudioManager.cs" | ||||
| DebugConsole="*res://Debug/DebugConsole.cs" | ||||
| Panku="*res://addons/panku_console/console.tscn" | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue