295 lines
8.3 KiB
C#
295 lines
8.3 KiB
C#
using Superlazy;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
public class SLSound : SLGameComponent
|
|
{
|
|
private static GameObject soundRoot;
|
|
|
|
private static bool mute = false;
|
|
|
|
// 재생 관리를 위한 큐
|
|
private static readonly Dictionary<string, List<AudioSource>> enableObjects = new Dictionary<string, List<AudioSource>>();
|
|
|
|
// 페이드
|
|
private static readonly List<AudioSource> fades = new List<AudioSource>();
|
|
|
|
private static readonly List<AudioSource> removes = new List<AudioSource>();
|
|
|
|
// 리소스 풀
|
|
private static int unusedCount = 0;
|
|
|
|
private static readonly Dictionary<string, Queue<AudioSource>> unused = new Dictionary<string, Queue<AudioSource>>();
|
|
|
|
// mute 정보
|
|
private static readonly HashSet<string> muteTagList = new HashSet<string>();
|
|
|
|
private static readonly List<string> currentFramePlays = new List<string>();
|
|
|
|
private static readonly Dictionary<string, SLEntity> delaySounds = new Dictionary<string, SLEntity>();
|
|
|
|
private static AudioSource GetAudioSource(string clipName)
|
|
{
|
|
if (currentFramePlays.Contains(clipName)) return null;
|
|
|
|
currentFramePlays.Add(clipName);
|
|
|
|
AudioSource audioSource = null;
|
|
if (unused.ContainsKey(clipName) && unused[clipName].Count != 0)
|
|
{
|
|
audioSource = unused[clipName].Dequeue();
|
|
--unusedCount;
|
|
}
|
|
else
|
|
{
|
|
//TODO : 추후 사운드도 ResourceManager 로 이관해야함
|
|
var sound = SLResources.Load<AudioClip>(clipName);
|
|
if (sound != null)
|
|
{
|
|
sound.name = clipName;
|
|
audioSource = soundRoot.AddComponent<AudioSource>();
|
|
audioSource.clip = sound;
|
|
}
|
|
}
|
|
|
|
return audioSource;
|
|
}
|
|
|
|
public static void MuteSounds(bool mute)
|
|
{
|
|
SLSound.mute = mute;
|
|
}
|
|
|
|
public static void ClearPool()
|
|
{
|
|
foreach (var queue in unused)
|
|
{
|
|
foreach (var source in queue.Value)
|
|
{
|
|
Object.Destroy(source);
|
|
}
|
|
}
|
|
unused.Clear();
|
|
unusedCount = 0;
|
|
}
|
|
|
|
public static void PlaySound(string clipName, string tag = "Effect", bool loop = false, bool unique = false, bool reset = true, float volume = 1, float delay = 0)
|
|
{
|
|
if (string.IsNullOrEmpty(clipName)) return;
|
|
|
|
if (clipName == "Off") return; // TODO: Off라는 이름의 사운드가 없어 임시 처리. 추후 수정 필요
|
|
|
|
if (soundRoot == null) return;
|
|
|
|
if (tag == "BGM")
|
|
{
|
|
volume *= SLGame.Session["Option"]["Volume"]["BGM"] * 0.1f;
|
|
}
|
|
else
|
|
{
|
|
volume *= SLGame.Session["Option"]["Volume"]["SE"] * 0.1f;
|
|
}
|
|
|
|
if (delay > 0)
|
|
{
|
|
SLEntity context = SLEntity.Empty;
|
|
context["Tage"] = tag;
|
|
context["Loop"] = loop;
|
|
context["Unique"] = unique;
|
|
context["Reset"] = reset;
|
|
context["Volume"] = volume;
|
|
context["Delay"] = delay;
|
|
delaySounds.Add(clipName, context);
|
|
return;
|
|
}
|
|
|
|
var exist = false;
|
|
if (unique)
|
|
{
|
|
if (enableObjects.ContainsKey(tag))
|
|
{
|
|
var stopList = new List<AudioSource>();
|
|
foreach (var source in enableObjects[tag])
|
|
{
|
|
if (reset == false && source.clip.name == clipName)
|
|
{
|
|
exist = true;
|
|
source.volume = volume;
|
|
continue;
|
|
}
|
|
|
|
if (source.loop)
|
|
{
|
|
fades.Add(source);
|
|
}
|
|
else
|
|
{
|
|
source.Stop();
|
|
removes.Add(source);
|
|
}
|
|
stopList.Add(source);
|
|
}
|
|
foreach (var source in stopList)
|
|
{
|
|
enableObjects[tag].Remove(source);
|
|
}
|
|
}
|
|
}
|
|
if (exist) return;
|
|
if (tag != "BGM" && tag != "Weather" && IsMuteTag(tag)) return;
|
|
|
|
if (enableObjects.ContainsKey(tag) && tag != "TextSound")
|
|
{
|
|
if (enableObjects[tag].Count > 4) return;
|
|
}
|
|
|
|
var audioSource = GetAudioSource(clipName);
|
|
|
|
if (audioSource != null)
|
|
{
|
|
// 여기서 각종 옵션을 제어한다.
|
|
{
|
|
audioSource.loop = loop;
|
|
audioSource.volume = volume;
|
|
audioSource.mute = IsMuteTag(tag);
|
|
}
|
|
audioSource.enabled = true;
|
|
audioSource.Play();
|
|
|
|
if (enableObjects.ContainsKey(tag) == false)
|
|
enableObjects[tag] = new List<AudioSource>();
|
|
enableObjects[tag].Add(audioSource);
|
|
}
|
|
}
|
|
|
|
public static void StopSound(string tag)
|
|
{
|
|
if (enableObjects.ContainsKey(tag))
|
|
{
|
|
foreach (var source in enableObjects[tag])
|
|
{
|
|
if (source.loop)
|
|
{
|
|
fades.Add(source);
|
|
}
|
|
else
|
|
{
|
|
source.Stop();
|
|
removes.Add(source);
|
|
}
|
|
}
|
|
enableObjects[tag].Clear();
|
|
}
|
|
}
|
|
|
|
public static void SetMute(string tag, bool mute)
|
|
{
|
|
if (mute) muteTagList.Add(tag);
|
|
else muteTagList.Remove(tag);
|
|
}
|
|
|
|
private static bool IsMuteTag(string tag)
|
|
{
|
|
if (mute) return true;
|
|
|
|
if (tag == "BGM" || tag == "Weather")
|
|
{
|
|
return muteTagList.Contains("BGM");
|
|
}
|
|
else
|
|
{
|
|
return muteTagList.Contains("Effect");
|
|
}
|
|
}
|
|
|
|
public static void VolumeChange(float before, float next)
|
|
{
|
|
foreach (var clip in enableObjects["BGM"])
|
|
{
|
|
clip.volume = before == 0f ? next * 0.1f : clip.volume * next / before;
|
|
}
|
|
}
|
|
|
|
public override void Begin()
|
|
{
|
|
if (soundRoot == null)
|
|
{
|
|
soundRoot = new GameObject("SoundRoot");
|
|
Object.DontDestroyOnLoad(soundRoot);
|
|
}
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
foreach (var sourceList in enableObjects)
|
|
{
|
|
foreach (var audioSource in sourceList.Value)
|
|
{
|
|
if (audioSource.clip.loadInBackground == false && audioSource.isPlaying == false)
|
|
{
|
|
removes.Add(audioSource);
|
|
}
|
|
else
|
|
{
|
|
audioSource.mute = IsMuteTag(sourceList.Key);
|
|
}
|
|
}
|
|
sourceList.Value.RemoveAll(u => u.clip.loadInBackground == false && u.isPlaying == false);
|
|
}
|
|
|
|
foreach (var source in fades)
|
|
{
|
|
source.volume -= Time.unscaledDeltaTime;
|
|
if (source.volume <= 0)
|
|
{
|
|
source.Stop();
|
|
removes.Add(source);
|
|
}
|
|
}
|
|
fades.RemoveAll(u => u.volume <= 0);
|
|
|
|
foreach (var audioSource in removes)
|
|
{
|
|
var name = audioSource.clip.name;
|
|
|
|
if (unused.ContainsKey(name) == false)
|
|
{
|
|
unused[name] = new Queue<AudioSource>();
|
|
}
|
|
unused[name].Enqueue(audioSource);
|
|
++unusedCount;
|
|
audioSource.enabled = false;
|
|
}
|
|
removes.Clear();
|
|
|
|
if (unusedCount >= 30)
|
|
{
|
|
ClearPool();
|
|
}
|
|
|
|
if (delaySounds.Count > 0)
|
|
{
|
|
var removeDelaySounds = new List<string>();
|
|
foreach (var delaySound in delaySounds)
|
|
{
|
|
delaySound.Value["Delay"] -= Time.unscaledDeltaTime;
|
|
if (delaySound.Value["Delay"] <= 0)
|
|
{
|
|
var context = delaySound.Value;
|
|
PlaySound(delaySound.Key, context["Tag"], context["Loop"], context["Unique"], context["Reset"], context["Volume"]);
|
|
removeDelaySounds.Add(delaySound.Key);
|
|
}
|
|
}
|
|
foreach (var key in removeDelaySounds)
|
|
{
|
|
delaySounds.Remove(key);
|
|
}
|
|
}
|
|
|
|
currentFramePlays.Clear();
|
|
}
|
|
|
|
public override void End()
|
|
{
|
|
}
|
|
} |