Unity——音频管理器(附例子)
在实际游戏开发中,音效既是一个相对独立的部分,又与其他游戏逻辑密切关联。也就是说,与音效相关的代码会插入很多细节代码中。
而且在音效非常丰富的情况下,如果每一个游戏模块都单独播放音效,那么可能会带来一些问题。例如,Audio Source组件很多,但大部分限制,同时播放的音效太多会显得混乱。
成熟的技术开发思路是:如果音效不多、没有造成问题,则完全可以简单处理;如果音效已经引起了代码的混乱和性能问题,就有必要统一管理所有的音源和音效,也就是设计一个易用的音频管理器。有了音频管理器,所有的Audio Source组件都会统一创建,而所有音效播放的需求都要通过调用音频管理器的方法简介实现。
音频管理器有很多设计思路,其中一种比较简洁的思路是,事先指定游戏中最多同时播放多少个音频,然后创建若干个音源。例如,最多播放8个音频,那么就创建8个Audio Source组件,这8个组件可以看作8个频道。需要播放音频时,只要找到任意一个空闲的频道播放即可;而如果8个频道都正在播放,那么就可以用某种策略替换音频(如将播放时间最早的音频替换成新的音频)。用这种简单的思路创建音频管理器的代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//音频管理器
public class AudioManager : MonoBehaviour
{// 整个游戏中,总的音源数量private const int AUDIO_CHANNEL_NUM = 8;private struct CHANNEL{public AudioSource channel;public float keyOnTime; //记录最近一次播放音乐的时刻};private CHANNEL[] m_channels;void Awake(){m_channels = new CHANNEL[AUDIO_CHANNEL_NUM];for (int i = 0; i < AUDIO_CHANNEL_NUM; i++){//每个频道对应一个音源m_channels[i].channel = gameObject.AddComponent<AudioSource>();m_channels[i].keyOnTime = 0;}}//公开方法:播放一次,参数为音频片段、音量、左右声道、速度//这个方法主要用于音效,因此考虑了音效顶替的逻辑public int PlayOneShot(AudioClip clip, float volume, float pan, float pitch = 1.0f){for (int i = 0; i < m_channels.Length; i++){//如果正在播放同一个片段,而且刚刚才开始,则直接退出函数if (m_channels[i].channel.isPlaying &&m_channels[i].channel.clip == clip &&m_channels[i].keyOnTime >= Time.time - 0.03f)return -1;}//遍历所有频道,如果有频道空闲直接播放新音频,并退出//如果没有空闲频道,先找到最开始播放的频道(oldest),稍后使用int oldest = -1;float time = 10000000.0f;for (int i = 0; i < m_channels.Length; i++){if (m_channels[i].channel.loop==false &&m_channels[i].channel.isPlaying &&m_channels[i].keyOnTime < time){oldest = i;time=m_channels[i].keyOnTime;}if (!m_channels[i].channel.isPlaying){m_channels[i].channel.clip=clip;m_channels[i].channel.volume=volume;m_channels[i].channel.pitch=pitch;m_channels[i].channel.panStereo=pan;m_channels[i].channel.loop = false;m_channels[i].channel.Play();m_channels[i].keyOnTime = Time.time;return i;}}//运行到这里说明没有空闲频道。让新的音频顶替最早播出的音频if(oldest>=0){m_channels[oldest].channel.clip = clip;m_channels[oldest].channel.volume = volume;m_channels[oldest].channel.pitch = pitch;m_channels[oldest].channel.panStereo = pan;m_channels[oldest].channel.loop = false;m_channels[oldest].channel.Play();m_channels[oldest].keyOnTime = Time.time;return oldest;}return -1;}//公开方法:循环播放,用于播放长时间的背景音乐,处理方式相对简单一些public int PlayLoop(AudioClip clip, float volume, float pan, float pitch = 1.0f){for(int i = 0; i < m_channels.Length; i++){if (!m_channels[i].channel.isPlaying){m_channels[i].channel.clip = clip;m_channels[i].channel.volume = volume;m_channels[i].channel.pitch = pitch;m_channels[i].channel.panStereo = pan;m_channels[i].channel.loop = true;m_channels[i].channel.Play();m_channels[i].keyOnTime = Time.time;return i;}}return -1;}//公开方法:停止所有音频public void StopAll(){foreach(CHANNEL channel in m_channels)channel.channel.Stop();}//公开方法:根据频道ID停止音频public void Stop(int id){if (id>= 0&& id < m_channels.Length){m_channels[id].channel.Stop();}}
}
以上代码可以作为创建音频管理器的一种思路参考。
实际上,根据游戏类型的不同,音频管理器的创建思路也有区别。例如,在很多3D游戏中,需要考虑音效播放的空间位置(目的是营造真实感),这是统一创建音源就不是很合适了
相关文章:
Unity——音频管理器(附例子)
在实际游戏开发中,音效既是一个相对独立的部分,又与其他游戏逻辑密切关联。也就是说,与音效相关的代码会插入很多细节代码中。 而且在音效非常丰富的情况下,如果每一个游戏模块都单独播放音效,那么可能会带来一些问题…...

TCP协议基础
一: TCP协议是什么? TCP协议是基于面向连接,可靠传输,基于字节流的传输层通信协议 1. 面向连接 TCP协议是一种面向连接的协议,意味着在双方在建立数据传输之前,需要进行一个逻辑上的连接,且是…...

