当前位置: 首页 > news >正文

unity全局音量管理/全局音量设置与音量设置界面(含静音功能)

 前言

本文将会介绍如何使用audiomixer实现全局音量控制,并且会介绍如何实现游戏内的含静音功能的音量设置界面。

本人也是个初学者,在看过一些关于音量管理的教程后,发现使用audiomixer实现全局音量控制可能是最方便、功能最完备、强大的,因此在这里分享一下自己的实现方法。如果有错误,还请指出捏

基础

音效成功播放需要两个先决条件:音频源 (Audio Source) 音频监听器 (Audio Listener)。

音频源 (Audio Source) 在场景中播放音频,而音频监听器 (Audio Listener) 充当类似于麦克风的设备。它接收来自场景中任何给定音频源的输入,并通过计算机扬声器播放声音。

7bdc23e565434b809f59238c976684a1.png

AudioListener和AudioSource

 其中,Audio Listener 会在相机创建时自动创建,当同一场景中的Audio Listener数量大于1时,unity编辑器会报错fe0c028c99534c24a2a658c153b75773.png

混音器 (Audio Mixer) 允许混合各种音频源,对音频源应用效果。在音频源脚本(Audio Source)的Output挂载AudioMixer的Group Controller文件后,这个音频源就会放出应用了AudioMixer效果的音频。基于此,通过使用代码对AudioMixer的音量进行动态调整,我们就可以实现游戏内动态调整这一个音频源的音量,进而调整全局音量了。

逻辑:

游戏中的音频大致可分为 音效(Sound) 和音乐(Music)两种,因此我们这里就只实现对音效和音乐的设置,同时实现对主音量(Master)的设置

98bb93f2a928447d9049e374543f18ef.png

逻辑关系

 

 AudioMixer制作

1.create->AudioMixer538dbf89f6204ee985293f36522d819f.png

 2.打开AudioMixer

f7dfbbd975224eb4a8cec6ae302c40c4.png

这个NewAudioMixer就是新建的AudioMixer

 3.点击Group的加号创建Music、Sound,并设置好层级关系

c4dd09599d524bebb015b95540b203b6.png

需要拖动,将三个group的层级关系设置为如图所示

 4.在每个group的inspector中右键Volume,并将volume属性暴露出去f628d3c05d294830bf6565cc5167bff6.png

5.如图所示,重命名暴露出去的volume属性cb0c1a47856d457ca6ba265a04299248.png

至此,AudioMixer就基本完成了。将AudioMixer文件夹下的Audio Mixer Group Controller文件拖动到AudioSource的Output中,这个AudioSource放出的音频就都将会应用对应Group的效果。

下面,我们就可以通过动态设置刚才暴露出的volume属性来实现音量设置了。开始愉快的写代码吧~

 

音量设置面板实现

在这里,我简单地假设开发情形如下:有两个场景,每个场景播放不同的背景音乐。那么,就只需要在两个场景中创建两个搭载了AudioSource,并循环播放bgm的空物体,即可实现播放背景音乐的需求

5377596c1f9e4dc99a62c037053066de.png

如图所示

 而音效的播放,则是在所有场景中都会频繁地使用到,并且播放的音效各不相同,因此需要创建一个用于播放音效的持续单例脚本,使其在场景切换时不被摧毁,并且便于其他脚本调用播放音效的脚本,满足整个游戏的音效播放需求。

至于音量设置,由常理可知音量是全局均可设置的,因此也使用持续单例模式开发,并且用滑动条(sliider)来调节音量。

同时:我们需要实现音量设置面板的如下功能:

1.静音按钮

2.取消静音时回调滑动条到未静音时的值

那么,我们将这一个功能的实现分为两个部分:持续单例AudioManager,以及一个继承了monobehavior的脚本,用于控制其所处场景的音量ui。

 

AudioManager脚本

