打算为项目增加音效,但是没有头绪不知从何做起。想要做一个便于拓展的音效管理系统,通过搜集网上资料暂时得到以下两种方案。(虽然实现方式远不止两种)其中对象池技术早有耳闻,趁此机会学习并应用。
一、创建一个AudioManager
AudioManager通常是一个单例(Singleton)类,负责管理和播放游戏中的所有音频
(GPT生成代码)
using UnityEngine;
public class AudioManager : MonoBehaviour
{
public static AudioManager Instance;
public AudioSource bgmSource;
public AudioSource sfxSource;
public AudioClip playerFootstep;
public AudioClip monsterFootstep;
public AudioClip playerAttack;
public AudioClip playerHurt;
public AudioClip playerDeath;
public AudioClip bossBgm;
private void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
Destroy(gameObject);
return;
}
DontDestroyOnLoad(gameObject);
}
// 播放背景音乐
public void PlayBGM(AudioClip bgm)
{
bgmSource.clip = bgm;
bgmSource.Play();
}
// 播放玩家走路脚步声
public void PlayPlayerFootstep()
{
PlaySFX(playerFootstep);
}
// 播放怪物走路脚步声
public void PlayMonsterFootstep()
{
PlaySFX(monsterFootstep);
}
// 播放玩家攻击声音
public void PlayPlayerAttack()
{
PlaySFX(playerAttack);
}
// 播放玩家受伤声音
public void PlayPlayerHurt()
{
PlaySFX(playerHurt);
}
// 播放玩家死亡声音
public void PlayPlayerDeath()
{
PlaySFX(playerDeath);
}
// 播放Boss特定背景音乐
public void PlayBossBGM()
{
PlayBGM(bossBgm);
}
// 播放音效
public void PlaySFX(AudioClip clip)
{
sfxSource.PlayOneShot(clip);
}
}
二、对象池管理音效
对象池定义
涉及对象的反复生成与销毁时频繁使用Instatiate实例化和Destory会造成较大的性能开销,于是有了对象池技术。
对象池是一个存放同种游戏对象GameObject的仓库,需要对象时将其中的对象激活,不需要时隐蔽,等待下次激活,避免了反复运算。最常用的应用是子弹的生成和销毁。
一般对象池都是一个全局性的通用脚本,可以采用单例模式来设计。
对象池功能
对象池至少包含以下两个基本功能:
1.从池中取出指定类型的对象
2.回收各式各样的对象到池中
各部分代码
定义对象池及容量
[System.Serializable]
public class Pool
{
public string tag;
public GameObject prefab;
public int size;
}
[SerializeField]
public List<Pool> pools ;//声明一个列表的对象池
private Dictionary<string, Queue<GameObject>> _poolDictionary;//_前缀表示私有
private GameObject _poolParent;//父对象
Pool类是单个对象池,包含tag等属性
pools是一个列表,包含多种对象池
_poolDictionary是一个字典,key是对象类型,value是对象队列(List也可),用以区分不同对象池。
初始化
初始化的前提是配置好Pools
代码如下
private void Start()
{
_poolDictionary = new Dictionary<string, Queue<GameObject>>();
_poolParent = new GameObject("poolParent");//在游戏中生成
_poolParent.transform.SetParent(this.transform);//_poolParent的父对象是ObjectPoolManager
InitPool();
}
//实例化每一个pool项目下的所有项目中的GameObject
private void InitPool()
{
if (pools.Count == 0) return;
for(int i = 0; i < pools.Count; i++)
{
for(int j = 0; j < pools[i].size; j++)
{
//实例化所有GameObject
var item = Instantiate(pools[i].prefab);
item.SetActive(false);
item.transform.SetParent(_poolParent.transform);
//判断对象池字典中是否有该类项目:创建字典键值对
if (!_poolDictionary.ContainsKey(pools[i].tag))
{
//给字典加键
_poolDictionary.Add(pools[i].tag, new Queue<GameObject>());
//给对应键加值
_poolDictionary[pools[i].tag].Enqueue(item);
}
else
{
//给对应键加值
_poolDictionary[pools[i].tag].Enqueue(item);
}
}
}
}
//至此把所有池子里所有项目实例化完毕
声明public方法供外界调用,生成对象
public void TryGetPoolItem(string name,Vector3 position,Quaternion rotate)
{
if (_poolDictionary.ContainsKey(name))
{
var item = _poolDictionary[name].Dequeue();//从字典中取出
item.transform.position = position;
item.transform.rotation = rotate;
item.SetActive(true);
_poolDictionary[name].Enqueue(item);//再放回去(总不能每次激活一个队列就少一个)
}
else
{
Debug.Log("当前字典名不存在");
}
}
完整代码ObjectPoolManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPoolManager : Singleton<ObjectPoolManager>
{
protected override void Awake()
{
base.Awake();
DontDestroyOnLoad(this);
}
[System.Serializable]
public class Pool
{
public string tag;
public GameObject prefab;
public int size;
}
[SerializeField]
public List<Pool> pools ;//声明一个列表的对象池
private Dictionary<string, Queue<GameObject>> _poolDictionary;//_前缀表示私有
private GameObject _poolParent;//父对象
private void Start()
{
//pools = new List<Pool>();
_poolDictionary = new Dictionary<string, Queue<GameObject>>();
_poolParent = new GameObject("poolParent");//在游戏中生成
_poolParent.transform.SetParent(this.transform);//_poolParent的父对象是ObjectPoolManager
InitPool();
}
//实例化每一个pool项目下的所有项目中的GameObject
private void InitPool()
{
if (pools.Count == 0) return;
for(int i = 0; i < pools.Count; i++)
{
for(int j = 0; j < pools[i].size; j++)
{
//实例化所有GameObject
var item = Instantiate(pools[i].prefab);
item.SetActive(false);
item.transform.SetParent(_poolParent.transform);
//判断对象池字典中是否有该类项目:创建字典键值对
if (!_poolDictionary.ContainsKey(pools[i].tag))
{
//给字典加键
_poolDictionary.Add(pools[i].tag, new Queue<GameObject>());
//给对应键加值
_poolDictionary[pools[i].tag].Enqueue(item);
}
else
{
//给对应键加值
_poolDictionary[pools[i].tag].Enqueue(item);
}
}
}
}
//至此把所有池子里所有项目实例化完毕
public void TryGetPoolItem(string name,Vector3 position,Quaternion rotate)
{
if (_poolDictionary.ContainsKey(name))
{
var item = _poolDictionary[name].Dequeue();//从字典中取出
item.transform.position = position;
item.transform.rotation = rotate;
item.SetActive(true);
_poolDictionary[name].Enqueue(item);//再放回去(总不能每次激活一个队列就少一个)
}
else
{
Debug.Log("当前字典名不存在");
}
}
}
此处缺少对象池的回收部分,该部分在SoundPoolItem.cs中
未完待续
标签:poolDictionary,管理系统,对象,void,item,Unity,音效,pools,public From: https://www.cnblogs.com/neromegumi/p/18033191