C# NetTopologySuite+ProjNet 任意图形类型坐标转换
添加引用:NetTopologySuite、ProjNet、ProjNet.SRID Program.cs文件: using ProjNet.CoordinateSystems; using ProjNet.CoordinateSystems.Transformations; using ProjNet.SRID; using System; using System.Collections.Generic; using System.Linq;…...
Windows笔记本电脑开机黑屏
Windows笔记本电脑开机黑屏 最近,我遇到了一件奇怪的事情。我的Windows笔记本电脑在开机时出现了一个黑屏,没有任何反应。我尝试了多种方法,包括重启和恢复出厂设置,但都无济于事。 我开始感到担心,因为这只会影响到…...
Samb共享用户的设置和修改Linux用户的id号,修改Linux组的id号,加入组,删除组成员等
零、samba帐号的设置 为samba共享添加用户,并设定仅能由授权用户进入的共享 #增加没有家目录,也无法登录系统的空用户 useradd -M userA -s /sbin/nologin #-M 选项是--no-create-home的简写形式,即不为该用户配置家目录;-s选项&…...

VBA:对Excel单元格进行合并操作
Sub hb()Dim nn 3For i 3 To 18If Range("b" & i) <> Range("b" & i 1) ThenRange("b" & n & ":b" & i).Mergen i 1End IfNextEnd Sub...
HTML5离线储存
简介 离线存储指的是:在用户没有与因特网连接时,可以正常访问站点或应用,在用户与因特网连接时,更新用户机器上的缓存文件。 原理:HTML5的离线存储是基于一个新建的 .appcache 文件的缓存机制(不是存储技术)…...

cmd: Union[List[str], str], ^ SyntaxError: invalid syntax
跑项目在调用from easyprocess import EasyProcess 遇到报错: cmd: Union[List[str], str], ^ SyntaxError: invalid syntax猜测是EasyProcess版本与python版本不对应 pip show EasyProcess查证一下: WARNING: pip is being invoked by an old…...

2023高教社杯数学建模思路 - 案例:异常检测
文章目录 赛题思路一、简介 -- 关于异常检测异常检测监督学习 二、异常检测算法2. 箱线图分析3. 基于距离/密度4. 基于划分思想 建模资料 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 一、简介 – 关于异常…...
FFDNet-pytorch版本代码测试教程
一、FFDNet-pytorch版本代码下载 (1)FFDNet-pytorch下载 https://download.csdn.net/download/qq_41104871/88233742 二、FFDNet-pytorch版本代码运行环境配置 (1)FFDNet-pytorch版本代码运行环境配置 https://blog.csdn.net/q…...
uni-app项目由hbuilder项目转化为cli项目
1.背景 原uni-app项目是通过hbuilder创建的,运行以及打包都要依赖于hbuilder运行;一般在vscode开发,在hbuilder运行比较怪异;后续希望脱离hbuilder运行并能通过构建平台进行打包,因此将hbuilder项目转化为cli项目 2.…...

使用SpaceDesk连接平板作为电脑副屏详细步骤教程
文章目录 下载安装PC端安装安卓端安装 配置步骤PC端安卓端 连接 SpaceDesk官网链接https://www.spacedesk.net/ (应该是需要科学上网才能进入) SpaceDesk它可以连接安卓,苹果的平板,手机等,也可以连接其他可以打开网页(HTML5)的设备。 这里我…...

云备份——第三方库使用介绍(下)
httplib库,一个C11单文件头的跨平台HTTP/HTTPS库。安装起来非常容易。只需包含httplib.h在你的代码中即可。 httplib库实际上是用于搭建一个简单的http服务器或者客户端的库,这种第三方网络库,可以让我们免去搭建服务器或客户端的时间&#x…...

springboot实战(一)之项目搭建
环境准备 ideajdk1.8springboot版本 2.7.15 项目开始 1.打开idea,点击new project 2.选择spring initillizr 核对:Server Url是否是:start.spring.io,然后根据自己依次设置项目名称、存储位置和包名,如下ÿ…...

线性代数的学习和整理16:什么是各种空间(类型),向量空间,距离(类型)?
目录 1 空间相关的群,环,域,集合,空间的预备知识 1.1:群,环,域,集合,空间的定义(表示不懂,只是做个标记) 2 空间 2.1 各种空间概念…...

css实现文字翻转效果
csss实现文字翻转效果 主要实现核心属性 direction: rtl; unicode-bidi: bidi-override; direction: rtl; 这个属性用于指定文本的方向为从右到左(Right-to-Left)。它常用于处理阿拉伯语、希伯来语等从右向左书写的文字样式。当设置了 direction: rtl; …...

19 Linux之Python定制篇-apt软件管理和远程登录
19 Linux之Python定制篇-apt软件管理和远程登录 文章目录 19 Linux之Python定制篇-apt软件管理和远程登录19.1 apt软件管理19.1.1 apt介绍19.1.2 更新软件下载地址-阿里源19.1.3 使用apt完成安装和卸载vim 19.2 远程登录Ubuntu 学习视频来自于B站【小白入门 通俗易懂】2021韩顺…...

WebDAV之π-Disk派盘 + notototo
notototo是一款功能丰富的笔记软件,提供了多种功能,包括载入PDF文件并进行批注和标记的能力。您可以使用Apple Pencil或手指在PDF文件上进行写作和绘图操作。 同时,notototo也提供了与团队合作的功能,您可以连接到服务器并与他人协作。此外,您还可以在notototo中进行绘图,…...
_kbhit() and getch() 在小游戏中用不了。因为控制台函数,仅在控制台程序中可用
太长不看版: _kbhit() and getch() 包含在conio.h中。 conio是Console Input/Output(控制台输入输出)的简写,其中定义了通过控制台进行数据输入和数据输出的函数,主要是一些用户通过按键盘产生的对应操作,…...

dayjs格式转换成日期
目录 方法一: 编辑方法二: 这个项目在筛选订单时间的时候是由前端进行筛选的,用的是adt-design-pro进行二开的,其中在用日期组件的时候遇到了一个问题,组件返回的是: 但是我需要的是年-月-日ÿ…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...