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 Godot; | ||||||
|  | using SupaLidlGame.Audio; | ||||||
| using SupaLidlGame.Characters; | using SupaLidlGame.Characters; | ||||||
| using SupaLidlGame.Extensions; | using SupaLidlGame.Extensions; | ||||||
| using SupaLidlGame.Scenes; | using SupaLidlGame.Scenes; | ||||||
|  | @ -123,13 +124,13 @@ public partial class World : Node | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         CurrentBoss = boss; |         CurrentBoss = boss; | ||||||
|         GetNode<AudioManager>("/root/AudioManager").PlayActive(boss.Music); |         GetNode<AudioManager>("/root/AudioManager").PlayBackground(boss.Music, 2); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void DeregisterBoss(Boss boss) |     private void DeregisterBoss(Boss boss) | ||||||
|     { |     { | ||||||
|         CurrentBoss = null; |         CurrentBoss = null; | ||||||
|         GetNode<AudioManager>("/root/AudioManager").StopActive(); |         GetNode<AudioManager>("/root/AudioManager").StopBackground(2); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void LoadMap(Map map) |     private void LoadMap(Map map) | ||||||
|  |  | ||||||
|  | @ -22,7 +22,7 @@ GlobalState="*res://State/Global/GlobalState.cs" | ||||||
| EventBus="*res://Events/EventBus.cs" | EventBus="*res://Events/EventBus.cs" | ||||||
| BaseUI="*res://UI/Base.tscn" | BaseUI="*res://UI/Base.tscn" | ||||||
| World="*res://Scenes/Level.tscn" | World="*res://Scenes/Level.tscn" | ||||||
| AudioManager="*res://Utils/AudioManager.cs" | AudioManager="*res://Audio/AudioManager.cs" | ||||||
| DebugConsole="*res://Debug/DebugConsole.cs" | DebugConsole="*res://Debug/DebugConsole.cs" | ||||||
| Panku="*res://addons/panku_console/console.tscn" | Panku="*res://addons/panku_console/console.tscn" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue