zoukankan      html  css  js  c++  java
  • 音效模块

    音效系统

    1.个人思路

    • 1.情景假设

    一天,小明想听歌。于是,他拿起手机,找到音乐播放软件,选择歌曲,按下播放键,听到了想听的歌

    • 2.过程分析

    1 小明想听歌 -> 听歌的对象,歌曲信息接收者

    2 打开音乐播放软件 -> 播放音乐的对象,音效源

    3 选择歌曲 -> 选择的数据,音效资源

    • 3.实现思路

    AudioListener: 音效的监听者

    AudioSources:音频控制器

    AudioClip:音频文件

    2.代码实现

    2.1 简易播放器

        `using UnityEngine;
    
    // 添加音效源
    [RequireComponent(typeof(AudioSource))]
    public class AudioManagerA : MonoBehaviour{
    
     	public AudioClip AudioClip;
    	private AudioSource _audioSource;
    
    	private void Start()
    	 {
        	_audioSource = GetComponent<AudioSource>();
    	 }
    
    	// 播放音效
    	public void PlayAudio(float volume = 1.0f, bool isLoop = false)
    	{
       		_audioSource.clip = AudioClip;
        	_audioSource.volume = volume;
        	_audioSource.loop = isLoop;
       		_audioSource.Play();
       		Debug.LogFormat("播放音效: {0}", AudioClip.name);
    	}
    }`
    
    `using UnityEngine;
    
    public class TestA : MonoBehaviour {
    
    public bool IsPlayAudio;
    
    void Start () {
        gameObject.AddComponent<AudioManagerA>();
        // 选择播放的音效
        gameObject.GetComponent<AudioManagerA>().AudioClip = Resources.Load<AudioClip>("Audio/BackgroundMusic/BgMusic");
    }
    
    void Update () {
        if (IsPlayAudio)
        {
            IsPlayAudio = false;
            gameObject.GetComponent<AudioManagerA>().PlayAudio();
        }
    }
    }`
    

    2.2 如何方便的选择音效文件

     `     using System;
    using System.Collections.Generic;
    using UnityEngine;
    
    public interface IUploadAudio
    {
    	// 加载音效资源
    	AudioClip GetAudioClip(string audioName);
    }
    
    [RequireComponent(typeof(AudioSource))]
    public class AudioManagerB : MonoBehaviour, IUploadAudio {
    
    // 保存已经加载过的音效
    private Dictionary<string, AudioClip> _audioDict;
    private AudioSource _audioSource;
    
    private void Start()
    {
        _audioDict = new Dictionary<string, AudioClip>();
        _audioSource = GetComponent<AudioSource>();
    }
    
    // 播放音效
    public void PlayAudio(string audioName, float volume = 1.0f, bool isLoop = false)
    {
        if (!_audioDict.ContainsKey(audioName))
        {
            _audioDict.Add(audioName, GetAudioClip(audioName));
        }
        _audioSource.clip = _audioDict[audioName];
        _audioSource.volume = volume;
        _audioSource.loop = isLoop;
        _audioSource.Play();
    }
    
    public AudioClip GetAudioClip(string audioName)
    {
        AudioClip audioClip = Resources.Load<AudioClip>(audioName);
        if (audioClip == null)
        {
            throw new Exception("没有找到相应的音效资源 请确认路径:" + audioName);
        }
        return audioClip;
    }
    }`
    

    `using UnityEngine;
    
    public class TestB : MonoBehaviour {
    
    public bool IsPlayAudio;
    public string AudioName;
    
    void Start()
    {
        AudioName = "Audio/BackgroundMusic/BgMusic";
        gameObject.AddComponent<AudioManagerB>();
    }
    
    void Update()
    {
        if (IsPlayAudio)
        {
            IsPlayAudio = false;
            gameObject.GetComponent<AudioManagerB>().PlayAudio(AudioName);
        }
    }
    }`
    

    2.2.1 使用一个音效路径管理类

    `public class AudioPath
    {
    
    	public const string BACKGROUND_MUSIC = "Audio/BackgroundMusic/BgMusic";
    	public const string BACKGROUND_MUSIC_B = "Audio/BackgroundMusic/BgMusicB";
    	public const string BACKGROUND_MUSIC_C = "Audio/BackgroundMusic/BgMusicC";
    	public const string BACKGROUND_MUSIC_D = "Audio/BackgroundMusic/BgMusicD";
    
    }`
    

    2.2.2 使用枚举组装路径

    `public class AudioType {
    
    public enum Dialogue
    {
    
    }
    
    public enum ScreenOnClick
    {
        // 点击正确
        Correct,
        // 点击错误
        Error,
    }
    
    public enum SpecialEffects
    {
    
    }
    
    public enum BackgroundMusic
    {
        // 背景音乐
        BgMusic,
    }
    
    public enum Other
    {
    
    }
    }`
    

    `using UnityEngine;
    
    public class TestB : MonoBehaviour {
    
    public bool IsPlayAudio;
    
    void Start()
    {
        gameObject.AddComponent<AudioManagerB>();
    }
    
    void Update()
    {
        if (IsPlayAudio)
        {
            IsPlayAudio = false;
            gameObject.GetComponent<AudioManagerB>().PlayAudio(AudioType.BackgroundMusic.BgMusic);
        }
    }
    }`
    

    `using System;
    using System.Collections.Generic;
    using UnityEngine;
    
    public interface IUploadAudio
    {
    // 加载音效资源
    AudioClip GetAudioClip(Enum audioName);
    }
    
    [RequireComponent(typeof(AudioSource))]
    public class AudioManagerB : MonoBehaviour, IUploadAudio
    {
    
    // 保存已经加载过的音效
    private Dictionary<Enum, AudioClip> _audioDict;
    private AudioSource _audioSource;
    private const string audioPath = "Audio/";
    
    private void Start()
    {
        _audioDict = new Dictionary<Enum, AudioClip>();
        _audioSource = GetComponent<AudioSource>();
    }
    
    // 播放音效
    public void PlayAudio(Enum audioName, float volume = 1.0f, bool isLoop = false)
    {
        if (!_audioDict.ContainsKey(audioName))
        {
            _audioDict.Add(audioName, GetAudioClip(audioName));
        }
        _audioSource.clip = _audioDict[audioName];
        _audioSource.volume = volume;
        _audioSource.loop = isLoop;
        _audioSource.Play();
    }
    
    public AudioClip GetAudioClip(Enum audioName)
    {
        string audioType = audioName.GetType().Name;
        AudioClip audioClip = Resources.Load<AudioClip>(audioPath + audioType + "/" + audioName);
        if (audioClip == null)
        {
            throw new Exception("没有找到相应的音效资源 请确认路径:" + audioName);
        }
        return audioClip;
    }
    }`
    

    2.3 考虑多个播放源

    2.3.1 接口设置

    `public interface IUploadAudioClip
    {
    // 加载音效资源
    AudioClip GetAudioClip(Enum audioName);
    }
    
    public interface IUploadAudioSource
    {
    // 加载音效播放源
    AudioSource GetAudioSource(string audioSourceName);
    }
    
    public interface IPlayAudio
    {
    // 播放音效
    void PlayAudio(Enum audioName, float volume, bool isLoop, string audioSourceName);
    // 停止播放的音效
    void StopAudio(string audioSourceName);
    }`
    

    2.3.2 播放源系统

    `
    public class UploadAudioSourceStrategy : IUploadAudioSource
    {
    // 播放的音频源
    private Dictionary<string, AudioSource> audioSourceDict;
    // 音效管理器
    private GameObject audioControl;
    private static int count;
    private readonly string currentAudioName;
    
    public UploadAudioSourceStrategy()
    {
        audioSourceDict = new Dictionary<string, AudioSource>(3);
        audioControl = new GameObject { name = "AudioModuleControl" };
    	Object.DontDestroyOnLoad(audioControl);
        audioControl.AddComponent<AudioListener>();
    }
    
    public AudioSource GetAudioSource(string audioSourceName)
    {
        if(audioSourceName.Equals(string.Empty))
        {
            return GetCurrentAudioSource();
        }
    
        if (audioSourceDict.ContainsKey(audioSourceName))
        {
            return audioSourceDict[audioSourceName];
        }
    
        return GetCurrentAudioSource(audioSourceName);
    }
    
    private AudioSource GetCurrentAudioSource()
    {
        foreach (var source in audioSourceDict)
        {
            if (!source.Value.isPlaying)
            {
                return source.Value;
            }
        }
        return GetCurrentAudioSource(currentAudioName + count++);
    }
    
    private AudioSource GetCurrentAudioSource(string audioSourceName)
    {
        audioSourceDict.Add(audioSourceName, audioControl.AddComponent<AudioSource>());
        return audioSourceDict[audioSourceName];
    }
    }`
    

    2.3.3 音效资源系统

    `public class UploadAudioClipStrategy : IUploadAudioClip
    {
    
    // 音效路径
    private readonly string audioPath;
    // 播放的音效
    private Dictionary<Enum, AudioClip> audioClipDict;
    
    public UploadAudioClipStrategy()
    {
        audioPath = "Audio/";
        audioClipDict = new Dictionary<Enum, AudioClip>();
    }
    
    public AudioClip GetAudioClip(Enum audioName)
    {
        if (audioClipDict.ContainsKey(audioName))
        {
            return audioClipDict[audioName];
        }
    
        AudioClip clip = Resources.Load<AudioClip>(AudioClipPath(audioName));
        audioClipDict.Add(audioName, clip);
    
        return audioClipDict[audioName];
    }
    
    private string AudioClipPath(Enum audioName)
    {
        string audioType = audioName.GetType().Name;
        return audioPath + audioType + "/" + audioName;
    }
    }
    

    `

    2.3.4 音效系统

    `
    public abstract class AudioManagerBase : IPlayAudio
    {
    public IUploadAudioSource UploadAudioSource { get; protected set; }
    public IUploadAudioClip UploadAudioClip { get; protected set; }
    
    protected AudioManagerBase() : this(new UploadAudioSourceStrategy(), new UploadAudioClipStrategy())
    {
    
    }
    
    protected AudioManagerBase(IUploadAudioSource uploadAudioSource, IUploadAudioClip uploadAudioClip)
    {
        UploadAudioSource = uploadAudioSource;
        UploadAudioClip = uploadAudioClip;
    }
    
    public void PlayAudio(Enum audioName, float volume, bool isLoop, string audioSourceName)
    {
        AudioClip clip = UploadAudioClip.GetAudioClip(audioName);
        AudioSource audioSource = UploadAudioSource.GetAudioSource(audioSourceName);
        audioSource.clip = clip;
        audioSource.volume = volume;
        audioSource.loop = isLoop;
        audioSource.Play();
    }
    
    public void StopAudio(string audioSourceName)
    {
        AudioSource audioSource = UploadAudioSource.GetAudioSource(audioSourceName);
        audioSource.loop = false;
        audioSource.Stop();
    }
    }`
    

    `
    public class AudioSourceManager : AudioManagerBase {
    
    public const string BgAudioName = "BgAudio";
    
    #region 播放音乐的调用方式
    public void PlayAudio(AudioType.Dialogue audioName, float volume = 1.0f, bool isLoop = false, string audioSourceName = "")
    {
        base.PlayAudio(audioName, volume, isLoop, audioSourceName);
    }
    
    public void PlayAudio(AudioType.ScreenOnClick audioName, float volume = 1.0f, bool isLoop = false, string audioSourceName = "")
    {
        base.PlayAudio(audioName, volume, isLoop, audioSourceName);
    }
    
    public void PlayAudio(AudioType.SpecialEffects audioName, float volume = 1.0f, bool isLoop = false, string audioSourceName = "")
    {
        base.PlayAudio(audioName, volume, isLoop, audioSourceName);
    }
    
    public void PlayAudio(AudioType.Other audioName, float volume = 1.0f, bool isLoop = false, string audioSourceName = "")
    {
        base.PlayAudio(audioName, volume, isLoop, audioSourceName);
    }
    
    public void PlayAudio(AudioType.BackgroundMusic audioName, string audioSourceName = BgAudioName, float volume = 1.0f, bool isLoop = true)
    {
        PlayAudio(audioName, volume, isLoop, audioSourceName);
    }
    
    #endregion
    
    }
    

    `


    2.3.5 播放测试

    `using UnityEngine;
    
    public class TestC : MonoBehaviour {
    
    private void Start()
    {
        AudioSourceManager audioSourceManager = new AudioSourceManager();
        audioSourceManager.PlayAudio(AudioType.BackgroundMusic.BgMusic);
    	audioSourceManager.PlayAudio(AudioType.ScreenOnClick.Correct);
        audioSourceManager.PlayAudio(AudioType.ScreenOnClick.Error);
    }
    }`
    

    2.4 常用方法扩展

    `public interface IUploadAudioSource
    {
       。。。
    // 停止选择的部分音效
    void StopGroupAudio(Func<string, bool> stopGroupAudio);
    }`
    
    `public class UploadAudioSourceStrategy : IUploadAudioSource{
    	。。。
    	public void StopGroupAudio(Func<string, bool> stopGroupAudio)
    	{
       		 foreach (var source in audioSourceDict)
        	{
           		 if (stopGroupAudio(source.Key))
            		{
               		 	source.Value.loop = false;
                		source.Value.Stop();
            		}
      		 }
        }
    }`
    
    `public abstract class AudioManagerBase : IPlayAudio{
    	 。。。
     	 public void Reset(Func<string, bool> stopGroupAudio)
    	 {
     	   UploadAudioSource.StopGroupAudio(stopGroupAudio);
    	  }
    
    	 public float PlayAudioTime(Enum audioName)
    	 {
       	 	 if (UploadAudioClip.GetAudioClip(audioName) == null)
        		{
           		 	Debug.Log("Error: " + "The music file could not be found");
            		return 0.0f;
        		}
       	 	return UploadAudioClip.GetAudioClip(audioName).length;
    	 }
    }`
    
    `public class AudioSourceManager : AudioManagerBase, ISingleton
    {
    	。。。
     	private AudioSourceManager() { }
    
    	public const string BgAudioName = "BgAudio"; }`
    
    `public class TestC : MonoBehaviour {
    
    	private void Start()
    	{
       		 SingletonManager.GetSingleton<AudioSourceManager>().PlayAudio(AudioType.BackgroundMusic.BgMusic);
        	 SingletonManager.GetSingleton<AudioSourceManager>().PlayAudio(AudioType.ScreenOnClick.Correct);
        	 SingletonManager.GetSingleton<AudioSourceManager>().PlayAudio(AudioType.ScreenOnClick.Error);
    
    	 }
    }`
  • 相关阅读:
    AI编辑SVG格式的相关问题
    HTML里的id等属性命名需要注意
    canvas绘图动画细节
    触控获取坐标判断滑动方向
    CSS3卡片旋转效果
    使用CURL下载远程文件保存到服务器
    微信JS-SDK应用DEMO
    布局转换:文档流->绝对定位
    ThinkPHP缓存微信公众号access_token
    JAVA JSP笔记
  • 原文地址:https://www.cnblogs.com/programmingAdorableNew/p/10344811.html
Copyright © 2011-2022 走看看