首页 > 其他分享 >Unity对象池(应用:游戏音效管理系统)

Unity对象池(应用:游戏音效管理系统)

时间:2024-02-25 22:57:43浏览次数:30  
标签:poolDictionary 管理系统 对象 void item Unity 音效 pools public

打算为项目增加音效,但是没有头绪不知从何做起。想要做一个便于拓展的音效管理系统,通过搜集网上资料暂时得到以下两种方案。(虽然实现方式远不止两种)其中对象池技术早有耳闻,趁此机会学习并应用。

一、创建一个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也可),用以区分不同对象池。

image

初始化

初始化的前提是配置好Pools
image

代码如下

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

相关文章

  • 实验室与排课管理系统
    适用于校园与科研单位主要技术栈Java8Maven3.6.3MySQL5.7Python3.8SpringBoot框架Vue2  项目地址:https://github.com/BennettMa23 说明手册默认用户,可在系统的用户管理自行增加管理员:用户名:admin密码:admin老师:用户名:teacher密码:admin学生......
  • Unity编辑器扩展秘籍-利用Editor.finishedDefaultHeaderGUI增加Header功能
    利用Editor.finishedDefaultHeaderGUI这个回调可以实现自定义Header菜单usingUnityEditor;usingUnityEngine;namespaceYaojz{[InitializeOnLoad]publicstaticclassDefaultHeaderDrawer{staticDefaultHeaderDrawer(){E......
  • Unity编辑器扩展秘籍-利用EditorApplication.contextualPropertyMenu为右键菜单增加自
    假设我们希望为材质右键弹出按钮增加新的功能,应该怎么做呢我们可以通过注册EditorApplication.contextualPropertyMenu全局回调方法,增加自定义的MenuItemusingUnityEditor;usingUnityEngine;namespaceYaojz{[InitializeOnLoad]publicstaticclassMaterialC......
  • Unity xLua开发环境搭建与基础进阶
    Unity是一款非常流行的游戏开发引擎,而xLua是一个为Unity开发者提供的Lua框架,可以让开发者使用Lua语言来进行游戏开发。在本文中,我们将介绍如何搭建UnityxLua开发环境,并进行基础进阶的学习。 对啦!这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白,也有一些正......
  • 打造纯Lua组件化开发模式:Unity xLua框架详解
    在传统的Unity开发中,通常会使用C#来编写游戏逻辑和组件。但是,随着Lua在游戏开发中的应用越来越广泛,我们可以将游戏逻辑和组件完全用Lua来实现,实现纯Lua的组件化开发模式。这样做的好处是可以更加灵活地修改游戏逻辑,而不需要重新编译C#代码。 3.实现步骤对啦!这里有个游戏开......
  • 02. 安装 Unity 引擎和代码编辑器
    下载并安装Unity访问网站unity.cn,在右边点击下载Unity。如果没有Unity账号,先注册账号,然后登陆账号。首先下载UnityHub,安装UnityHub,获取个人免费许可,再安装编辑器代码编辑器有VisualStudio、VisualStudioCode、Rider具体怎么用见下面的链接https://learn.microso......
  • 【Unity】ScriptableObject使用之后,重新打开Unity会报错
    导致问题出现的原因:ScriptableObject的类与其他类放一起了具体请见:unity2020.3官方文档ScriptableObject部分解决方法:为ScriptableObject单独创建一个c#脚本,并将c#名称与ScriptableObject类名保持一致。猜测出现这样的原因,如果哪里不对烦请大佬指正一下:Unity中基本上都是会通......
  • Unity如何从0实现技能CD遮罩
    需求描述我们需要实现一个类似英雄联盟中的技能CD遮罩,施放技能后,技能遮罩占满技能图标,随着时间推移,技能遮罩顺时针减少遮挡面积,CD结束时,遮罩应完全消失。需求分析由于每个时刻,都会有一条线从中心点射向上面那条边的中点,我们自然可以想到将遮罩面片分为8个三角形。并且我们只......
  • Unity编辑器扩展秘籍-反射解决ParticleSystemEditor的扩展显示错误的问题
    如果使用常规的扩展编辑器方法,为ParticleSystem增加一个自定义按钮[CustomEditor(typeof(ParticleSystem))]publicclassMyParticleSystemEditor:UnityEditor.Editor{privateList<Material>_mats=newList<Material>();publicoverridevoi......
  • Unity引擎2D游戏开发,场景管理和切换
    需要用到的工具资源打包、远程热更新工具Addressables工具基本操作在Window菜单下方,会有AssetManagement,选择Addressables中的Groups会弹出相关菜单,将其拖入底部工具栏会提示没有创建Addressables的相关配置,则点击CreateAddressablesSettings这时候会在Project中,多出......