Unity实现高效的音效管理类的示例代码

 更新时间:2023年03月22日 10:28:47   作者:极客柒  
这篇文章主要为大家详细介绍了如何通过Unity实现高效的音效管理类,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的可以了解一下

效果

自动维护一个 AudioSource的池子

如果超过了池子的峰值 池子会生成一个新的AudioSource对象来进行扩容

  • 支持2D音效调用方式 public void PlaySound( string url, float volume = 1.0f, bool loop = false )
  • 支持2D音乐调用方式 public void PlayMusic( string url, float volume = 1.0f, bool loop = true )
  • 支持3D音效调用方式 public void PlaySoundAtPoint( string url, Vector3 position, float volume = 1f )

食用方式

更改这块的加载 用你们自己框架里的加载方式 或者 走 Resource.Load

源码

using ResourceFramework;
using System.Collections.Generic;
using UnityEngine;

public class AudioManager : SingleTon<AudioManager>
{

    Queue<AudioSource> freeAudioSources = new Queue<AudioSource>();
    List<AudioSource> activeAudioSources = new List<AudioSource>();
    Dictionary<string, List<AudioSource>> playingSources = new Dictionary<string, List<AudioSource>>();
    List<AudioSource> musicSources = new List<AudioSource>();
    List<AudioSource> soundSources = new List<AudioSource>();
    Dictionary<string, AudioClip> audioClips = new Dictionary<string, AudioClip>();

    Transform transform;
    public float soundVolume { private set; get; } = 1.0f;
    public float musicVolume { private set; get; } = 1.0f;
    public bool soundMute { private set; get; } = false;
    public bool musicMute { private set; get; } = false;

    /// <summary>
    /// 初始化 给音效节点们一个爸爸
    /// </summary>
    /// <param name="root"></param>
    public void Init( Transform root )
    {
        transform = root;
        LoadAudioClip();//默认音效加载
    }

    /// <summary>
    /// 加载本地音效到音效缓存池
    /// </summary>
    /// <param name="url"></param>
    public void LoadAudioClip( string url = "Assets/AssetBundle/Sounds" )
    {

        AudioClip[] clips = null;
        //#if UNITY_EDITOR
        //        var files = System.IO.Directory.GetFiles( url );
        //        var clipList = new List<AudioClip>();
        //        foreach ( var file in files )
        //        {
        //            var ac = UnityEditor.AssetDatabase.LoadAssetAtPath<AudioClip>( file );
        //            if ( null != ac )
        //            {
        //                clipList.Add( ac );
        //            }
        //        }
        //        clips = clipList.ToArray();

        //#else
        List<AudioClip> clipList = new List<AudioClip>();
        for ( int i = 0; i < AllSoundName.allSoundPath.Length; i++ )
        {
            clipList.Add( Loader.LoadAsset<AudioClip>( $"{url}/{AllSoundName.allSoundPath[ i ]}.mp3" ) );
        }
        clips = clipList.ToArray();

        //#endif




        foreach ( var clip in clips )
        {
            audioClips.Add( clip.name, clip );
        }
    }

    /// <summary>
    /// 缓存一个音效到池子里
    /// </summary>
    /// <param name="audioClip"></param>
    public void Cache( AudioClip audioClip )
    {
        if ( !audioClips.ContainsKey( audioClip.name ) )
        {
            audioClips.Add( audioClip.name, audioClip );
        }
    }

    /// <summary>
    /// 需要主动去调用这个更新检查  当然你也可以开一个定时器来检测
    /// </summary>
    public void OnUpdate()
    {
        for ( int i = 0; i < activeAudioSources.Count; i++ )
        {
            if ( !activeAudioSources[ i ].isPlaying )
            {
                var free = activeAudioSources[ i ];
                free.gameObject.SetActive( false );
                freeAudioSources.Enqueue( free );
                activeAudioSources.RemoveAt( i-- );

                soundSources.Remove( free );
                musicSources.Remove( free );
            }
        }
    }

