SoundController.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. import { _decorator, Component, Node, Slider, Button, Sprite, SpriteFrame, ProgressBar, resources, tween, Vec3 } from 'cc';
  2. import { AudioManager } from '../../AudioManager/AudioManager';
  3. import { SaveDataManager } from '../../LevelSystem/SaveDataManager';
  4. const { ccclass, property } = _decorator;
  5. /**
  6. * 音频控制器
  7. * 管理音效和音乐的音量控制以及开关状态
  8. */
  9. @ccclass('SoundController')
  10. export class SoundController extends Component {
  11. // 音效控制组件
  12. @property({ type: Slider, tooltip: '音效音量滑动条' })
  13. public soundEffectSlider: Slider = null;
  14. @property({ type: Button, tooltip: '音效开关按钮' })
  15. public soundEffectCheckbox: Button = null;
  16. @property({ type: Node, tooltip: '音效勾选标记节点' })
  17. public soundEffectCheck: Node = null;
  18. @property({ type: ProgressBar, tooltip: '音效进度条' })
  19. public soundEffectProgressBar: ProgressBar = null;
  20. // 音乐控制组件
  21. @property({ type: Slider, tooltip: '音乐音量滑动条' })
  22. public musicSlider: Slider = null;
  23. @property({ type: Button, tooltip: '音乐开关按钮' })
  24. public musicCheckbox: Button = null;
  25. @property({ type: Node, tooltip: '音乐勾选标记节点' })
  26. public musicCheck: Node = null;
  27. @property({ type: ProgressBar, tooltip: '音乐进度条' })
  28. public musicProgressBar: ProgressBar = null;
  29. // 震动控制组件
  30. @property({ type: Button, tooltip: '震动开关按钮' })
  31. public vibrationOnButton: Button = null;
  32. @property({ type: Button, tooltip: '震动关闭按钮' })
  33. public vibrationOffButton: Button = null;
  34. @property({ type: Node, tooltip: '震动滑动节点' })
  35. public vibrationSlideNode: Node = null;
  36. // 音量状态
  37. private soundEffectEnabled: boolean = true;
  38. private musicEnabled: boolean = true;
  39. private savedSoundEffectVolume: number = 0.5;
  40. private savedMusicVolume: number = 0.5;
  41. private vibrationEnabled: boolean = true;
  42. onLoad() {
  43. this.initializeSliders();
  44. this.bindEvents();
  45. this.loadSettings();
  46. }
  47. /**
  48. * 初始化滑动条
  49. */
  50. private initializeSliders() {
  51. if (this.soundEffectSlider) {
  52. this.soundEffectSlider.progress = this.savedSoundEffectVolume;
  53. this.updateProgressBar(this.soundEffectProgressBar, this.soundEffectSlider.progress);
  54. }
  55. if (this.musicSlider) {
  56. this.musicSlider.progress = this.savedMusicVolume;
  57. this.updateProgressBar(this.musicProgressBar, this.musicSlider.progress);
  58. }
  59. }
  60. /**
  61. * 绑定事件
  62. */
  63. private bindEvents() {
  64. // 音效滑动条事件
  65. if (this.soundEffectSlider) {
  66. this.soundEffectSlider.node.on('slide', this.onSoundEffectSliderChange, this);
  67. }
  68. // 音乐滑动条事件
  69. if (this.musicSlider) {
  70. this.musicSlider.node.on('slide', this.onMusicSliderChange, this);
  71. }
  72. // 音效开关按钮事件
  73. if (this.soundEffectCheckbox) {
  74. this.soundEffectCheckbox.node.on(Button.EventType.CLICK, this.onSoundEffectCheckboxClick, this);
  75. }
  76. // 音乐开关按钮事件
  77. if (this.musicCheckbox) {
  78. this.musicCheckbox.node.on(Button.EventType.CLICK, this.onMusicCheckboxClick, this);
  79. }
  80. // 震动开关按钮事件
  81. if (this.vibrationOnButton) {
  82. this.vibrationOnButton.node.on(Button.EventType.CLICK, this.onVibrationOnClick, this);
  83. }
  84. if (this.vibrationOffButton) {
  85. this.vibrationOffButton.node.on(Button.EventType.CLICK, this.onVibrationOffClick, this);
  86. }
  87. }
  88. /**
  89. * 音效滑动条变化事件
  90. */
  91. private onSoundEffectSliderChange(slider: Slider) {
  92. if (this.soundEffectEnabled) {
  93. this.savedSoundEffectVolume = slider.progress;
  94. this.updateProgressBar(this.soundEffectProgressBar, slider.progress);
  95. // TODO: 应用音效音量到音频系统
  96. this.applySoundEffectVolume(slider.progress);
  97. }
  98. }
  99. /**
  100. * 音乐滑动条变化事件
  101. */
  102. private onMusicSliderChange(slider: Slider) {
  103. if (this.musicEnabled) {
  104. this.savedMusicVolume = slider.progress;
  105. this.updateProgressBar(this.musicProgressBar, slider.progress);
  106. // TODO: 应用音乐音量到音频系统
  107. this.applyMusicVolume(slider.progress);
  108. }
  109. }
  110. /**
  111. * 音效开关按钮点击事件
  112. */
  113. private onSoundEffectCheckboxClick() {
  114. this.soundEffectEnabled = !this.soundEffectEnabled;
  115. if (this.soundEffectEnabled) {
  116. // 开启音效:恢复之前保存的音量
  117. this.soundEffectSlider.progress = this.savedSoundEffectVolume;
  118. this.updateProgressBar(this.soundEffectProgressBar, this.savedSoundEffectVolume);
  119. this.applySoundEffectVolume(this.savedSoundEffectVolume);
  120. } else {
  121. // 关闭音效:保存当前音量并设置为0
  122. this.savedSoundEffectVolume = this.soundEffectSlider.progress;
  123. this.soundEffectSlider.progress = 0;
  124. this.updateProgressBar(this.soundEffectProgressBar, 0);
  125. this.applySoundEffectVolume(0);
  126. }
  127. // 更新勾选标记显示
  128. if (this.soundEffectCheck) {
  129. this.soundEffectCheck.active = this.soundEffectEnabled;
  130. }
  131. this.saveSettings();
  132. }
  133. /**
  134. * 音乐开关按钮点击事件
  135. */
  136. private onMusicCheckboxClick() {
  137. this.musicEnabled = !this.musicEnabled;
  138. if (this.musicEnabled) {
  139. // 开启音乐:恢复之前保存的音量
  140. this.musicSlider.progress = this.savedMusicVolume;
  141. this.updateProgressBar(this.musicProgressBar, this.savedMusicVolume);
  142. this.applyMusicVolume(this.savedMusicVolume);
  143. } else {
  144. // 关闭音乐:保存当前音量并设置为0
  145. this.savedMusicVolume = this.musicSlider.progress;
  146. this.musicSlider.progress = 0;
  147. this.updateProgressBar(this.musicProgressBar, 0);
  148. this.applyMusicVolume(0);
  149. }
  150. // 更新勾选标记显示
  151. if (this.musicCheck) {
  152. this.musicCheck.active = this.musicEnabled;
  153. }
  154. this.saveSettings();
  155. }
  156. /**
  157. * 震动开启按钮点击事件
  158. */
  159. private onVibrationOnClick() {
  160. this.vibrationEnabled = true;
  161. this.updateVibrationSlideButton();
  162. this.saveVibrationSetting();
  163. // 开启音效和音乐
  164. this.enableSoundEffectAndMusic();
  165. }
  166. /**
  167. * 震动关闭按钮点击事件
  168. */
  169. private onVibrationOffClick() {
  170. this.vibrationEnabled = false;
  171. this.updateVibrationSlideButton();
  172. this.saveVibrationSetting();
  173. // 关闭音效和音乐
  174. this.disableSoundEffectAndMusic();
  175. }
  176. /**
  177. * 更新震动滑动按钮位置
  178. */
  179. private updateVibrationSlideButton() {
  180. if (!this.vibrationSlideNode || !this.vibrationOnButton || !this.vibrationOffButton) {
  181. return;
  182. }
  183. // 获取目标按钮的位置
  184. const targetButton = this.vibrationEnabled ? this.vibrationOnButton : this.vibrationOffButton;
  185. const targetPosition = targetButton.node.position.clone();
  186. // 使用缓动动画移动滑动节点
  187. tween(this.vibrationSlideNode)
  188. .to(0.3, { position: targetPosition }, { easing: 'sineInOut' })
  189. .start();
  190. }
  191. /**
  192. * 保存震动设置
  193. */
  194. private saveVibrationSetting() {
  195. const saveDataManager = SaveDataManager.getInstance();
  196. if (saveDataManager) {
  197. saveDataManager.updateSetting('vibrationEnabled', this.vibrationEnabled);
  198. }
  199. }
  200. /**
  201. * 立即更新震动滑动按钮位置(不使用动画)
  202. */
  203. private updateVibrationSlideButtonImmediate() {
  204. if (!this.vibrationSlideNode || !this.vibrationOnButton || !this.vibrationOffButton) {
  205. return;
  206. }
  207. // 获取目标按钮的位置
  208. const targetButton = this.vibrationEnabled ? this.vibrationOnButton : this.vibrationOffButton;
  209. const targetPosition = targetButton.node.position.clone();
  210. // 直接设置位置,不使用动画
  211. this.vibrationSlideNode.position = targetPosition;
  212. }
  213. /**
  214. * 更新进度条显示
  215. */
  216. private updateProgressBar(progressBar: ProgressBar, progress: number) {
  217. if (!progressBar) return;
  218. // 直接设置ProgressBar的进度值
  219. // ProgressBar会自动处理背景和前景的显示,保持黑色背景不变
  220. progressBar.progress = progress;
  221. }
  222. /**
  223. * 应用音效音量到音频系统
  224. */
  225. private applySoundEffectVolume(volume: number) {
  226. const audioManager = AudioManager.getInstance();
  227. if (audioManager) {
  228. audioManager.setSoundEffectVolume(volume);
  229. }
  230. //console.log(`[SoundController] 设置音效音量: ${volume}`);
  231. }
  232. /**
  233. * 应用音乐音量到音频系统
  234. */
  235. private applyMusicVolume(volume: number) {
  236. const audioManager = AudioManager.getInstance();
  237. if (audioManager) {
  238. audioManager.setMusicVolume(volume);
  239. }
  240. //console.log(`[SoundController] 设置音乐音量: ${volume}`);
  241. }
  242. /**
  243. * 保存设置到本地存储
  244. */
  245. private saveSettings() {
  246. const settings = {
  247. soundEffectEnabled: this.soundEffectEnabled,
  248. musicEnabled: this.musicEnabled,
  249. soundEffectVolume: this.savedSoundEffectVolume,
  250. musicVolume: this.savedMusicVolume
  251. };
  252. localStorage.setItem('audioSettings', JSON.stringify(settings));
  253. }
  254. /**
  255. * 从本地存储加载设置
  256. */
  257. private loadSettings() {
  258. const savedSettings = localStorage.getItem('audioSettings');
  259. if (savedSettings) {
  260. try {
  261. const settings = JSON.parse(savedSettings);
  262. this.soundEffectEnabled = settings.soundEffectEnabled ?? true;
  263. this.musicEnabled = settings.musicEnabled ?? true;
  264. this.savedSoundEffectVolume = settings.soundEffectVolume ?? 0.8;
  265. this.savedMusicVolume = settings.musicVolume ?? 0.8;
  266. // 更新UI显示
  267. this.updateUI();
  268. } catch (e) {
  269. console.warn('[SoundController] 加载音频设置失败:', e);
  270. }
  271. }
  272. // 从SaveDataManager加载震动设置
  273. const saveDataManager = SaveDataManager.getInstance();
  274. if (saveDataManager) {
  275. this.vibrationEnabled = saveDataManager.getSetting('vibrationEnabled');
  276. }
  277. }
  278. /**
  279. * 更新UI显示
  280. */
  281. private updateUI() {
  282. // 更新勾选标记
  283. if (this.soundEffectCheck) {
  284. this.soundEffectCheck.active = this.soundEffectEnabled;
  285. }
  286. if (this.musicCheck) {
  287. this.musicCheck.active = this.musicEnabled;
  288. }
  289. // 更新滑动条和进度条
  290. if (this.soundEffectSlider) {
  291. this.soundEffectSlider.progress = this.soundEffectEnabled ? this.savedSoundEffectVolume : 0;
  292. this.updateProgressBar(this.soundEffectProgressBar, this.soundEffectSlider.progress);
  293. }
  294. if (this.musicSlider) {
  295. this.musicSlider.progress = this.musicEnabled ? this.savedMusicVolume : 0;
  296. this.updateProgressBar(this.musicProgressBar, this.musicSlider.progress);
  297. }
  298. // 更新震动滑动按钮位置(不使用动画,直接设置位置)
  299. this.updateVibrationSlideButtonImmediate();
  300. }
  301. /**
  302. * 获取当前音效音量
  303. */
  304. public getSoundEffectVolume(): number {
  305. return this.soundEffectEnabled ? this.savedSoundEffectVolume : 0;
  306. }
  307. /**
  308. * 获取当前音乐音量
  309. */
  310. public getMusicVolume(): number {
  311. return this.musicEnabled ? this.savedMusicVolume : 0;
  312. }
  313. /**
  314. * 设置音效音量
  315. */
  316. public setSoundEffectVolume(volume: number) {
  317. this.savedSoundEffectVolume = Math.max(0, Math.min(1, volume));
  318. if (this.soundEffectEnabled && this.soundEffectSlider) {
  319. this.soundEffectSlider.progress = this.savedSoundEffectVolume;
  320. this.updateProgressBar(this.soundEffectProgressBar, this.savedSoundEffectVolume);
  321. this.applySoundEffectVolume(this.savedSoundEffectVolume);
  322. }
  323. this.saveSettings();
  324. }
  325. /**
  326. * 设置音乐音量
  327. */
  328. public setMusicVolume(volume: number) {
  329. this.savedMusicVolume = Math.max(0, Math.min(1, volume));
  330. if (this.musicEnabled && this.musicSlider) {
  331. this.musicSlider.progress = this.savedMusicVolume;
  332. this.updateProgressBar(this.musicProgressBar, this.savedMusicVolume);
  333. this.applyMusicVolume(this.savedMusicVolume);
  334. }
  335. this.saveSettings();
  336. }
  337. /**
  338. * 获取当前震动状态
  339. */
  340. public getVibrationEnabled(): boolean {
  341. return this.vibrationEnabled;
  342. }
  343. /**
  344. * 设置震动状态
  345. */
  346. public setVibrationEnabled(enabled: boolean) {
  347. this.vibrationEnabled = enabled;
  348. this.updateVibrationSlideButton();
  349. this.saveVibrationSetting();
  350. }
  351. /**
  352. * 开启音效和音乐
  353. */
  354. private enableSoundEffectAndMusic() {
  355. // 如果音效未开启,则开启音效
  356. if (!this.soundEffectEnabled) {
  357. this.soundEffectEnabled = true;
  358. // 恢复之前保存的音量或使用默认值0.5
  359. const volumeToRestore = this.savedSoundEffectVolume > 0 ? this.savedSoundEffectVolume : 0.5;
  360. this.soundEffectSlider.progress = volumeToRestore;
  361. this.updateProgressBar(this.soundEffectProgressBar, volumeToRestore);
  362. this.applySoundEffectVolume(volumeToRestore);
  363. // 更新勾选标记显示
  364. if (this.soundEffectCheck) {
  365. this.soundEffectCheck.active = true;
  366. }
  367. }
  368. // 如果音乐未开启,则开启音乐
  369. if (!this.musicEnabled) {
  370. this.musicEnabled = true;
  371. // 恢复之前保存的音量或使用默认值0.5
  372. const volumeToRestore = this.savedMusicVolume > 0 ? this.savedMusicVolume : 0.5;
  373. this.musicSlider.progress = volumeToRestore;
  374. this.updateProgressBar(this.musicProgressBar, volumeToRestore);
  375. this.applyMusicVolume(volumeToRestore);
  376. // 更新勾选标记显示
  377. if (this.musicCheck) {
  378. this.musicCheck.active = true;
  379. }
  380. }
  381. this.saveSettings();
  382. }
  383. /**
  384. * 关闭音效和音乐
  385. */
  386. private disableSoundEffectAndMusic() {
  387. // 关闭音效
  388. if (this.soundEffectEnabled) {
  389. this.soundEffectEnabled = false;
  390. // 保存当前音量并设置为0
  391. this.savedSoundEffectVolume = this.soundEffectSlider.progress;
  392. this.soundEffectSlider.progress = 0;
  393. this.updateProgressBar(this.soundEffectProgressBar, 0);
  394. this.applySoundEffectVolume(0);
  395. // 更新勾选标记显示
  396. if (this.soundEffectCheck) {
  397. this.soundEffectCheck.active = false;
  398. }
  399. }
  400. // 关闭音乐
  401. if (this.musicEnabled) {
  402. this.musicEnabled = false;
  403. // 保存当前音量并设置为0
  404. this.savedMusicVolume = this.musicSlider.progress;
  405. this.musicSlider.progress = 0;
  406. this.updateProgressBar(this.musicProgressBar, 0);
  407. this.applyMusicVolume(0);
  408. // 更新勾选标记显示
  409. if (this.musicCheck) {
  410. this.musicCheck.active = false;
  411. }
  412. }
  413. this.saveSettings();
  414. }
  415. }