音效模块

音效系统

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);

     }
}`
posted @ 2019-02-01 17:11 CDCDDCDC 阅读(...) 评论(...) 编辑 收藏