(我偷懒,就把播放音效功能和AudioManager脚本写到一起了,虽然这样不会有什么大问题,但二者终究不是同一个功能,可能会导致代码比较混乱)

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Audio;//使用单例模式开发,继承单例父类,使其在场景切换时不销毁
//同时包括音量设置功能和播放音效功能
public class AudioManager : PersistentSingleton<AudioManager>
{[SerializeField] AudioMixer audioMixer;//改变音调const float pitchMin = 0.9f;const float pitchMax = 1.1f;//用于判断静音与否private bool IsMuteMaster = false;private bool IsMuteMusic = false;private bool IsMuteSound = false;//用于储存静音前的音量private float LastMaster;private float LastMusic;private float LastSound;//音量设置//Slider on click:调节音量,若静音则取消静音public void MasterSldOnClick(GameObject image, Slider slider){audioMixer.SetFloat("vMaster", slider.value);if (IsMuteMaster == false) return;else{image.SetActive(false);IsMuteMaster = false;}}public void MusicSldOnClick(GameObject image, Slider slider){audioMixer.SetFloat("vMusic", slider.value);if (IsMuteMusic == false) return;else{image.SetActive(false);IsMuteMusic = false;}}public void SoundSldOnClick(GameObject image, Slider slider){audioMixer.SetFloat("vSound", slider.value);if (IsMuteSound == false) return;else{image.SetActive(false);IsMuteSound = false;};}//Button on click:若静音则取消静音并回调音量;若未静音则静音并储存音量public void MasterBtnOnClick(GameObject image, Slider Master){if (IsMuteMaster){image.SetActive(false);IsMuteMaster = false;Master.value = LastMaster;}else{image.SetActive(true);LastMaster = Master.value;Master.value = Master.minValue;IsMuteMaster = true;}}public void SoundBtnOnClick(GameObject image, Slider Sound){if (IsMuteSound){image.SetActive(false);IsMuteSound = false;Sound.value = Instance.LastSound;}else{image.SetActive(true);LastSound = Sound.value;Sound.value = Sound.minValue;IsMuteSound = true;}}public void MusicBtnOnClick(GameObject image, Slider Music){if (IsMuteMusic){image.SetActive(false);IsMuteMusic = false;Music.value = LastMusic;}else{image.SetActive(true);LastMusic = Music.value;Music.value = Music.minValue;IsMuteMusic = true;}}[SerializeField] AudioSource SoundPlayer;//播放音效public void PlaySound(AudioClip audioClip){SoundPlayer.pitch = 1;SoundPlayer.PlayOneShot(audioClip);}// 改变音调,主要用于重复播放的音效public void PlayRandomSound(AudioClip audioClip){SoundPlayer.pitch = Random.Range(pitchMin , pitchMax );SoundPlayer.PlayOneShot(audioClip);}public void PlayRandomSound(AudioClip[] audioClip){PlayRandomSound(audioClip[Random.Range(0, audioClip.Length)]);}
}

其中 ,PersistentSingleton为持续泛型单例父类,使脚本挂载的物体不随场景改变而销毁,并且使其他脚本更容易调用本脚本内容。代码见下,详情可见unity单例,实现全局保存/跨场景传输数据

using UnityEngine;public class PersistentSingleton<T> : MonoBehaviour where T : Component
{public static T Instance { get; private set; }protected virtual void Awake(){if (Instance == null){Instance = this as T;}else if (Instance != this){Destroy(gameObject);}DontDestroyOnLoad(gameObject);}
}

 写完AudioManager脚本后,将AudioManager挂载到一个第一个场景的空物体上,以便生效(或是挂载到可以调节音量的第一个场景也行)。然后再将刚做好的AudioMixer和用于播放音效的AudioSource拖进脚本里面就行了~

389d2286fe314291a89b24b4b0915795.png

AudioSource和AudioManager如上图所示
在这种实现方式下,需要把AudioSource放在AudioManager下,防止跨场景销毁。但这是基于只用这一个音源就可满足整个游戏音效需求的大前提下的,可能会有更好的实现方法。

 

AudioManager是全局起作用的,只需要在调节滑动条(slider)时调用三个SldOnClick函数/点击按钮时调用三个BtnOnClick函数,即可以实现全局调节音量的功能。

不过值得注意的是,三个BtnOnClick函数中有一条命令:Sound.value = Instance.LastSound。这条命令不会导致bug,会正常触发SldOnClick,因为SldOnClick的触发条件实际上是On Value Change(所有slider都是),只要值变化就可以触发,而并非一定要click。

 

各场景音量设置界面,以及设置界面脚本

下面,我们需要为每个场景创建音量设置界面,这里只创建一个场景的,因为其他场景也是一样的,实际开发时复制粘贴就行。

1.滑动条(slider)

slider组件比较复杂,虽然不难,但是创建一个功能完备的slider也不是一两句就能说完的,这里时跳过,不懂的小伙伴可以去找些教程,先创建一个能用的滑动条。

99bf8818c57342848a1acaa4a797d3e7.gif

 

2.音量设置界面

b54ae7a35204480ea16fb761aafc5cb4.png

按照上图思路,继续创建音效和音乐的设置界面。83826d4adc894a9a9cd2cc8a9d9b2f45.png

 3.设置界面脚本

