Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / manager / SoundManager.cs
@小李xl 小李xl on 22 Jun 2023 7 KB 调整整体音量
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using Godot;
  5.  
  6. /// <summary>
  7. /// 音频总线 区分不同的声音 添加声音效果 目前只有背景音乐 和音效 两个bus
  8. /// </summary>
  9. public enum BUS
  10. {
  11. BGM = 0,
  12. SFX = 1
  13. }
  14.  
  15. /// <summary>
  16. /// 声音管理 背景音乐管理 音效
  17. /// </summary>
  18. public partial class SoundManager
  19. {
  20. /// <summary>
  21. /// 全局音效音量, 范围 0 - 1
  22. /// </summary>
  23. public static float SoundVolume { get; set; } = 0.4f;
  24. private static Stack<GameAudioPlayer2D> _streamPlayer2DStack = new Stack<GameAudioPlayer2D>();
  25. private static Stack<GameAudioPlayer> _streamPlayerStack = new Stack<GameAudioPlayer>();
  26. private static HashSet<string> _playingSoundResourceList = new HashSet<string>();
  27.  
  28. /// <summary>
  29. /// 2D音频播放节点
  30. /// </summary>
  31. public partial class GameAudioPlayer2D : AudioStreamPlayer2D
  32. {
  33. public override void _Ready()
  34. {
  35. Finished += OnPlayFinish;
  36. }
  37.  
  38. public void PlaySoundByResource(string path, float delayTime)
  39. {
  40. if (delayTime <= 0)
  41. {
  42. PlaySoundByResource(path);
  43. }
  44. else
  45. {
  46. GameApplication.Instance.StartCoroutine(DelayPlay(path, delayTime));
  47. }
  48. }
  49.  
  50. public void PlaySoundByResource(string path)
  51. {
  52. if (_playingSoundResourceList.Contains(path))
  53. {
  54. GD.Print("重复播放: " + path);
  55. }
  56. else
  57. {
  58. _playingSoundResourceList.Add(path);
  59. var sound = ResourceManager.Load<AudioStream>(path);
  60. Stream = sound;
  61. Bus = Enum.GetName(typeof(BUS), 1);
  62. Play();
  63. }
  64. }
  65.  
  66. /// <summary>
  67. /// 停止播放, 并回收节点
  68. /// </summary>
  69. public void StopPlay()
  70. {
  71. Stop();
  72. OnPlayFinish();
  73. }
  74.  
  75. private void OnPlayFinish()
  76. {
  77. RecycleAudioPlayer2D(this);
  78. }
  79.  
  80. private IEnumerator DelayPlay(string path, float delayTime)
  81. {
  82. yield return new WaitForSeconds(delayTime);
  83. PlaySoundByResource(path);
  84. }
  85. }
  86.  
  87. /// <summary>
  88. /// 音频播放节点
  89. /// </summary>
  90. public partial class GameAudioPlayer : AudioStreamPlayer
  91. {
  92. public string SoundResourceName { get; set; }
  93. public override void _Ready()
  94. {
  95. Finished += OnPlayFinish;
  96. }
  97.  
  98. /// <summary>
  99. /// 停止播放, 并回收节点
  100. /// </summary>
  101. public void StopPlay()
  102. {
  103. Stop();
  104. OnPlayFinish();
  105. }
  106. private void OnPlayFinish()
  107. {
  108. GetParent().RemoveChild(this);
  109. Stream = null;
  110. Playing = false;
  111. RecycleAudioPlayer(this);
  112. }
  113. }
  114.  
  115. public static void Update(float delta)
  116. {
  117. _playingSoundResourceList.Clear();
  118. }
  119. /// <summary>
  120. /// 播放声音 用于bgm
  121. /// </summary>
  122. /// <param name="soundName">bgm路径</param>
  123. /// <param name="volume">音量</param>
  124. public static GameAudioPlayer PlayMusic(string soundName, float volume = 0.5f)
  125. {
  126. var sound = ResourceManager.Load<AudioStream>(soundName);
  127. var soundNode = GetAudioPlayerInstance();
  128. GameApplication.Instance.GlobalNodeRoot.AddChild(soundNode);
  129. soundNode.Stream = sound;
  130. soundNode.Bus = Enum.GetName(typeof(BUS), 0);
  131. soundNode.VolumeDb = volume;
  132. soundNode.Play();
  133. return soundNode;
  134. }
  135.  
  136. /// <summary>
  137. /// 添加并播放音效 用于音效
  138. /// </summary>
  139. /// <param name="soundName">音效文件路径</param>
  140. /// <param name="volume">音量 (0 - 1)</param>
  141. public static GameAudioPlayer PlaySoundEffect(string soundName, float volume = 1f)
  142. {
  143. var sound = ResourceManager.Load<AudioStream>(soundName);
  144. var soundNode = GetAudioPlayerInstance();
  145. GameApplication.Instance.GlobalNodeRoot.AddChild(soundNode);
  146. soundNode.Stream = sound;
  147. soundNode.Bus = Enum.GetName(typeof(BUS), 1);
  148. soundNode.VolumeDb = Mathf.LinearToDb(Mathf.Clamp(volume, 0, 1));
  149. soundNode.Play();
  150. return soundNode;
  151. }
  152.  
  153. /// <summary>
  154. /// 在指定的节点下播放音效 用于音效
  155. /// </summary>
  156. /// <param name="soundName">音效文件路径</param>
  157. /// <param name="pos">发声节点所在全局坐标</param>
  158. /// <param name="volume">音量 (0 - 1)</param>
  159. /// <param name="target">挂载节点, 为null则挂载到房间根节点下</param>
  160. public static GameAudioPlayer2D PlaySoundEffectPosition(string soundName, Vector2 pos, float volume = 1f, Node2D target = null)
  161. {
  162. return PlaySoundEffectPositionDelay(soundName, pos, 0, volume, target);
  163. }
  164.  
  165. /// <summary>
  166. /// 在指定的节点下延时播放音效 用于音效
  167. /// </summary>
  168. /// <param name="soundName">音效文件路径</param>
  169. /// <param name="pos">发声节点所在全局坐标</param>
  170. /// <param name="delayTime">延时时间</param>
  171. /// <param name="volume">音量 (0 - 1)</param>
  172. /// <param name="target">挂载节点, 为null则挂载到房间根节点下</param>
  173. public static GameAudioPlayer2D PlaySoundEffectPositionDelay(string soundName, Vector2 pos, float delayTime, float volume = 1f, Node2D target = null)
  174. {
  175. var soundNode = GetAudioPlayer2DInstance();
  176. if (target != null)
  177. {
  178. target.AddChild(soundNode);
  179. }
  180. else
  181. {
  182. GameApplication.Instance.GlobalNodeRoot.AddChild(soundNode);
  183. }
  184. soundNode.GlobalPosition = pos;
  185. soundNode.VolumeDb = Mathf.LinearToDb(Mathf.Clamp(volume * SoundVolume, 0, 1));
  186. soundNode.PlaySoundByResource(soundName, delayTime);
  187. return soundNode;
  188. }
  189.  
  190. /// <summary>
  191. /// 获取2D音频播放节点
  192. /// </summary>
  193. private static GameAudioPlayer2D GetAudioPlayer2DInstance()
  194. {
  195. if (_streamPlayer2DStack.Count > 0)
  196. {
  197. return _streamPlayer2DStack.Pop();
  198. }
  199.  
  200. var inst = new GameAudioPlayer2D();
  201. inst.AreaMask = 0;
  202. return inst;
  203. }
  204.  
  205. /// <summary>
  206. /// 获取音频播放节点
  207. /// </summary>
  208. private static GameAudioPlayer GetAudioPlayerInstance()
  209. {
  210. if (_streamPlayerStack.Count > 0)
  211. {
  212. return _streamPlayerStack.Pop();
  213. }
  214.  
  215. return new GameAudioPlayer();
  216. }
  217.  
  218. /// <summary>
  219. /// 回收2D音频播放节点
  220. /// </summary>
  221. private static void RecycleAudioPlayer2D(GameAudioPlayer2D inst)
  222. {
  223. var parent = inst.GetParent();
  224. if (parent != null)
  225. {
  226. parent.RemoveChild(inst);
  227. }
  228.  
  229. inst.Stream = null;
  230. _streamPlayer2DStack.Push(inst);
  231. }
  232.  
  233. /// <summary>
  234. /// 回收音频播放节点
  235. /// </summary>
  236. private static void RecycleAudioPlayer(GameAudioPlayer inst)
  237. {
  238. _streamPlayerStack.Push(inst);
  239. }
  240.  
  241. /// <summary>
  242. /// 计算指定角色播放音效使用的音量
  243. /// </summary>
  244. public static float CalcRoleVolume(float volume, Role role)
  245. {
  246. if (role is not Player)
  247. {
  248. return volume * 0.4f;
  249. }
  250.  
  251. return volume;
  252. }
  253. }