AudioManager.ts 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import { assetManager, AudioClip, AudioSource, director, Node, sys } from 'cc';
  2. import { LocalStorageMgr } from './game/LocalStorageMgr';
  3. export class AudioManager {
  4. /** 单例模式 */
  5. private static _ins: AudioManager;
  6. constructor() {
  7. const audioMgr = new Node();
  8. audioMgr.name = '__audioMgr__';
  9. AudioManager._ins = this;
  10. director.getScene().addChild(audioMgr);
  11. director.addPersistRootNode(audioMgr);
  12. // 创建一个 AudioSource 用于背景音乐
  13. this._bgmAudioSource = audioMgr.addComponent(AudioSource);
  14. // 创建一个 AudioSource 用于effect音效
  15. this._effectAudioSource = audioMgr.addComponent(AudioSource);
  16. // 创建一个 AudioSource 用于可在随意时间停止的音效
  17. this._effectDiAudioSource = audioMgr.addComponent(AudioSource);
  18. // 从本地存储恢复静音状态
  19. const effectMuteState: boolean = LocalStorageMgr.getItem('audio_effectMute');
  20. const bgmMuteState: boolean = LocalStorageMgr.getItem('audio_bgmMute');
  21. this.effectMute = effectMuteState ?? false;
  22. this.bgmMute = bgmMuteState ?? false;
  23. this._updateBGMVolume();
  24. }
  25. public static get ins(): AudioManager {
  26. if (!AudioManager._ins) {
  27. AudioManager._ins = new AudioManager();
  28. }
  29. return AudioManager._ins;
  30. }
  31. private _bgmAudioSource: AudioSource;
  32. private _effectAudioSource: AudioSource;
  33. private _effectDiAudioSource: AudioSource;
  34. private bgmVolume = 1.0;
  35. private soundVolume = 1.0;
  36. private _isEffectMuted: boolean = false;
  37. private _isBGMMuted: boolean = false;
  38. private _activeOneShotSources: Map<string, AudioSource> = new Map();
  39. public get effectMute() {
  40. if (this._isEffectMuted === undefined) {
  41. this.effectMute = LocalStorageMgr.getItem('audio_effectMute') ?? false;
  42. }
  43. return this._isEffectMuted;
  44. }
  45. public set effectMute(muted: boolean) {
  46. this._isEffectMuted = muted;
  47. LocalStorageMgr.setItem('audio_effectMute', muted);
  48. }
  49. public get bgmMute() {
  50. if (this._isBGMMuted === undefined) {
  51. this.bgmMute = LocalStorageMgr.getItem('audio_bgmMute') ?? false;
  52. }
  53. return this._isBGMMuted;
  54. }
  55. public set bgmMute(muted: boolean) {
  56. this._isBGMMuted = muted;
  57. LocalStorageMgr.setItem('audio_bgmMute', muted);
  58. this._updateBGMVolume(muted);
  59. }
  60. private _updateBGMVolume(mute?: boolean) {
  61. mute = mute ?? this.bgmMute;
  62. this._bgmAudioSource.volume = mute ? 0 : 1;
  63. }
  64. playOneShot(sound: AudioClip | string, volume: number = 1.0, bundleName: string = 'resources') {
  65. if (this._isEffectMuted) return; // 如果音效静音,直接返回
  66. if (sound instanceof AudioClip) {
  67. this._effectAudioSource.playOneShot(sound, volume);
  68. } else {
  69. let bundle = assetManager.getBundle(bundleName);
  70. bundle.load(sound, (err, clip: AudioClip) => {
  71. if (err) {
  72. console.log(err);
  73. } else {
  74. this._effectAudioSource.playOneShot(clip, volume);
  75. }
  76. });
  77. }
  78. }
  79. /** 播放一个短音效,可以控制停止暂停 */
  80. playEff(sound: AudioClip | string, bundleName: string = 'resources') {
  81. if (this._isEffectMuted) return; // 如果音效静音,直接返回
  82. if (sound instanceof AudioClip) {
  83. this._effectDiAudioSource.stop();
  84. this._effectDiAudioSource.clip = sound;
  85. this._effectDiAudioSource.loop = false; // 不循环播放
  86. this._effectDiAudioSource.play();
  87. } else {
  88. let bundle = assetManager.getBundle(bundleName);
  89. bundle.load(sound, (err, clip: AudioClip) => {
  90. if (err) {
  91. console.log(err);
  92. } else {
  93. this._effectDiAudioSource.stop();
  94. this._effectDiAudioSource.clip = clip;
  95. this._effectDiAudioSource.loop = false; // 不循环播放
  96. this._effectDiAudioSource.play();
  97. }
  98. });
  99. }
  100. }
  101. /**
  102. * 停止播放playEff指定的短音效
  103. */
  104. stopPlayEff(sound: AudioClip | string) {
  105. const audioSource = this._effectDiAudioSource;
  106. if (audioSource) {
  107. audioSource.stop();
  108. } else {
  109. console.log(`Sound ${sound} is not currently playing.`);
  110. }
  111. }
  112. play(sound: AudioClip | string, loop: boolean = true, bundleName: string = 'resources') {
  113. if (this.bgmMute) {
  114. this.bgmVolume = 0
  115. } else {
  116. this.bgmVolume = 1;
  117. }
  118. if (sound instanceof AudioClip) {
  119. this._bgmAudioSource.stop();
  120. this._bgmAudioSource.clip = sound;
  121. this._bgmAudioSource.loop = loop;
  122. this._bgmAudioSource.play();
  123. this._updateBGMVolume();
  124. } else {
  125. const bundle = assetManager.getBundle(bundleName);
  126. if (!bundle) {
  127. // console.error(`Bundle ${bundleName} not found.`);
  128. return;
  129. }
  130. bundle.load(sound, (err, clip: AudioClip) => {
  131. if (err) {
  132. // console.error(`Failed to load sound ${sound}: ${err}`);
  133. } else if (clip) {
  134. this._bgmAudioSource.stop();
  135. this._bgmAudioSource.clip = clip;
  136. this._bgmAudioSource.loop = loop;
  137. this._bgmAudioSource.play();
  138. this._updateBGMVolume();
  139. }
  140. });
  141. }
  142. }
  143. stopBgm() {
  144. this._bgmAudioSource.stop();
  145. }
  146. pauseBgm() {
  147. this._bgmAudioSource.pause();
  148. }
  149. resumeBgm() {
  150. this._bgmAudioSource.play();
  151. }
  152. }