    /// <summary>
    /// 设置 音效系统音量 0~1
    /// </summary>
    /// <param name="volume"></param>
    public void SetSoundSysVolume( float volume )
    {
        float newVolume = Mathf.Clamp( volume, 0, 1 );
        float scale = newVolume / soundVolume;
        soundVolume = newVolume;

        foreach ( var asource in soundSources )
        {
            asource.volume *= scale;
        }
    }
    /// <summary>
    /// 设置 音乐系统音量 0~1
    /// </summary>
    /// <param name="volume"></param>
    public void SetMusicSysVolume( float volume )
    {
        float newVolume = Mathf.Clamp( volume, 0, 1 );
        float scale = newVolume / musicVolume;
        musicVolume = newVolume;

        foreach ( var asource in musicSources )
        {
            asource.volume *= scale;
        }
    }

    /// <summary>
    /// 设置音效静音状态
    /// </summary>
    /// <param name="isMute"></param>
    public void SetSoundMuteState( bool isMute )
    {
        soundMute = isMute;
        foreach ( var asource in soundSources )
        {
            asource.mute = soundMute;
        }
    }

    /// <summary>
    /// 设置音乐静音状态
    /// </summary>
    /// <param name="isMute"></param>
    public void SetMusicMuteState( bool isMute )
    {
        musicMute = isMute;
        foreach ( var asource in musicSources )
        {
            asource.mute = musicMute;
        }
    }

    /// <summary>
    /// 播放音乐 默认循环播放
    /// </summary>
    /// <param name="url"></param>
    /// <param name="volume"></param>
    /// <param name="loop"></param>
    public void PlayMusic( string url, float volume = 1.0f, bool loop = true )
    {

        if ( freeAudioSources.Count == 0 )
        {
            GenAudioSouceNew();
        }
        var audioSource = freeAudioSources.Dequeue();
        activeAudioSources.Add( audioSource );
        Recoverd( url, audioSource );
        audioSource.gameObject.SetActive( true );
        audioSource.volume = volume * musicVolume;
        audioSource.mute = soundMute;
        audioSource.loop = loop;
        audioSource.spatialBlend = 0f;
        audioSource.clip = GetAudioClip( url );
        audioSource.Play();

        if ( soundSources.Contains( audioSource ) )
        {
            soundSources.Remove( audioSource );
        }
        if ( !musicSources.Contains( audioSource ) )
        {
            musicSources.Add( audioSource );
        }
    }

    /// <summary>
    /// 停掉所有url相关的音效
    /// 因为是可以同时存在多个相同url的音效的  它们都有自己的生命周期
    /// </summary>
    /// <param name="url"></param>
    public void StopMusic( string url )
    {
        if ( playingSources.ContainsKey( url ) )
        {
            playingSources[ url ].ForEach( s => s.Stop() );
            playingSources.Remove( url );
        }
    }

    /// <summary>
    /// 播放音效 默认单次播放
    /// </summary>
    /// <param name="url"></param>
    /// <param name="volume"></param>
    /// <param name="loop"></param>
    public void PlaySound( string url, float volume = 1.0f, bool loop = false )
    {
        if ( freeAudioSources.Count == 0 )
        {
            GenAudioSouceNew();
        }
        var audioSource = freeAudioSources.Dequeue();
        activeAudioSources.Add( audioSource );
        Recoverd( url, audioSource );
        audioSource.gameObject.SetActive( true );
        audioSource.volume = volume * soundVolume;
        audioSource.mute = soundMute;
        audioSource.loop = loop;
        audioSource.spatialBlend = 0f;
        audioSource.clip = GetAudioClip( url );
        audioSource.Play();


        if ( musicSources.Contains( audioSource ) )
        {
            musicSources.Remove( audioSource );
        }
        if ( !soundSources.Contains( audioSource ) )
        {
            soundSources.Add( audioSource );
        }
    }


    /// <summary>
    /// 3D世界播放一个音效  指定一个位置
    /// </summary>
    /// <param name="url"></param>
    /// <param name="position"></param>
    /// <param name="volume"></param>
    public void PlaySoundAtPoint( string url, Vector3 position, float volume = 1f )
    {
        if ( freeAudioSources.Count == 0 )
        {
            GenAudioSouceNew();
        }
        var audioSource = freeAudioSources.Dequeue();
        activeAudioSources.Add( audioSource );
        Recoverd( url, audioSource );
        audioSource.gameObject.transform.position = position;
        audioSource.gameObject.SetActive( true );
        audioSource.clip = GetAudioClip( url );
        audioSource.volume = volume * soundVolume;
        audioSource.mute = soundMute;
        audioSource.loop = false;
        audioSource.spatialBlend = 1f;
        audioSource.Play();
    }

