Unity3d简便的声音管理方案
本方法是对Ez-Sound-Manager的扩展
https://github.com/JackM36/Eazy-Sound-Manager
参考Audio Toolkit Free Version
http://unity.clockstone.com/
SoundManager
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using UnityEngine; 3 using System.Collections.Generic; 4 5 namespace ZStudio.SoundManager 6 { 7 public class SoundManager : MonoBehaviour 8 { 9 private static SoundManager _instance = null; 10 private static float vol = 1f; 11 private static float musicVol = 1f; 12 private static float soundsVol = 1f; 13 private static float UISoundsVol = 1f; 14 15 private static Dictionary<int, Audio> musicAudio; 16 private static Dictionary<int, Audio> soundsAudio; 17 private static Dictionary<int, Audio> UISoundsAudio; 18 19 private static bool initialized = false; 20 21 private static SoundManager instance 22 { 23 get 24 { 25 if (_instance == null) 26 { 27 _instance = (SoundManager)FindObjectOfType(typeof(SoundManager)); 28 if (_instance == null) 29 { 30 // Create gameObject and add component 31 _instance = (new GameObject("ZSoundManager")).AddComponent<SoundManager>(); 32 } 33 } 34 return _instance; 35 } 36 } 37 38 /// <summary> 39 /// The gameobject that the sound manager is attached to 40 /// </summary> 41 public static GameObject gameobject { get { return instance.gameObject; } } 42 43 /// <summary> 44 /// When set to true, new Audios that have the same audio clip as any other Audio, will be ignored 45 /// </summary> 46 public static bool ignoreDuplicateMusic { get; set; } 47 48 /// <summary> 49 /// When set to true, new Audios that have the same audio clip as any other Audio, will be ignored 50 /// </summary> 51 public static bool ignoreDuplicateSounds { get; set; } 52 53 /// <summary> 54 /// When set to true, new Audios that have the same audio clip as any other Audio, will be ignored 55 /// </summary> 56 public static bool ignoreDuplicateUISounds { get; set; } 57 58 /// <summary> 59 /// Global volume 60 /// </summary> 61 public static float globalVolume 62 { 63 get 64 { 65 return vol; 66 } 67 set 68 { 69 vol = value; 70 } 71 } 72 73 /// <summary> 74 /// Global music volume 75 /// </summary> 76 public static float globalMusicVolume 77 { 78 get 79 { 80 return musicVol; 81 } 82 set 83 { 84 musicVol = value; 85 } 86 } 87 88 /// <summary> 89 /// Global sounds volume 90 /// </summary> 91 public static float globalSoundsVolume 92 { 93 get 94 { 95 return soundsVol; 96 } 97 set 98 { 99 soundsVol = value; 100 } 101 } 102 103 /// <summary> 104 /// Global UI sounds volume 105 /// </summary> 106 public static float globalUISoundsVolume 107 { 108 get 109 { 110 return UISoundsVol; 111 } 112 set 113 { 114 UISoundsVol = value; 115 } 116 } 117 118 void Awake() 119 { 120 instance.Init(); 121 } 122 123 void Update() 124 { 125 List<int> keys; 126 127 // Update music 128 keys = new List<int>(musicAudio.Keys); 129 for (var i = 0; i < keys.Count; i++) 130 { 131 int key = keys[i]; 132 Audio _audio = musicAudio[key]; 133 _audio.Update(); 134 135 // Remove all music clips that are not playing 136 if (!_audio.playing && !_audio.paused) 137 { 138 if (_audio.onComletelyPlayed != null) 139 _audio.onComletelyPlayed.Invoke(_audio); 140 Destroy(_audio.audioSource); 141 musicAudio.Remove(key); 142 } 143 } 144 145 // Update sound fx 146 keys = new List<int>(soundsAudio.Keys); 147 for (var i = 0; i < keys.Count; i++) 148 { 149 int key = keys[i]; 150 Audio _audio = soundsAudio[key]; 151 _audio.Update(); 152 153 // Remove all sound fx clips that are not playing 154 if (!_audio.playing && !_audio.paused) 155 { 156 if (_audio.onComletelyPlayed != null) 157 _audio.onComletelyPlayed.Invoke(_audio); 158 Destroy(_audio.audioSource); 159 soundsAudio.Remove(key); 160 } 161 } 162 163 // Update UI sound fx 164 keys = new List<int>(UISoundsAudio.Keys); 165 for (var i = 0; i < keys.Count; i++) 166 { 167 int key = keys[i]; 168 Audio _audio = UISoundsAudio[key]; 169 _audio.Update(); 170 171 // Remove all UI sound fx clips that are not playing 172 if (!_audio.playing && !_audio.paused) 173 { 174 if (_audio.onComletelyPlayed != null) 175 _audio.onComletelyPlayed.Invoke(_audio); 176 Destroy(_audio.audioSource); 177 UISoundsAudio.Remove(key); 178 } 179 } 180 } 181 182 void Init() 183 { 184 if (!initialized) 185 { 186 musicAudio = new Dictionary<int, Audio>(); 187 soundsAudio = new Dictionary<int, Audio>(); 188 UISoundsAudio = new Dictionary<int, Audio>(); 189 190 ignoreDuplicateMusic = false; 191 ignoreDuplicateSounds = false; 192 ignoreDuplicateUISounds = false; 193 194 initialized = true; 195 DontDestroyOnLoad(this); 196 } 197 } 198 199 #region GetAudio Functions 200 201 /// <summary> 202 /// Returns the Audio that has as its id the audioID if one is found, returns null if no such Audio is found 203 /// </summary> 204 /// <param name="audioID">The id of the Audio to be retrieved</param> 205 /// <returns>Audio that has as its id the audioID, null if no such Audio is found</returns> 206 public static Audio GetAudio(int audioID) 207 { 208 Audio audio; 209 210 audio = GetMusicAudio(audioID); 211 if (audio != null) 212 { 213 return audio; 214 } 215 216 audio = GetSoundAudio(audioID); 217 if (audio != null) 218 { 219 return audio; 220 } 221 222 audio = GetUISoundAudio(audioID); 223 if (audio != null) 224 { 225 return audio; 226 } 227 228 return null; 229 } 230 231 /// <summary> 232 /// Returns the first occurrence of Audio that plays the given audioClip. Returns null if no such Audio is found 233 /// </summary> 234 /// <param name="audioClip">The audio clip of the Audio to be retrieved</param> 235 /// <returns>First occurrence of Audio that has as plays the audioClip, null if no such Audio is found</returns> 236 public static Audio GetAudio(AudioClip audioClip) 237 { 238 Audio audio = GetMusicAudio(audioClip); 239 if (audio != null) 240 { 241 return audio; 242 } 243 244 audio = GetSoundAudio(audioClip); 245 if (audio != null) 246 { 247 return audio; 248 } 249 250 audio = GetUISoundAudio(audioClip); 251 if (audio != null) 252 { 253 return audio; 254 } 255 256 return null; 257 } 258 259 /// <summary> 260 /// Returns the music Audio that has as its id the audioID if one is found, returns null if no such Audio is found 261 /// </summary> 262 /// <param name="audioID">The id of the music Audio to be returned</param> 263 /// <returns>Music Audio that has as its id the audioID if one is found, null if no such Audio is found</returns> 264 public static Audio GetMusicAudio(int audioID) 265 { 266 List<int> keys = new List<int>(musicAudio.Keys); 267 foreach (int key in keys) 268 { 269 if (audioID == key) 270 { 271 return musicAudio[key]; 272 } 273 } 274 275 return null; 276 } 277 278 /// <summary> 279 /// Returns the first occurrence of music Audio that plays the given audioClip. Returns null if no such Audio is found 280 /// </summary> 281 /// <param name="audioClip">The audio clip of the music Audio to be retrieved</param> 282 /// <returns>First occurrence of music Audio that has as plays the audioClip, null if no such Audio is found</returns> 283 public static Audio GetMusicAudio(AudioClip audioClip) 284 { 285 List<int> keys; 286 keys = new List<int>(musicAudio.Keys); 287 foreach (int key in keys) 288 { 289 Audio audio = musicAudio[key]; 290 if (audio.clip == audioClip) 291 { 292 return audio; 293 } 294 } 295 296 return null; 297 } 298 299 /// <summary> 300 /// Returns the sound fx Audio that has as its id the audioID if one is found, returns null if no such Audio is found 301 /// </summary> 302 /// <param name="audioID">The id of the sound fx Audio to be returned</param> 303 /// <returns>Sound fx Audio that has as its id the audioID if one is found, null if no such Audio is found</returns> 304 public static Audio GetSoundAudio(int audioID) 305 { 306 List<int> keys = new List<int>(soundsAudio.Keys); 307 foreach (int key in keys) 308 { 309 if (audioID == key) 310 { 311 return soundsAudio[key]; 312 } 313 } 314 315 return null; 316 } 317 318 /// <summary> 319 /// Returns the first occurrence of sound Audio that plays the given audioClip. Returns null if no such Audio is found 320 /// </summary> 321 /// <param name="audioClip">The audio clip of the sound Audio to be retrieved</param> 322 /// <returns>First occurrence of sound Audio that has as plays the audioClip, null if no such Audio is found</returns> 323 public static Audio GetSoundAudio(AudioClip audioClip) 324 { 325 List<int> keys; 326 keys = new List<int>(soundsAudio.Keys); 327 foreach (int key in keys) 328 { 329 Audio audio = soundsAudio[key]; 330 if (audio.clip == audioClip) 331 { 332 return audio; 333 } 334 } 335 336 return null; 337 } 338 339 /// <summary> 340 /// Returns the UI sound fx Audio that has as its id the audioID if one is found, returns null if no such Audio is found 341 /// </summary> 342 /// <param name="audioID">The id of the UI sound fx Audio to be returned</param> 343 /// <returns>UI sound fx Audio that has as its id the audioID if one is found, null if no such Audio is found</returns> 344 public static Audio GetUISoundAudio(int audioID) 345 { 346 List<int> keys = new List<int>(UISoundsAudio.Keys); 347 foreach (int key in keys) 348 { 349 if (audioID == key) 350 { 351 return UISoundsAudio[key]; 352 } 353 } 354 355 return null; 356 } 357 358 /// <summary> 359 /// Returns the first occurrence of UI sound Audio that plays the given audioClip. Returns null if no such Audio is found 360 /// </summary> 361 /// <param name="audioClip">The audio clip of the UI sound Audio to be retrieved</param> 362 /// <returns>First occurrence of UI sound Audio that has as plays the audioClip, null if no such Audio is found</returns> 363 public static Audio GetUISoundAudio(AudioClip audioClip) 364 { 365 List<int> keys; 366 keys = new List<int>(UISoundsAudio.Keys); 367 foreach (int key in keys) 368 { 369 Audio audio = UISoundsAudio[key]; 370 if (audio.clip == audioClip) 371 { 372 return audio; 373 } 374 } 375 376 return null; 377 } 378 379 #endregion 380 381 #region Play Functions 382 383 /// <summary> 384 /// Play background music 385 /// </summary> 386 /// <param name="clip">The audio clip to play</param> 387 /// <param name="onCompletelyPlayed">The audio play completed</param> 388 /// <returns>The ID of the created Audio object</returns> 389 public static int PlayMusic(AudioClip clip, Action<Audio> onCompletelyPlayed) 390 { 391 return PlayMusic(clip, 1f, false, false, 1f, 1f, -1f, null, onCompletelyPlayed); 392 } 393 394 /// <summary> 395 /// Play background music 396 /// </summary> 397 /// <param name="clip">The audio clip to play</param> 398 /// <param name="volume"> The volume the music will have</param> 399 /// <param name="onCompletelyPlayed">The audio play completed</param> 400 /// <returns>The ID of the created Audio object</returns> 401 public static int PlayMusic(AudioClip clip, float volume, Action<Audio> onCompletelyPlayed) 402 { 403 return PlayMusic(clip, volume, false, false, 1f, 1f, -1f, null, onCompletelyPlayed); 404 } 405 406 /// <summary> 407 /// Play background music 408 /// </summary> 409 /// <param name="clip">The audio clip to play</param> 410 /// <param name="volume"> The volume the music will have</param> 411 /// <param name="loop">Wether the music is looped</param> 412 /// <param name = "persist" > Whether the audio persists in between scene changes</param> 413 /// <param name="onCompletelyPlayed">The audio play completed</param> 414 /// <returns>The ID of the created Audio object</returns> 415 public static int PlayMusic(AudioClip clip, float volume, bool loop, bool persist, Action<Audio> onCompletelyPlayed) 416 { 417 return PlayMusic(clip, volume, loop, persist, 1f, 1f, -1f, null, onCompletelyPlayed); 418 } 419 420 /// <summary> 421 /// Play background music 422 /// </summary> 423 /// <param name="clip">The audio clip to play</param> 424 /// <param name="volume"> The volume the music will have</param> 425 /// <param name="loop">Wether the music is looped</param> 426 /// <param name="persist"> Whether the audio persists in between scene changes</param> 427 /// <param name="fadeInSeconds">How many seconds it needs for the audio to fade in/ reach target volume (if higher than current)</param> 428 /// <param name="fadeOutSeconds"> How many seconds it needs for the audio to fade out/ reach target volume (if lower than current)</param> 429 /// <param name="onCompletelyPlayed">The audio play completed</param> 430 /// <returns>The ID of the created Audio object</returns> 431 public static int PlayMusic(AudioClip clip, float volume, bool loop, bool persist, float fadeInSeconds, 432 float fadeOutSeconds, Action<Audio> onCompletelyPlayed) 433 { 434 return PlayMusic(clip, volume, loop, persist, fadeInSeconds, fadeOutSeconds, -1f, null, onCompletelyPlayed); 435 } 436 437 /// <summary> 438 /// Play background music 439 /// </summary> 440 /// <param name="clip">The audio clip to play</param> 441 /// <param name="volume"> The volume the music will have</param> 442 /// <param name="loop">Wether the music is looped</param> 443 /// <param name="persist"> Whether the audio persists in between scene changes</param> 444 /// <param name="fadeInSeconds">How many seconds it needs for the audio to fade in/ reach target volume (if higher than current)</param> 445 /// <param name="fadeOutSeconds"> How many seconds it needs for the audio to fade out/ reach target volume (if lower than current)</param> 446 /// <param name="currentMusicfadeOutSeconds"> How many seconds it needs for current music audio to fade out. It will override its own fade out seconds. If -1 is passed, current music will keep its own fade out seconds</param> 447 /// <param name="sourceTransform">The transform that is the source of the music (will become 3D audio). If 3D audio is not wanted, use null</param> 448 /// <param name="onCompletelyPlayed">The audio play completed</param> 449 /// <returns>The ID of the created Audio object</returns> 450 public static int PlayMusic(AudioClip clip, float volume, bool loop, bool persist, float fadeInSeconds, 451 float fadeOutSeconds, float currentMusicfadeOutSeconds, Transform sourceTransform, Action<Audio> onCompletelyPlayed) 452 { 453 if (clip == null) 454 { 455 Debug.LogError("Sound Manager: Audio clip is null, cannot play music", clip); 456 } 457 458 if(ignoreDuplicateMusic) 459 { 460 List<int> keys = new List<int>(musicAudio.Keys); 461 foreach (int key in keys) 462 { 463 if (musicAudio[key].audioSource.clip == clip) 464 { 465 return musicAudio[key].audioID; 466 } 467 } 468 } 469 470 instance.Init(); 471 472 // Stop all current music playing 473 StopAllMusic(currentMusicfadeOutSeconds); 474 475 // Create the audioSource 476 //AudioSource audioSource = instance.gameObject.AddComponent<AudioSource>() as AudioSource; 477 Audio audio = new Audio(Audio.AudioType.Music, clip, loop, persist, volume, fadeInSeconds, fadeOutSeconds, 478 sourceTransform, onCompletelyPlayed); 479 480 // Add it to music list 481 musicAudio.Add(audio.audioID, audio); 482 483 return audio.audioID; 484 } 485 486 /// <summary> 487 /// Play a sound fx 488 /// </summary> 489 /// <param name="clip">The audio clip to play</param> 490 /// <param name="onCompletelyPlayed">The audio play completed</param> 491 /// <returns>The ID of the created Audio object</returns> 492 public static int PlaySound(AudioClip clip, Action<Audio> onCompletelyPlayed) 493 { 494 return PlaySound(clip, 1f, false, null, onCompletelyPlayed); 495 } 496 497 /// <summary> 498 /// Play a sound fx 499 /// </summary> 500 /// <param name="clip">The audio clip to play</param> 501 /// <param name="volume"> The volume the music will have</param> 502 /// <param name="onCompletelyPlayed">The audio play completed</param> 503 /// <returns>The ID of the created Audio object</returns> 504 public static int PlaySound(AudioClip clip, float volume, Action<Audio> onCompletelyPlayed) 505 { 506 return PlaySound(clip, volume, false, null, onCompletelyPlayed); 507 } 508 509 /// <summary> 510 /// Play a sound fx 511 /// </summary> 512 /// <param name="clip">The audio clip to play</param> 513 /// <param name="loop">Wether the sound is looped</param> 514 /// <param name="onCompletelyPlayed">The audio play completed</param> 515 /// <returns>The ID of the created Audio object</returns> 516 public static int PlaySound(AudioClip clip, bool loop, Action<Audio> onCompletelyPlayed) 517 { 518 return PlaySound(clip, 1f, loop, null, onCompletelyPlayed); 519 } 520 521 /// <summary> 522 /// Play a sound fx 523 /// </summary> 524 /// <param name="clip">The audio clip to play</param> 525 /// <param name="volume"> The volume the music will have</param> 526 /// <param name="loop">Wether the sound is looped</param> 527 /// <param name="sourceTransform">The transform that is the source of the sound (will become 3D audio). If 3D audio is not wanted, use null</param> 528 /// <param name="onCompletelyPlayed">The audio play completed</param> 529 /// <returns>The ID of the created Audio object</returns> 530 public static int PlaySound(AudioClip clip, float volume, bool loop, Transform sourceTransform, Action<Audio> onCompletelyPlayed) 531 { 532 if (clip == null) 533 { 534 Debug.LogError("Sound Manager: Audio clip is null, cannot play music", clip); 535 } 536 537 if (ignoreDuplicateSounds) 538 { 539 List<int> keys = new List<int>(soundsAudio.Keys); 540 foreach (int key in keys) 541 { 542 if (soundsAudio[key].audioSource.clip == clip) 543 { 544 return soundsAudio[key].audioID; 545 } 546 } 547 } 548 549 instance.Init(); 550 551 // Create the audioSource 552 //AudioSource audioSource = instance.gameObject.AddComponent<AudioSource>() as AudioSource; 553 Audio audio = new Audio(Audio.AudioType.Sound, clip, loop, false, volume, 0f, 0f, sourceTransform, onCompletelyPlayed); 554 555 // Add it to music list 556 soundsAudio.Add(audio.audioID, audio); 557 558 return audio.audioID; 559 } 560 561 /// <summary> 562 /// Play a UI sound fx 563 /// </summary> 564 /// <param name="clip">The audio clip to play</param> 565 /// <param name="onCompletelyPlayed">The audio play completed</param> 566 /// <returns>The ID of the created Audio object</returns> 567 public static int PlayUISound(AudioClip clip, Action<Audio> onCompletelyPlayed) 568 { 569 return PlayUISound(clip, 1f, onCompletelyPlayed); 570 } 571 572 /// <summary> 573 /// Play a UI sound fx 574 /// </summary> 575 /// <param name="clip">The audio clip to play</param> 576 /// <param name="volume"> The volume the music will have</param> 577 /// <param name="onCompletelyPlayed">The audio play completed</param> 578 /// <returns>The ID of the created Audio object</returns> 579 public static int PlayUISound(AudioClip clip, float volume, Action<Audio> onCompletelyPlayed) 580 { 581 if (clip == null) 582 { 583 Debug.LogError("Sound Manager: Audio clip is null, cannot play music", clip); 584 } 585 586 if (ignoreDuplicateUISounds) 587 { 588 List<int> keys = new List<int>(UISoundsAudio.Keys); 589 foreach (int key in keys) 590 { 591 if (UISoundsAudio[key].audioSource.clip == clip) 592 { 593 return UISoundsAudio[key].audioID; 594 } 595 } 596 } 597 598 instance.Init(); 599 600 // Create the audioSource 601 //AudioSource audioSource = instance.gameObject.AddComponent<AudioSource>() as AudioSource; 602 Audio audio = new Audio(Audio.AudioType.UISound, clip, false, false, volume, 0f, 0f, null, onCompletelyPlayed); 603 604 // Add it to music list 605 UISoundsAudio.Add(audio.audioID, audio); 606 607 return audio.audioID; 608 } 609 610 #endregion 611 612 #region Stop Functions 613 614 /// <summary> 615 /// Stop all audio playing 616 /// </summary> 617 public static void StopAll() 618 { 619 StopAll(-1f); 620 } 621 622 /// <summary> 623 /// Stop all audio playing 624 /// </summary> 625 /// <param name="fadeOutSeconds"> How many seconds it needs for all music audio to fade out. It will override their own fade out seconds. If -1 is passed, all music will keep their own fade out seconds</param> 626 public static void StopAll(float fadeOutSeconds) 627 { 628 StopAllMusic(fadeOutSeconds); 629 StopAllSounds(); 630 StopAllUISounds(); 631 } 632 633 /// <summary> 634 /// Stop all music playing 635 /// </summary> 636 public static void StopAllMusic() 637 { 638 StopAllMusic(-1f); 639 } 640 641 /// <summary> 642 /// Stop all music playing 643 /// </summary> 644 /// <param name="fadeOutSeconds"> How many seconds it needs for all music audio to fade out. It will override their own fade out seconds. If -1 is passed, all music will keep their own fade out seconds</param> 645 public static void StopAllMusic(float fadeOutSeconds) 646 { 647 List<int> keys = new List<int>(musicAudio.Keys); 648 foreach (int key in keys) 649 { 650 Audio audio = musicAudio[key]; 651 if (fadeOutSeconds > 0) 652 { 653 audio.fadeOutSeconds = fadeOutSeconds; 654 } 655 audio.Stop(); 656 } 657 } 658 659 /// <summary> 660 /// Stop all sound fx playing 661 /// </summary> 662 public static void StopAllSounds() 663 { 664 List<int> keys = new List<int>(soundsAudio.Keys); 665 foreach (int key in keys) 666 { 667 Audio audio = soundsAudio[key]; 668 audio.Stop(); 669 } 670 } 671 672 /// <summary> 673 /// Stop all UI sound fx playing 674 /// </summary> 675 public static void StopAllUISounds() 676 { 677 List<int> keys = new List<int>(UISoundsAudio.Keys); 678 foreach (int key in keys) 679 { 680 Audio audio = UISoundsAudio[key]; 681 audio.Stop(); 682 } 683 } 684 685 #endregion 686 687 #region Pause Functions 688 689 /// <summary> 690 /// Pause all audio playing 691 /// </summary> 692 public static void PauseAll() 693 { 694 PauseAllMusic(); 695 PauseAllSounds(); 696 PauseAllUISounds(); 697 } 698 699 /// <summary> 700 /// Pause all music playing 701 /// </summary> 702 public static void PauseAllMusic() 703 { 704 List<int> keys = new List<int>(musicAudio.Keys); 705 foreach (int key in keys) 706 { 707 Audio audio = musicAudio[key]; 708 audio.Pause(); 709 } 710 } 711 712 /// <summary> 713 /// Pause all sound fx playing 714 /// </summary> 715 public static void PauseAllSounds() 716 { 717 List<int> keys = new List<int>(soundsAudio.Keys); 718 foreach (int key in keys) 719 { 720 Audio audio = soundsAudio[key]; 721 audio.Pause(); 722 } 723 } 724 725 /// <summary> 726 /// Pause all UI sound fx playing 727 /// </summary> 728 public static void PauseAllUISounds() 729 { 730 List<int> keys = new List<int>(UISoundsAudio.Keys); 731 foreach (int key in keys) 732 { 733 Audio audio = UISoundsAudio[key]; 734 audio.Pause(); 735 } 736 } 737 738 #endregion 739 740 #region Resume Functions 741 742 /// <summary> 743 /// Resume all audio playing 744 /// </summary> 745 public static void ResumeAll() 746 { 747 ResumeAllMusic(); 748 ResumeAllSounds(); 749 ResumeAllUISounds(); 750 } 751 752 /// <summary> 753 /// Resume all music playing 754 /// </summary> 755 public static void ResumeAllMusic() 756 { 757 List<int> keys = new List<int>(musicAudio.Keys); 758 foreach (int key in keys) 759 { 760 Audio audio = musicAudio[key]; 761 audio.Resume(); 762 } 763 } 764 765 /// <summary> 766 /// Resume all sound fx playing 767 /// </summary> 768 public static void ResumeAllSounds() 769 { 770 List<int> keys = new List<int>(soundsAudio.Keys); 771 foreach (int key in keys) 772 { 773 Audio audio = soundsAudio[key]; 774 audio.Resume(); 775 } 776 } 777 778 /// <summary> 779 /// Resume all UI sound fx playing 780 /// </summary> 781 public static void ResumeAllUISounds() 782 { 783 List<int> keys = new List<int>(UISoundsAudio.Keys); 784 foreach (int key in keys) 785 { 786 Audio audio = UISoundsAudio[key]; 787 audio.Resume(); 788 } 789 } 790 791 #endregion 792 } 793 794 public class Audio 795 { 796 private static int audioCounter = 0; 797 private float volume; 798 private float targetVolume; 799 private float initTargetVolume; 800 private float tempFadeSeconds; 801 private float fadeInterpolater; 802 private float onFadeStartVolume; 803 private AudioType audioType; 804 private AudioClip initClip; 805 private Transform sourceTransform; 806 807 /// <summary> 808 /// The ID of the Audio 809 /// </summary> 810 public int audioID { get; private set; } 811 812 /// <summary> 813 /// The audio source that is responsible for this audio 814 /// </summary> 815 public AudioSource audioSource { get; private set; } 816 817 /// <summary> 818 /// Audio clip to play/is playing 819 /// </summary> 820 public AudioClip clip 821 { 822 get 823 { 824 return audioSource == null ? initClip : audioSource.clip; 825 } 826 } 827 828 /// <summary> 829 /// Whether the audio will be lopped 830 /// </summary> 831 public bool loop { get; set; } 832 833 /// <summary> 834 /// Whether the audio persists in between scene changes 835 /// </summary> 836 public bool persist { get; set; } 837 838 /// <summary> 839 /// How many seconds it needs for the audio to fade in/ reach target volume (if higher than current) 840 /// </summary> 841 public float fadeInSeconds { get; set; } 842 843 /// <summary> 844 /// How many seconds it needs for the audio to fade out/ reach target volume (if lower than current) 845 /// </summary> 846 public float fadeOutSeconds { get; set; } 847 848 /// <summary> 849 /// Whether the audio is currently playing 850 /// </summary> 851 public bool playing { get; set; } 852 853 /// <summary> 854 /// Whether the audio is paused 855 /// </summary> 856 public bool paused { get; private set; } 857 858 /// <summary> 859 /// Whether the audio is stopping 860 /// </summary> 861 public bool stopping { get; private set; } 862 863 /// <summary> 864 /// Whether the audio is created and updated at least once. 865 /// </summary> 866 public bool activated { get; private set; } 867 868 /// <summary> 869 /// The audio played completed. 870 /// </summary> 871 public Action<Audio> onComletelyPlayed; 872 873 public enum AudioType 874 { 875 Music, 876 Sound, 877 UISound 878 } 879 880 public Audio(AudioType audioType, AudioClip clip, bool loop, bool persist, float volume, float fadeInValue, 881 float fadeOutValue, Transform sourceTransform, Action<Audio> onComletelyPlayed) 882 { 883 if (sourceTransform == null) 884 { 885 this.sourceTransform = SoundManager.gameobject.transform; 886 } 887 else 888 { 889 this.sourceTransform = sourceTransform; 890 } 891 892 this.audioID = audioCounter; 893 audioCounter++; 894 895 this.audioType = audioType; 896 this.initClip = clip; 897 this.loop = loop; 898 this.persist = persist; 899 this.targetVolume = volume; 900 this.initTargetVolume = volume; 901 this.tempFadeSeconds = -1; 902 this.volume = 0f; 903 this.fadeInSeconds = fadeInValue; 904 this.fadeOutSeconds = fadeOutValue; 905 this.onComletelyPlayed = onComletelyPlayed; 906 907 this.playing = false; 908 this.paused = false; 909 this.activated = false; 910 911 CreateAudiosource(clip, loop); 912 Play(); 913 } 914 915 void CreateAudiosource(AudioClip clip, bool loop) 916 { 917 audioSource = sourceTransform.gameObject.AddComponent<AudioSource>() as AudioSource; 918 919 audioSource.clip = clip; 920 audioSource.loop = loop; 921 audioSource.volume = 0f; 922 if (sourceTransform != SoundManager.gameobject.transform) 923 { 924 audioSource.spatialBlend = 1; 925 } 926 } 927 928 /// <summary> 929 /// Start playing audio clip from the beggining 930 /// </summary> 931 public void Play() 932 { 933 Play(initTargetVolume); 934 } 935 936 /// <summary> 937 /// Start playing audio clip from the beggining 938 /// </summary> 939 /// <param name="volume">The target volume</param> 940 public void Play(float volume) 941 { 942 if(audioSource == null) 943 { 944 CreateAudiosource(initClip, loop); 945 } 946 947 audioSource.Play(); 948 playing = true; 949 950 fadeInterpolater = 0f; 951 onFadeStartVolume = this.volume; 952 targetVolume = volume; 953 } 954 955 /// <summary> 956 /// Stop playing audio clip 957 /// </summary> 958 public void Stop() 959 { 960 fadeInterpolater = 0f; 961 onFadeStartVolume = volume; 962 targetVolume = 0f; 963 964 stopping = true; 965 } 966 967 /// <summary> 968 /// Pause playing audio clip 969 /// </summary> 970 public void Pause() 971 { 972 audioSource.Pause(); 973 paused = true; 974 } 975 976 /// <summary> 977 /// Resume playing audio clip 978 /// </summary> 979 public void Resume() 980 { 981 audioSource.UnPause(); 982 paused = false; 983 } 984 985 /// <summary> 986 /// Sets the audio volume 987 /// </summary> 988 /// <param name="volume">The target volume</param> 989 public void SetVolume(float volume) 990 { 991 if(volume > targetVolume) 992 { 993 SetVolume(volume, fadeOutSeconds); 994 } 995 else 996 { 997 SetVolume(volume, fadeInSeconds); 998 } 999 } 1000 1001 /// <summary> 1002 /// Sets the audio volume 1003 /// </summary> 1004 /// <param name="volume">The target volume</param> 1005 /// <param name="fadeSeconds">How many seconds it needs for the audio to fade in/out to reach target volume. If passed, it will override the Audio's fade in/out seconds, but only for this transition</param> 1006 public void SetVolume(float volume, float fadeSeconds) 1007 { 1008 SetVolume(volume, fadeSeconds, this.volume); 1009 } 1010 1011 /// <summary> 1012 /// Sets the audio volume 1013 /// </summary> 1014 /// <param name="volume">The target volume</param> 1015 /// <param name="fadeSeconds">How many seconds it needs for the audio to fade in/out to reach target volume. If passed, it will override the Audio's fade in/out seconds, but only for this transition</param> 1016 /// <param name="startVolume">Immediately set the volume to this value before beginning the fade. If not passed, the Audio will start fading from the current volume towards the target volume</param> 1017 public void SetVolume(float volume, float fadeSeconds, float startVolume) 1018 { 1019 targetVolume = Mathf.Clamp01(volume); 1020 fadeInterpolater = 0; 1021 onFadeStartVolume = startVolume; 1022 tempFadeSeconds = fadeSeconds; 1023 } 1024 1025 /// <summary> 1026 /// Sets the Audio 3D max distance 1027 /// </summary> 1028 /// <param name="max">the max distance</param> 1029 public void Set3DMaxDistance(float max) 1030 { 1031 audioSource.maxDistance = max; 1032 } 1033 1034 /// <summary> 1035 /// Sets the Audio 3D min distance 1036 /// </summary> 1037 /// <param name="max">the min distance</param> 1038 public void Set3DMinDistance(float min) 1039 { 1040 audioSource.minDistance = min; 1041 } 1042 1043 /// <summary> 1044 /// Sets the Audio 3D distances 1045 /// </summary> 1046 /// <param name="min">the min distance</param> 1047 /// <param name="max">the max distance</param> 1048 public void Set3DDistances(float min, float max) 1049 { 1050 Set3DMinDistance(min); 1051 Set3DMaxDistance(max); 1052 } 1053 1054 public void Update() 1055 { 1056 if(audioSource == null) 1057 { 1058 return; 1059 } 1060 1061 activated = true; 1062 1063 if (volume != targetVolume) 1064 { 1065 float fadeValue; 1066 fadeInterpolater += Time.deltaTime; 1067 if (volume > targetVolume) 1068 { 1069 fadeValue = tempFadeSeconds != -1? tempFadeSeconds: fadeOutSeconds; 1070 } 1071 else 1072 { 1073 fadeValue = tempFadeSeconds != -1 ? tempFadeSeconds : fadeInSeconds; 1074 } 1075 1076 volume = Mathf.Lerp(onFadeStartVolume, targetVolume, fadeInterpolater / fadeValue); 1077 } 1078 else if(tempFadeSeconds != -1) 1079 { 1080 tempFadeSeconds = -1; 1081 } 1082 1083 switch (audioType) 1084 { 1085 case AudioType.Music: 1086 { 1087 audioSource.volume = volume * SoundManager.globalMusicVolume * SoundManager.globalVolume; 1088 break; 1089 } 1090 case AudioType.Sound: 1091 { 1092 audioSource.volume = volume * SoundManager.globalSoundsVolume * SoundManager.globalVolume; 1093 break; 1094 } 1095 case AudioType.UISound: 1096 { 1097 audioSource.volume = volume * SoundManager.globalUISoundsVolume * SoundManager.globalVolume; 1098 break; 1099 } 1100 } 1101 1102 if (volume == 0f && stopping) 1103 { 1104 audioSource.Stop(); 1105 stopping = false; 1106 playing = false; 1107 paused = false; 1108 } 1109 1110 // Update playing status 1111 if (audioSource.isPlaying != playing) 1112 { 1113 playing = audioSource.isPlaying; 1114 } 1115 } 1116 } 1117 }
ZSAudioController
1 using System; 2 using System.Collections.Generic; 3 using UnityEngine; 4 using ZStudio.SoundManager; 5 using Object = UnityEngine.Object; 6 7 public class ZSAudioControllerStub : MonoBehaviour 8 { 9 public List<AudioSett> audioSetts; 10 public AudioGlobalSett audioGlobalSett = new AudioGlobalSett(); 11 12 public AudioSett GetAudio(string an) 13 { 14 return audioSetts.Find(aud => aud.name == an); 15 } 16 } 17 18 [Serializable] 19 public class AudioGlobalSett 20 { 21 public float uiVolome; 22 public float fxVolume; 23 public float soundVolume; 24 25 public bool ignoreDuplicateMusic; 26 public bool ignoreDuplicateSounds; 27 public bool ignoreDuplicateUISounds; 28 29 public AudioGlobalSett() 30 { 31 uiVolome = 1; 32 fxVolume = 1; 33 soundVolume = 1; 34 35 ignoreDuplicateMusic = false; 36 ignoreDuplicateSounds = false; 37 ignoreDuplicateUISounds = false; 38 } 39 } 40 41 [Serializable] 42 public class AudioSett 43 { 44 public Audio.AudioType type; 45 46 public string name; 47 public AudioClip clip; 48 public float volume; 49 public bool loop; 50 public bool persist; 51 public float fadeInSec; 52 public float fadeOutSec; 53 54 public AudioSett() 55 { 56 volume = 1; 57 loop = false; 58 persist = false; 59 fadeInSec = 0; 60 fadeOutSec = 0; 61 } 62 } 63 64 public class ZSAudioController : Singleton<ZSAudioController> 65 { 66 private static ZSAudioControllerStub stub; 67 68 public enum RangeType 69 { 70 Music, 71 Sound, 72 UISound, 73 All 74 } 75 76 private static void InitStub() 77 { 78 var stubs = Object.FindObjectsOfType<ZSAudioControllerStub>(); 79 if (stubs.Length > 1) 80 { 81 Debug.LogWarning("More than one ZSAudioControllerStub in scene."); 82 foreach (var st in stubs) 83 { 84 Object.DestroyObject(st.gameObject); 85 } 86 } 87 else if (stubs.Length == 1) stub = stubs[0]; 88 89 if (stub == null) 90 stub = Object.Instantiate(Resources.Load<ZSAudioControllerStub>("AudioController")); 91 Object.DontDestroyOnLoad(stub.gameObject); 92 } 93 94 public static void Play(string audid, Action<Audio> onPlayed = null) 95 { 96 if (stub == null) InitStub(); 97 98 AudioSett _ass = stub.GetAudio(audid); 99 if (_ass != null) 100 { 101 if (_ass.type == Audio.AudioType.Music) 102 { 103 SoundManager.PlayMusic(_ass.clip, _ass.volume, _ass.loop, _ass.persist, _ass.fadeInSec, 104 _ass.fadeOutSec, onPlayed); 105 } 106 else if (_ass.type == Audio.AudioType.Sound) 107 { 108 SoundManager.PlaySound(_ass.clip, _ass.volume, _ass.loop, null, onPlayed); 109 } 110 else if (_ass.type == Audio.AudioType.UISound) 111 { 112 SoundManager.PlayUISound(_ass.clip, _ass.volume, onPlayed); 113 } 114 } 115 } 116 117 public static void Stop(string audid) 118 { 119 if (stub == null) InitStub(); 120 121 AudioSett _ass = stub.GetAudio(audid); 122 if (_ass != null) 123 { 124 Audio _audio = SoundManager.GetAudio(_ass.clip); 125 if (_audio != null) _audio.Stop(); 126 } 127 } 128 129 public static void Pause(string audid) 130 { 131 if (stub == null) InitStub(); 132 133 AudioSett _ass = stub.GetAudio(audid); 134 if (_ass != null) 135 { 136 Audio _audio = SoundManager.GetAudio(_ass.clip); 137 if (_audio != null) _audio.Pause(); 138 } 139 } 140 141 public static void Resume(string audid) 142 { 143 if (stub == null) InitStub(); 144 145 AudioSett _ass = stub.GetAudio(audid); 146 if (_ass != null) 147 { 148 Audio _audio = SoundManager.GetAudio(_ass.clip); 149 if (_audio != null) _audio.Resume(); 150 } 151 } 152 153 public static void Stop(RangeType range) 154 { 155 if (range == RangeType.Music) SoundManager.StopAllMusic(); 156 if (range == RangeType.Sound) SoundManager.StopAllSounds(); 157 if (range == RangeType.UISound) SoundManager.StopAllUISounds(); 158 if (range == RangeType.All) SoundManager.StopAll(); 159 } 160 161 public static void Pause(RangeType range) 162 { 163 if (range == RangeType.Music) SoundManager.PauseAllMusic(); 164 if (range == RangeType.Sound) SoundManager.PauseAllSounds(); 165 if (range == RangeType.UISound) SoundManager.PauseAllUISounds(); 166 if (range == RangeType.All) SoundManager.PauseAll(); 167 } 168 169 public static void Resume(RangeType range) 170 { 171 if (range == RangeType.Music) SoundManager.ResumeAllMusic(); 172 if (range == RangeType.Sound) SoundManager.ResumeAllSounds(); 173 if (range == RangeType.UISound) SoundManager.ResumeAllUISounds(); 174 if (range == RangeType.All) SoundManager.ResumeAll(); 175 } 176 }
ZSAudioControllerEditor
1 using UnityEditor; 2 using UnityEngine; 3 using ZStudio.SoundManager; 4 5 [CustomEditor(typeof(ZSAudioControllerStub))] 6 [CanEditMultipleObjects] 7 public class ZSAudioControllerEditor : Editor 8 { 9 private SerializedProperty ass; 10 private SerializedProperty ags; 11 private Audio.AudioType audioType; 12 13 private bool showAudio = true; 14 private bool showGlobal = true; 15 private int deleteIndex = -1; 16 private int selectedIndex = 0; 17 18 private GUIStyle labelStyle; 19 private GUIStyle foldoutStyle; 20 21 // 当对象已启用并处于活动状态时调用此函数 22 private void OnEnable() 23 { 24 ass = serializedObject.FindProperty("audioSetts"); 25 ags = serializedObject.FindProperty("audioGlobalSett"); 26 } 27 28 private void SetStyles() 29 { 30 foldoutStyle = new GUIStyle(EditorStyles.foldout); 31 Color color = new Color(0, 0, 0.2f); 32 foldoutStyle.onNormal.background = EditorStyles.boldLabel.onNormal.background; 33 foldoutStyle.onFocused.background = EditorStyles.boldLabel.onNormal.background; 34 foldoutStyle.onActive.background = EditorStyles.boldLabel.onNormal.background; 35 foldoutStyle.onHover.background = EditorStyles.boldLabel.onNormal.background; 36 foldoutStyle.normal.textColor = color; 37 foldoutStyle.focused.textColor = color; 38 foldoutStyle.active.textColor = color; 39 foldoutStyle.hover.textColor = color; 40 foldoutStyle.fixedWidth = 1000f; 41 42 labelStyle = new GUIStyle(EditorStyles.foldout); 43 color = new Color(0, 0, 0.5f); 44 labelStyle.onNormal.background = EditorStyles.boldLabel.onNormal.background; 45 labelStyle.onFocused.background = EditorStyles.boldLabel.onNormal.background; 46 labelStyle.onActive.background = EditorStyles.boldLabel.onNormal.background; 47 labelStyle.onHover.background = EditorStyles.boldLabel.onNormal.background; 48 labelStyle.font = EditorStyles.boldFont; 49 labelStyle.normal.textColor = color; 50 labelStyle.focused.textColor = color; 51 labelStyle.active.textColor = color; 52 labelStyle.hover.textColor = color; 53 labelStyle.fixedWidth = 1000f; 54 } 55 56 public override void OnInspectorGUI() 57 { 58 SetStyles(); 59 serializedObject.Update(); 60 61 // 全局设定 62 GlobalSetting(); 63 64 //GUILayout.Label("添加/删除音乐", foldoutStyle); 65 EditorGUILayout.Foldout(true, "添加音乐", foldoutStyle); 66 GUILayout.BeginVertical("Box"); 67 GUILayout.BeginHorizontal("Box"); 68 audioType = (Audio.AudioType) EditorGUILayout.EnumPopup(audioType, GUILayout.MinWidth(65)); 69 GUILayout.Label("", GUILayout.MaxWidth(1000)); 70 GUILayout.EndHorizontal(); 71 GUILayout.BeginHorizontal("box"); 72 if (GUILayout.Button("Add", GUILayout.Width(50))) 73 { 74 AddAudio(audioType); 75 } 76 GUILayout.Label("", GUILayout.MaxWidth(1000)); 77 if (GUILayout.Button("ClearAll", GUILayout.MinWidth(80))) 78 { 79 ass.ClearArray(); 80 } 81 GUILayout.EndHorizontal(); 82 GUILayout.EndVertical(); 83 GUILayout.Space(10); 84 85 // 移除项 86 if (deleteIndex > -1) 87 { 88 RemoveAudio(deleteIndex); 89 deleteIndex = -1; 90 } 91 92 showAudio = EditorGUILayout.Foldout(showAudio, new GUIContent("音乐列表"), foldoutStyle); 93 if (showAudio) 94 { 95 PopupAudio(); 96 if (ass.arraySize > selectedIndex) 97 { 98 var audio = ass.GetArrayElementAtIndex(selectedIndex); 99 DrawAudio(audio, selectedIndex); 100 } 101 } 102 103 serializedObject.ApplyModifiedProperties(); 104 } 105 106 private void GlobalSetting() 107 { 108 GUILayout.BeginVertical(); 109 showGlobal = EditorGUILayout.Foldout(showGlobal, "Global Settings", foldoutStyle); 110 if (showGlobal) 111 { 112 var uiv = ags.FindPropertyRelative("uiVolome"); 113 EditorGUILayout.Slider(uiv, 0, 1, "UI Volume:"); 114 var fxv = ags.FindPropertyRelative("fxVolume"); 115 EditorGUILayout.Slider(fxv, 0, 1, "Fx Volume:"); 116 var sdv = ags.FindPropertyRelative("soundVolume"); 117 EditorGUILayout.Slider(sdv, 0, 1, "Sound Volume:"); 118 GUILayout.EndVertical(); 119 } 120 } 121 122 private void PopupAudio() 123 { 124 string[] names = new string[ass.arraySize]; 125 for (int i = 0; i < ass.arraySize; i++) 126 { 127 SerializedProperty _ass = ass.GetArrayElementAtIndex(i); 128 string _name = _ass.FindPropertyRelative("name").stringValue; 129 names[i] = _name; 130 } 131 132 GUILayout.BeginHorizontal(new GUIStyle(EditorStyles.whiteBoldLabel)); 133 selectedIndex = EditorGUILayout.Popup("Audio:", selectedIndex, names); 134 GUILayout.EndHorizontal(); 135 } 136 137 private void DrawAudio(SerializedProperty audio, int index) 138 { 139 GUILayout.BeginVertical("Box"); 140 141 GUILayout.BeginHorizontal(); 142 EditorGUILayout.LabelField("Type:", GUILayout.MaxWidth(40)); 143 SerializedProperty _type = audio.FindPropertyRelative("type"); 144 EditorGUILayout.PropertyField(_type, new GUIContent(""), GUILayout.MaxWidth(200)); 145 GUILayout.Label("", GUILayout.MaxWidth(1000)); 146 if (GUILayout.Button("-", GUILayout.MaxWidth(25))) 147 { 148 deleteIndex = index; 149 } 150 GUILayout.EndHorizontal(); 151 152 SerializedProperty _clip = audio.FindPropertyRelative("clip"); 153 EditorGUILayout.PropertyField(_clip, new GUIContent("Audio Clip:")); 154 SerializedProperty _name = audio.FindPropertyRelative("name"); 155 EditorGUILayout.PropertyField(_name, new GUIContent("Audio Name:")); 156 SerializedProperty _volume = audio.FindPropertyRelative("volume"); 157 EditorGUILayout.Slider(_volume, 0, 1, "Volume:"); 158 SerializedProperty _loop = audio.FindPropertyRelative("loop"); 159 EditorGUILayout.PropertyField(_loop, new GUIContent("Loop:")); 160 SerializedProperty _persist = audio.FindPropertyRelative("persist"); 161 EditorGUILayout.PropertyField(_persist, new GUIContent("Persist:")); 162 GUILayout.BeginHorizontal(); 163 SerializedProperty _fadeInSec = audio.FindPropertyRelative("fadeInSec"); 164 EditorGUILayout.PropertyField(_fadeInSec, new GUIContent("Fade-In:")); 165 GUILayout.Label("Sec"); 166 GUILayout.EndHorizontal(); 167 GUILayout.BeginHorizontal(); 168 SerializedProperty _fadeOutSec = audio.FindPropertyRelative("fadeOutSec"); 169 EditorGUILayout.PropertyField(_fadeOutSec, new GUIContent("Fade-Out:")); 170 GUILayout.Label("Sec"); 171 GUILayout.EndHorizontal(); 172 173 GUILayout.EndVertical(); 174 } 175 176 private void AddAudio(Audio.AudioType type) 177 { 178 AudioClip[] clips = GetSelectedAudioClips(); 179 for (int i = 0; i < clips.Length; i++) 180 { 181 ass.arraySize += 1; 182 var _audio = ass.GetArrayElementAtIndex(ass.arraySize - 1); 183 _audio.FindPropertyRelative("clip").objectReferenceValue = clips[i]; 184 _audio.FindPropertyRelative("name").stringValue = clips[i].name; 185 _audio.FindPropertyRelative("type").enumValueIndex = (int)type; 186 _audio.FindPropertyRelative("volume").floatValue = 1; 187 _audio.FindPropertyRelative("loop").boolValue = false; 188 _audio.FindPropertyRelative("persist").boolValue = false; 189 _audio.FindPropertyRelative("fadeInSec").floatValue = 0; 190 _audio.FindPropertyRelative("fadeOutSec").floatValue = 0; 191 } 192 serializedObject.ApplyModifiedProperties(); 193 } 194 195 private void RemoveAudio(int index) 196 { 197 if (index >= ass.arraySize || index < 0) 198 { 199 Debug.LogWarning("invalid index in DeleteArrayElement: " + index); 200 } 201 else 202 { 203 ass.DeleteArrayElementAtIndex(index); 204 // 最后一个元素被删除 205 if (selectedIndex >= ass.arraySize - 1) 206 { 207 selectedIndex -= 1; 208 if (selectedIndex < 0) selectedIndex = 0; 209 } 210 } 211 } 212 213 // 获取选中的音乐或者文件夹下面的音乐 214 private AudioClip[] GetSelectedAudioClips() 215 { 216 var filtered = Selection.GetFiltered<AudioClip>(SelectionMode.DeepAssets); 217 return filtered; 218 } 219 }
- 测试播放
1 // TODEBUG 测试声音播放 2 ZSAudioController.Play("0");
添加音乐只需要在资源视图中选中音乐或者音乐文件夹,点击Add.