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