217 lines
7.7 KiB
C#
217 lines
7.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using FlaxEngine;
|
|
using Console = Cabrito.Console;
|
|
using Object = FlaxEngine.Object;
|
|
|
|
namespace Game
|
|
{
|
|
[Flags]
|
|
public enum AudioFlags
|
|
{
|
|
None = 0,
|
|
|
|
/// Avoid replacing the existing playing audio source in this channel.
|
|
ContinuePlayingExistingSource = 1,
|
|
}
|
|
|
|
public static class AudioManager
|
|
{
|
|
private class AudioInfo
|
|
{
|
|
public AudioClip[] AudioClips;
|
|
public int lastAudioPlayed;
|
|
}
|
|
|
|
private class ActorAudioChannels
|
|
{
|
|
public Dictionary<int, AudioSource> channelSources;
|
|
|
|
public ActorAudioChannels()
|
|
{
|
|
channelSources = new Dictionary<int, AudioSource>();
|
|
}
|
|
}
|
|
|
|
private static Random random = new Random();
|
|
|
|
private static Dictionary<string, AudioInfo> cachedAudioInfos = new Dictionary<string, AudioInfo>();
|
|
|
|
private static Dictionary<Actor, ActorAudioChannels> actorAudioChannels =
|
|
new Dictionary<Actor, ActorAudioChannels>();
|
|
|
|
public static void PlaySound(string soundName, Actor actor, Vector3 position, float volume = 1f)
|
|
{
|
|
PlaySound(soundName, actor, 0, AudioFlags.None, position, volume, Vector2.One);
|
|
}
|
|
|
|
public static void PlaySound(string soundName, Actor actor, Vector3 position, float volume, Vector2 pitchRange)
|
|
{
|
|
PlaySound(soundName, actor, 0, AudioFlags.None, position, volume, pitchRange);
|
|
}
|
|
|
|
public static void PlaySound(string soundName, Actor actor, int channel, Vector3 position, float volume = 1f)
|
|
{
|
|
PlaySound(soundName, actor, channel, AudioFlags.None, position, volume, Vector2.One);
|
|
}
|
|
|
|
public static void PlaySound(string soundName, Actor actor, int channel, AudioFlags flags, Vector3 position, float volume = 1f)
|
|
{
|
|
PlaySound(soundName, actor, channel, flags, position, volume, Vector2.One);
|
|
}
|
|
|
|
public static void PlaySound(string soundName, Actor actor, int channel, AudioFlags flags, Vector3 position, float volume, Vector2 pitchRange)
|
|
{
|
|
AudioInfo audio = GetSound(soundName);
|
|
if (audio.AudioClips.Length == 0)
|
|
return;
|
|
|
|
channel = Math.Max(channel, 0);
|
|
ActorAudioChannels actorChannels = null;
|
|
if (channel > 0)
|
|
{
|
|
if (!actorAudioChannels.TryGetValue(actor, out actorChannels))
|
|
{
|
|
actorChannels = new ActorAudioChannels();
|
|
actorAudioChannels.Add(actor, actorChannels);
|
|
}
|
|
|
|
if (!actorChannels.channelSources.TryGetValue(channel, out AudioSource existingAudioSource))
|
|
actorChannels.channelSources.Add(channel, null);
|
|
|
|
if (existingAudioSource && existingAudioSource != null &&
|
|
existingAudioSource.State == AudioSource.States.Playing)
|
|
{
|
|
if (flags.HasFlag(AudioFlags.ContinuePlayingExistingSource))
|
|
return;
|
|
|
|
existingAudioSource.Stop();
|
|
Object.Destroy(existingAudioSource);
|
|
actorChannels.channelSources[channel] = null;
|
|
}
|
|
}
|
|
|
|
AudioClip audioClip;
|
|
if (audio.AudioClips.Length > 1)
|
|
{
|
|
// Randomize selected clip while avoiding the last used clip
|
|
int randomIndex = 0;
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
randomIndex = random.Next(audio.AudioClips.Length);
|
|
if (randomIndex != audio.lastAudioPlayed)
|
|
break;
|
|
}
|
|
|
|
audioClip = audio.AudioClips[randomIndex];
|
|
audio.lastAudioPlayed = randomIndex;
|
|
}
|
|
else
|
|
audioClip = audio.AudioClips[0];
|
|
|
|
float pitch;
|
|
if (pitchRange[0] < pitchRange[1]) // Randomized pitch
|
|
pitch = (float)(pitchRange[0] + (random.NextDouble() * (pitchRange[1] - pitchRange[0])));
|
|
else
|
|
pitch = pitchRange[0];
|
|
|
|
var audioSource = new AudioSource();
|
|
audioSource.Clip = audioClip;
|
|
audioSource.Position = position;
|
|
audioSource.Parent = actor.Parent;
|
|
audioSource.Pitch = pitch;
|
|
audioSource.Name = Path.GetFileNameWithoutExtension(audioClip.Path);
|
|
audioSource.Volume = volume;
|
|
|
|
if (volume != 1f)
|
|
audioSource.Name += ", vol: " + volume.ToString();
|
|
|
|
audioSource.Play();
|
|
Object.Destroy(audioSource, audioClip.Length);
|
|
|
|
if (channel > 0)
|
|
{
|
|
actorChannels.channelSources[channel] = audioSource;
|
|
}
|
|
}
|
|
|
|
public static void StopSound(Actor actor, int channel)
|
|
{
|
|
if (channel <= 0)
|
|
return;
|
|
|
|
if (!actorAudioChannels.TryGetValue(actor, out ActorAudioChannels actorChannels))
|
|
return;
|
|
|
|
if (!actorChannels.channelSources.TryGetValue(channel, out AudioSource existingAudioSource))
|
|
return;
|
|
|
|
if (existingAudioSource && existingAudioSource != null &&
|
|
existingAudioSource.State == AudioSource.States.Playing)
|
|
{
|
|
existingAudioSource.Stop();
|
|
Object.Destroy(existingAudioSource);
|
|
actorChannels.channelSources[channel] = null;
|
|
}
|
|
}
|
|
|
|
public static bool IsSoundPlaying(Actor actor, int channel)
|
|
{
|
|
if (channel <= 0)
|
|
return false;
|
|
|
|
if (!actorAudioChannels.TryGetValue(actor, out ActorAudioChannels actorChannels))
|
|
return false;
|
|
|
|
if (!actorChannels.channelSources.TryGetValue(channel, out AudioSource existingAudioSource))
|
|
return false;
|
|
|
|
if (existingAudioSource && existingAudioSource != null &&
|
|
existingAudioSource.State == AudioSource.States.Playing)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static AudioInfo GetSound(string soundName)
|
|
{
|
|
if (cachedAudioInfos.TryGetValue(soundName, out AudioInfo cachedAudio))
|
|
return cachedAudio;
|
|
|
|
AudioInfo audio = new AudioInfo();
|
|
|
|
var workDir = Directory.GetCurrentDirectory();
|
|
var audioBasePath = Path.Combine(workDir, "Content", "Audio");
|
|
AudioClip audioClip = Content.Load<AudioClip>(Path.Combine(audioBasePath, soundName + ".flax"));
|
|
if (audioClip != null)
|
|
audio.AudioClips = new AudioClip[] { audioClip };
|
|
else
|
|
{
|
|
// Check if this audio has multiple variations
|
|
List<AudioClip> audioClips = new List<AudioClip>();
|
|
for (int i = 1; i<50; i++)
|
|
{
|
|
// TODO: make this more efficient, maybe get a list of assets and filter by name?
|
|
AudioClip audioClipVariation = Content.Load<AudioClip>(Path.Combine(audioBasePath, soundName + "_var" + i + ".flax"));
|
|
if (audioClipVariation == null)
|
|
break;
|
|
|
|
audioClips.Add(audioClipVariation);
|
|
}
|
|
|
|
if (audioClips.Count > 0)
|
|
audio.AudioClips = audioClips.ToArray();
|
|
else
|
|
Console.PrintError("AudioClip '" + soundName + "' not found");
|
|
}
|
|
|
|
audio.lastAudioPlayed = audio.AudioClips.Length + 1;
|
|
|
|
cachedAudioInfos.Add(soundName, audio);
|
|
return audio;
|
|
}
|
|
}
|
|
} |