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#实现给Word每一页设置不同文字水印的方法详解

    C#实现给Word每一页设置不同文字水印的方法详解

    Word中设置水印时,可使用预设的文字或自定义文字设置为水印效果,但通常添加水印效果时,会对所有页面都设置成统一效果。本文以C# 代码为例,对Word每一页设置不同的文字水印效果作详细介绍,感兴趣的可以了解一下
    2022-07-07
  • C#中 paint()与Onpaint()的区别

    C#中 paint()与Onpaint()的区别

    paint是事件onpaint方法onpaint方法是调用paint事件的,用哪一个,效果是一样,就看那一个方便了内部是这样实现的:
    2013-04-04
  • WPF开发之实现一种三轴机械手控件

    WPF开发之实现一种三轴机械手控件

    这篇文章主要为大家详细介绍了如何利用WPF实现简单一种三轴机械手控件,文中的示例代码讲解详细,对我们学习或工作有一定帮助,感兴趣的小伙伴可以了解一下
    2023-01-01
  • C#编程获取资源文件中图片的方法

    C#编程获取资源文件中图片的方法

    这篇文章主要介绍了C#编程获取资源文件中图片的方法,涉及C#针对项目中资源文件操作的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-08-08
  • C#SuperSocket的搭建并配置启动总结

    C#SuperSocket的搭建并配置启动总结

    在本篇文章里我们给大家总结了关于C#SuperSocket的搭建并配置启动的相关内容,正在学习的朋友们跟着参考下。
    2019-05-05
  • C#几种截取字符串的方法小结

    C#几种截取字符串的方法小结

    C#几种截取字符串的方法小结,需要的朋友可以参考一下
    2013-04-04
  • C# 9 新特性——record的相关总结

    C# 9 新特性——record的相关总结

    这篇文章主要介绍了C# 9 新特性——record的相关总结,帮助大家更好的理解和学习使用c# 9的新特性,感兴趣的朋友可以了解下
    2021-02-02
  • C#实现windows form倒计时的方法

    C#实现windows form倒计时的方法

    这篇文章主要介绍了C#实现windows form倒计时的方法,涉及C#桌面程序设计中时间操作的技巧,非常具有实用价值,需要的朋友可以参考下
    2015-04-04
  • Unity色子的投掷和点数的获得详析

    Unity色子的投掷和点数的获得详析

    这篇文章主要给大家介绍了关于Unity色子的投掷和点数的获得的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-10-10
  • WinForm 自动完成控件实例代码简析

    WinForm 自动完成控件实例代码简析

    在Web的应用方面有js的插件实现自动完成(或叫智能提示)功能,但在WinForm窗体应用方面就没那么好了,接下来参考一下这个实例,看看有没有以外收获,感兴趣的朋友可以了解下啊,希望本文对你有帮助啊
    2013-01-01

最新评论