项目实训--Unity多人游戏开发(八、3D音效融合AudioMixer、统一的音频播放系统)

目标及介绍

目标:
实现一个

  1. 可复用集中管理音效
  2. 3D音效
  3. 音频clip播放不冲突
  4. 可以由制作的音量面板调节(AudioMixer)。

的音效系统。
(BGM无需3D音效)

如何制作音量面板同步控制AudioMixer这里不涉及,从csdn或b站都能找到一大片教学。

AudioSource有三个播放方法:

  1. Play()成员方法。
  2. PlayOneShot(clip等参数)成员方法。
  3. PlayClipAtPoint(clip,position),是静态方法。

遇到的问题

AudioSource组件设置中可以改为播放3D音效。
但是,
Play()不能同时播放多个clip,会产生冲突,不能指定位置。
PlayOneShot()能同时播放,但是不能指定位置。
PlayClipAtPoint是静态方法不能由AudioMixer控制。

目标第四点,想可以由AudioMixer调节,只能是确切的AudioSource组件,相应的只能用属于这个AudioSource的对象的成员方法。(目前知识储备是这样理解的,只有成员方法才能由对象的成员变量挂钩,于是无法使用PlayClipAtPoint静态方法)。

思路

针对1.,可以实现一个AudioManager的空物体并且挂在上AudioManager.cs脚本,所有代码和Clip在AudioManager集中管理。并且AudioManager实现单例模式,多场景可用(DontDestroyOnLoad)。需要时可以直接通过instance单例对象调用相应的方法进行播放。
其实如果不集中管理,在每个音源物体上挂一个AudioSource组件就解决问题了。但是这样对于后续的AudioMixer调整也确实不友好。

针对2.,起初从网上查找教程以为只有PlayClipAtPoint(唯一可以指认音效位置的方法)能播放3D效果。着实不好办了。
后来发现Play和PlayOnShot也可以实现3D音效,本质上是在AudioSource组件把
在这里插入图片描述
SpatialBlend改为3D就可以实现3D效果了。
然后其他具体的调整可以在3D Sound Settings里进行设置。

针对3.,播放不冲突,那么只能使用PlayOnShot或者PlayClipAtPoint(不满足可控音量的限制)。

针对4.,确保用成员方法,并且有一个AudioSource组件。

一个解决方案

上面每一条限制取一个交集,那么其中一个解决方法是:
GameObject.Instantiate(prefab)prefab是一个预制体(AudioSpot),上面挂载一个AudioSource组件并且设置为3D音效,并且在其上挂一个AudioSpot.cs,在一定时长之后自动摧毁(放置占用过多硬件资源)。这样Play和PlayOnShot都可以用,具体用哪个看代码写法。

在AudioManager里,哪里需要播放3D音效,则在对应地方实例化一个AudioSpot,然后调用其方法进行播放。同时此音效可以受AudioMixer控制。

这么一来就可以实现这四点要求。

统一的音效管理系统(关键代码)

AudioManager.cs

单例类,一个游戏场景一个即可
	public static AudioManager instance;
    
    public AudioClip ShootClip;
    public AudioClip RelodClip;
    public AudioClip thunderClip;

	//协调好每个场景中的设置面板---emm有其他更好的实现方式,直接看这里挺突兀,可以不管
	private void Start()
    {
        if (Launcher.instance.bgmVolume == -100 && Launcher.instance.soundVolume == -100)
        {
            //audioMixer.GetFloat();
            Launcher.instance.bgmVolume = 10;
            Launcher.instance.soundVolume = 10;
        }
        else
        {
            audioMixer.SetFloat("bgm1", Launcher.instance.bgmVolume);
            audioMixer.SetFloat("eff1", Launcher.instance.soundVolume);
            //UI
            soundSettingsPanel.transform.GetChild(1).GetComponent<Slider>().value = Launcher.instance.bgmVolume;
            soundSettingsPanel.transform.GetChild(2).GetComponent<Slider>().value = Launcher.instance.soundVolume;
        }
    }
	
	//一个3d音效例子,
	//别的类只需要调用AudioManager.instance.Thunder(position)
	//即可在position那里释放一个打雷音效。
	public void Thunder(Vector3 pos)
    {
        PlaySound(thunderClip, pos);
    }

	private void PlaySound(AudioClip clip,Vector3 pos)//在指定地方播放指定3d音效
    {
        //AudioSource.PlayClipAtPoint(clip, pos, sfxVoluePercent * masterVolumePercent);
        AudioSpot spot = GameObject.Instantiate(audioSpot, pos, Quaternion.identity);
        spot.PlayClip(clip);
        /*
        audioSource2D.clip = ShootClip;
        audioSource2D.Play();//Pasuse//stop不能同时播放多个,重复播放会打断上一次播放
        audioSource2D.PlayOneShot(RelodClip);//不是3D音效
        //static 
        AudioSource.PlayClipAtPoint(ShootClip, pos);//是3D音效但是静态方法不受AudioMixer控制
        */
    }
    //播放2d音效
    private void PlaySound2D(AudioClip clip, float volumeScale = 1)
    {
        audioSource2D.PlayOneShot(clip, volumeScale);
    }
    

AudioSpot预制体与AudioSpot.cs

预制体上挂着AudioSpot脚本,添加一个AudioSource组件,并设其为3D模式。
AudioSpot.cs

public class AudioSpot : MonoBehaviour
{
    public void PlayClip(AudioClip clip)
    {
        GetComponent<AudioSource>().PlayOneShot(clip);
        Invoke("DestroyThis", clip.length);
    }

    public void DestroyThis()
    {
        Destroy(gameObject);
    }
}

总结

完成了3D音效同时受AudioMixer控制的音效系统。

不过当游戏中突发很多音效的时候会不会卡呢?毕竟在瞬时要实例化很多个预制体。不清楚这方面的开销,会不会相当于反向优化游戏呢?
目前知识储备还不太能找到一个完美解决方案,等待后续学习吧。

初入开发Unity,如果这种设计存在缺陷等问题,欢迎留言指正,十分感谢。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值