    public void PlayClipAtPoint( AudioClip clip, Vector3 position, float volume = 1f )
    {
        foreach ( var item in audioClips )
        {
            if ( item.Value == clip )
            {
                PlaySoundAtPoint( item.Key, position, volume );
                break;
            }
        }
    }

    public AudioClip GetAudioClip( string url )
    {
        AudioClip clip = null;
        if ( audioClips.TryGetValue( url, out clip ) )
        {
            return clip;
        }
        return null;
    }

    private void GenAudioSouceNew()
    {
        var obj = new GameObject( $"AudioComponent_{( activeAudioSources.Count + freeAudioSources.Count )}" );
        obj.transform.SetParent( transform, true );
        var asource = obj.AddComponent<AudioSource>();
        asource.loop = false;
        asource.volume = 0;
        asource.playOnAwake = false;
        asource.mute = false;
        freeAudioSources.Enqueue( asource );
    }

    private void Recoverd( string url, AudioSource ac )
    {
        List<AudioSource> result = null;
        if ( !playingSources.TryGetValue( url, out result ) )
        {
            result = new List<AudioSource>();
            playingSources.Add( url, result );
        }
        result.Add( ac );
    }
}

以上就是Unity实现高效的音效管理类的示例代码的详细内容,更多关于Unity音效管理类的资料请关注脚本之家其它相关文章!

相关文章

  • C#获取任务栏显示进程的方法

    C#获取任务栏显示进程的方法

    这篇文章主要介绍了C#获取任务栏显示进程的方法,涉及C#针对进程操作的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-08-08
  • C#串口通信总是丢数据的原因及解决方案

    C#串口通信总是丢数据的原因及解决方案

    在上位机开发中,串口通信是一个非常常见的通信方式,尤其是在与嵌入式设备、PLC、传感器等硬件设备进行交互时,串口通信简单、直接且广泛应用,但它也有自己的局限性,那么,为什么你的C#串口通信总是丢数据?本文将深度分析串口通信丢数据的原因,并提供一些有效的解决方案
    2025-02-02
  • C#信号量用法简单示例

    C#信号量用法简单示例

    这篇文章主要介绍了C#信号量用法,结合简单C#控制台应用程序形式分析了信号量的功能、定义、调用、释放等操作技巧,需要的朋友可以参考下
    2016-07-07
  • C#编程调用Cards.dll实现图形化发牌功能示例

    C#编程调用Cards.dll实现图形化发牌功能示例

    这篇文章主要介绍了C#编程调用Cards.dll实现图形化发牌功能,结合实例形式分析了C#动态链接库调用及图形操作技巧,需要的朋友可以参考下
    2017-06-06
  • C# Path类---文件路径解读

    C# Path类---文件路径解读

    这篇文章主要介绍了C# Path类---文件路径,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • c# 如何更简单的使用Polly

    c# 如何更简单的使用Polly

    这篇文章主要介绍了c# 如何更简单的使用Polly,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下
    2021-03-03
  • C#11新特性使用案例详解

    C#11新特性使用案例详解

    这篇文章主要为大家介绍了C#11新特性的使用案例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • DevExpress实现GridControl删除所有行的方法

    DevExpress实现GridControl删除所有行的方法

    这篇文章主要介绍了DevExpress实现GridControl删除所有行的方法,对于C#初学者有一定的参考借鉴价值,需要的朋友可以参考下
    2014-08-08
  • C#实现查杀本地与远程进程的方法

    C#实现查杀本地与远程进程的方法

    这篇文章主要介绍了C#实现查杀本地与远程进程的方法,可实现针对特定进程的关闭操作,是C#进程操作的一个典型应用,需要的朋友可以参考下
    2014-12-12
  • .net使用Aspose.Words进行Word替换操作的实现代码

    .net使用Aspose.Words进行Word替换操作的实现代码

    之前在工作中,需要实现Word打印功能,并且插入图片。当时采取的方式则是使用书签进行操作。首先在word内插入书签,完成后,存为模板。程序加载该模板,找到书签,并在指定位置写入文字即可
    2013-05-05

最新评论