using UnityEngine;
using UnityEngine.UI;public class TestScene : MonoBehaviour
{[Header("-----音量设置条-----")][SerializeField] Slider Master;[SerializeField] Slider Music;[SerializeField] Slider Sound;//SldOnClick:传递参数以触发AudioManager的SldOnClickpublic void MasterSldOnClick(GameObject image){AudioManager.Instance.MasterSldOnClick(image, Master);}public void MusicSldOnClick(GameObject image){AudioManager.Instance.MusicSldOnClick(image, Music);}public void SoundSldOnClick(GameObject image){AudioManager.Instance.SoundSldOnClick(image, Sound);}//BtnOnClick:传递参数以触发AudioManager的BtnOnClickpublic void MasterBtnOnClick(GameObject image){AudioManager.Instance.MasterBtnOnClick(image, Master);}public void SoundBtnOnClick(GameObject image){AudioManager.Instance.SoundBtnOnClick(image, Sound);}public void MusicBtnOnClick(GameObject image){AudioManager.Instance.MusicBtnOnClick(image, Music);}}

这个脚本实际上只是起到了传递参数的作用,这么做一方面时因为,多个参数的函数不能挂载到button、slider等组件上,另一方面是因为, AudioManager是持续单例,在某些场景中不是初始存在,无法直接挂载到组件上,需要使用代码动态调用。

将这个脚本挂载到场景中(随便哪都行),并将三个slider挂载到脚本上即可。24b93c2d47dc428ebc630aaedfba12fd.png

 3.配置按键与滑动条

以Master按键和滑动条为例:

13bcd38298514480b53fd4d32d3faf11.png

将刚才设置好的脚本挂到button组件下,并选择MasterBtnOnClick函数,将按键的子物体image挂到这个函数下面

e01b1e05457d41989005a84b9ba6f3e7.png

Sound、Music同上

同样的,给Master的slider挂上 MasterSldOnClick函数,同样的把Master的叉号挂到函数下即可。

至此,整个音量设置界面就做完了a37411890bd146669ec47560b4d1ab66.gif

 

 

 

 

相关文章:

unity全局音量管理/全局音量设置与音量设置界面(含静音功能)

前言 本文将会介绍如何使用audiomixer实现全局音量控制&#xff0c;并且会介绍如何实现游戏内的含静音功能的音量设置界面。 本人也是个初学者&#xff0c;在看过一些关于音量管理的教程后&#xff0c;发现使用audiomixer实现全局音量控制可能是最方便、功能最完备、强大的&a…...

C++ vector 数组转换、查找、最大最小值、排序、排行的几种用法

C vector中常用到排序、取最值&#xff0c;一些场景可能还会要计算某个元素的排行&#xff0c;以下就是一些实际例子&#xff0c;精简、有效。 【1】会涉及到数组转vector&#xff1a; vector<int> v(arr, arr N); // N为数组size&#xff0c;可用sizeof(arr)/sizeof(i…...

vmware 安装Rocky-9.3系统

安装系统截图 安装完成&#xff0c;启动 查看版本和内核 开启远程登陆授权 1、编辑配置文件 #提升权限&#xff0c;输入su,并输入密码 su #编辑ssh文件开启root远程登陆 vi /etc/ssh/sshd_config找到以下内容&#xff1a;#PermitRootLogin prohibit-password 添加&#xff1a…...

C++提高编程——模板

本专栏记录C学习过程包括C基础以及数据结构和算法&#xff0c;其中第一部分计划时间一个月&#xff0c;主要跟着黑马视频教程&#xff0c;学习路线如下&#xff0c;不定时更新&#xff0c;欢迎关注。 当前章节处于&#xff1a; ---------第1阶段-C基础入门 ---------第2阶段实战…...

单线程、同步、异步、预解析、作用域、隐式全局变量、对象创建、new

单线程 进程 cpu 资源分配的最小单位一个进程可以有多个线程 线程 cpu调度的最小单位线程建立在进程的建立基础上的一次程序的运行单位 线程分为&#xff1a;单线程 多线程 单线程&#xff1a;js是单线程 &#xff08;同一个时间只能完成一个任务&#xff09;多线程&…...

《设计模式的艺术》笔记 - 外观模式

介绍 外观模式中外部与一个子系统的通信通过一个统一的外观角色进行&#xff0c;为子系统中的一组接口提供一个一致的入口。外观模式定义了一个高层接口&#xff0c;这个接口使得子系统更加容易使用。外观模式又称为门面模式&#xff0c;它是一种对象结构型模式。 实现 myclas…...

sql 查询时间范围内的数据

要查询特定时间范围内的数据&#xff0c;您可以使用 SQL 中的 BETWEEN 运算符。以下是一个示例查询&#xff0c;它从名为 your_table 的表中检索在 start_date 和 end_date 之间创建的所有记录&#xff1a; SELECT * FROM your_table WHERE created_date BETWEEN start_date AN…...

TestNG中的@BeforeSuite注释

目录 什么是BeforeSuite注解&#xff1f; BeforeSuite带注释的方法何时执行&#xff1f; BeforeSuite annotation有什么用&#xff1f; 所以&#xff0c;是时候集思广益了 我们可以在一个类中使用多个BeforeSuite注释方法吗&#xff1f; BeforeSuite放在超类上时如何工作…...

[学习笔记]刘知远团队大模型技术与交叉应用L3-Transformer_and_PLMs

RNN存在信息瓶颈的问题。 注意力机制的核心就是在decoder的每一步&#xff0c;都把encoder的所有向量提供给decoder模型。 具体的例子 先获得encoder隐向量的一个注意力分数。 注意力机制的各种变体 一&#xff1a;直接点积 二&#xff1a;中间乘以一个矩阵 三&#xff1a;…...

图像处理工具包Pillow的使用分享

Pillow 是 Python 中一个流行的图像处理库&#xff0c;它是 PIL&#xff08;Python Imaging Library&#xff09;的一个友好的分支版本。Pillow 提供了许多功能&#xff0c;使得图像处理变得容易和方便。下面是一些基本用法和示例&#xff1a; 安装 Pillow 首先&#xff0c;你…...

python进程间通信——命名管道(Named Pipe、FIFO)

文章目录 Python中的命名管道&#xff1a;深入理解进程间通信1. 命名管道简介2. 创建和删除命名管道3. 写入命名管道4. 读取命名管道5. 示例&#xff1a;进程间通信write_to_pipe.pyread_from_pipe.py测试运行 6. 注意事项和限制命名管道的半双工机制命名管道读写任意一方未打开…...

03 OSPF 学习大纲

参考文章 1 初步认识OSPF的大致内容(第三课)-CSDN博客 2...

HJ7 取近似值【C语言】

【华为机试题 HJ7】取近似值 描述输入描述:输出描述:示例1示例2参考代码1参考代码2参考代码3描述 写出一个程序,接受一个正浮点数值,输出该数值的近似整数值。如果小数点后数值大于等于 0.5 ,向上取整;小于 0.5 ,则向下取整。 数据范围:保证输入的数字在 32 位浮点数范…...

php基础学习之常量

php常量的基本概念 常量是在程序运行中的一种不可改变的量&#xff08;数据&#xff09;&#xff0c;常量一旦定义&#xff0c;通常不可改变&#xff08;用户级别&#xff09;。 php常量的定义形式 使用define函数&#xff1a;define("常量名字", 常量值);使用cons…...

2024最新面试经验分享

目录 重点掌握的知识点JavaMySQLRedis 微服务分布式系统项目亮点场景题/设计题短链抢红包多租户 开放性问题自我介绍为什么跳槽团队规模如何带团队如何看待加班职业规划 主要针对Java程序员&#xff0c;当然也包含一些通用的内容。 重点掌握的知识点 需要重点掌握的知识点必须…...

《WebKit 技术内幕》之八(1):硬件加速机制

《WebKit 技术内幕》之八&#xff08;1&#xff09;&#xff1a;硬件加速机制 1 硬件加速基础 1.1 概念 这里说的硬件加速技术是指使用GPU的硬件能力来帮助渲染网页&#xff0c;因为GPU的作用主要是用来绘制3D图形并且性能特别好&#xff0c;这是它的专长所在&#xff0c;它…...

子表单扫码录入,显著节省填写时间

01/17 主要更新模块概览 扫 码 识 别 新 增 字 号 登 录 配 置 匹 配 搜 素 扫码识别 路径&#xff1a;表单设计 >> 字段属性 功能简介 之前对子表单扫码录入&#xff0c;是单独在组件内设置扫码&#xff0c;操作需重新点击扫码功能&#xff0c;手工新增子表数据&a…...

【Redis】Ubuntu安装配置

目录 一、安装Redis 1.1 从APT仓库安装Redis 二、启动&关闭&重启 三、Redis核心配置 3.1 CONFIG命令 3.2 redis.conf文件说明 一、安装Redis 1.1 从APT仓库安装Redis 从APT仓库可以安装最新的Redis稳定版&#xff0c;步骤如下&#xff1a; 【1】安装需要用到的…...

idea远程服务调试

1. 配置idea远程服务调试 这里以 idea 新 ui 为例&#xff0c;首先点击上面的 debug 旁边的三个小圆点&#xff0c;然后在弹出的框框中选择 “Edit”&#xff0c;如下图所示。 然后进入到打开的界面后&#xff0c;点击左上角的 “” 进行添加&#xff0c;找到 “Remote JVM De…...

Google Colab运行Pytorch项目

Google Colab运行Pytorch项目 连接google drive切换到某一文件夹显示当前目录文件安装依赖执行py文件numpy相关numpy.random.randn() 参考文章&#xff1a;文章1 文章2 连接google drive from google.colab import drive import os drive.mount(/content/drive)切换到某一文件…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...