音效模塊

来源:https://www.cnblogs.com/programmingAdorableNew/archive/2019/02/01/10344811.html
-Advertisement-
Play Games

音效系統 1.個人思路 1.情景假設 一天,小明想聽歌。於是,他拿起手機,找到音樂播放軟體,選擇歌曲,按下播放鍵,聽到了想聽的歌 2.過程分析 1 小明想聽歌 聽歌的對象,歌曲信息接收者 2 打開音樂播放軟體 播放音樂的對象,音效源 3 選擇歌曲 選擇的數據,音效資源 3.實現思路 AudioLis ...


音效系統

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

     }
}`

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、ViewData 1、ViewData派生自ViewDataDictionary,所以它具有字典的屬性,例如:ContainsKey 、Add 、Remove 和 Clear ; 2、字典鍵值是字元串類型,所以可以帶空格,例如ViewData["a b"]; 3、在視圖中,只有string類型的 ...
  • Newtonsoft.Json Newtonsoft.Json 是.Net平臺操作Json的工具,他的介紹就不多說了,筆者最近在弄介面,需要操作Json。 以某個雲計算平臺的Token為例,邊操作邊講解。 Json 轉為 Model 將 Model 轉為 Json 將 LINQ 轉為 JSON Li ...
  • .net core已經出來很長一段時間了,沒有很好的學習過,現在工作不那麼忙了,參考官方文檔,在這裡記錄自己的學習過程! ASP.NET Core 是一個跨平臺的高性能開源框架,用於生成基於雲且連接 Internet 的新式應用程式。 使用ASP.NET Core,可以:創建 Web 應用程式和服務 ...
  • asp.net core webapi/website+Azure DevOps+GitHub+Docker ...
  • EFCore中的約定簡單來說就是規則,CodeFirst基於模型的約定來映射表結構。除此之外還有Fluent API、Data Annotations(數據註釋) 可以幫助我們進一步配置模型。 按照這三者的優先順序高低排序分別是:Fluent API、Data Annotations(數據註釋)、約定 ...
  • 配置資料庫表首碼 "ABP踩坑記錄 目錄" 本篇其實和ABP關係並不大,主要是EF Core的一些應用 . 。 起因 支持資料庫表首碼應該是很多應用中比較常見的功能,而在ABP中並沒直接提供這一功能,所以在我們的應用中,我們轉而藉助EF Core的配置來實現資料庫表首碼的配置。 解決方案 這裡我結合 ...
  • 介紹 新年之際,給大家介紹個我自己開發的ORM類庫Insql。TA是一個輕量級的.NET ORM類庫 . 對象映射基於Dapper , Sql配置靈感來自於Mybatis。簡單優雅性能是TA的追求。 "github" | "gitee" 閑聊 以下可跳過 : ) 自己為什麼會開發Insql? 1. ...
  • 之前獲取上傳文件都是使用Request.Form.Files獲取,直到這次改成定義形參 IFormFile時才遇到這個問題。 不知道這是不是微軟的一個bug? 解決方案有兩種 方案一:去除[ApiController]這個Attribute 方案二:在[FromForm]里添加Name屬性:[Fro ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...