Unity对象池管理

一、Demo展示

二.逻辑

在游戏中会出现大量重复的物体需要频繁的创建和销毁;比如子弹,敌人,成就列表的格子等;

频繁的创建删除物体会造成很大的开销,像这种大量创建重复且非持续性保持作用的对象我们会使用对象池将其管理起来,用空间换效率;

对象池的要对外提供创建销毁对象的接口,已经添加对象池的接口;

对内要提供创建对象,根据路径查找预制的接口;

整体逻辑如下:

二.加载/添加对象池

添加资源路径,分为Resources文件夹下和SteamingAssets文件下资源;

Resources加载时路径不需要后缀,SteamingAssets需要后缀,根据path路径开头的判断加载方式,同时对路径做处理;

SteamingAssets需要根据平台添加路径头Application.streamingAssetsPath;

Resources需要去掉格式后缀,如.perfab;

这里我测试只使用Resources路径,正式项目自行处理;

存放预创建好的对象:

private Dictionary<string,List<GameObject>> pool;

存放预制体路径:

private Dictionary<string, string> objPath;
public void InitPath()
{
//测试用,正常肯定要做字符串处理的,需要加后缀
objPath.Add("cube","Cube");
objPath.Add("sphere","Sphere");
}
public void Add(string key, int num)
{
if (pool.ContainsKey(key))
{
for (int i = 0; i < num; ++i)
{
//AssetBundle ab = AssetBundle.LoadFromFile($"{path}/{objPath[key]}");
//GameObject go = Instantiate(ab.LoadAsset<GameObject>(key));
//由于我的测试资源就放在Resources下,正式项目需要根据路径做个判断;
GameObject go = Instantiate(Resources.Load<GameObject>(objPath[key]));
go.SetActive(false);
pool[key].Add(go);
}
}
else
{
List<GameObject> goList = new List<GameObject>();
pool.Add(key, goList); for (int i = 0; i < num; ++i)
{
//AssetBundle ab = AssetBundle.LoadFromFile(objPath[key]);
//GameObject go = Instantiate(ab.LoadAsset<GameObject>(key));
GameObject go = Instantiate(Resources.Load<GameObject>(objPath[key]));
go.SetActive(false);
pool[key].Add(go);
}
}
}

三.管理对象池

对象池管理需要对外提供创建对象,销毁对象,延迟销毁和清空池的方法;

创建对象时,需要提供key,坐标,旋转;

现查找是否有对象池,没有则添加;

这里提供了四元素和欧拉角的重载方法;

1.创建对象

public GameObject FindUsable(string key
{
if(pool.ContainsKey(key))
{
foreach (GameObject item in poo
{
if (!item.activeSelf)
return item;
}
Debug.Log($"{key}的对象池数量不够");
}
else
{
Debug.Log($"{key}未添加对象池");
}
return null;
}
/// <summary>创建一个游戏物体到场景 </summary>
public GameObject CreateObject(string k
{
GameObject tempGo = FindUsable(key)
if (tempGo == null)
{
Debug.Log($"{key}的对象池数量不够");
Add(key, 10);
tempGo = FindUsable(key);
}
tempGo.transform.position = positio
tempGo.transform.rotation = quatern
tempGo.SetActive(true);
return tempGo;
}
public GameObject CreateObject(string k
{
GameObject tempGo = FindUsable(key)
if (tempGo == null)
{
Debug.Log($"{key}的对象池数量不够");
Add(key, 10);
tempGo = FindUsable(key);
}
tempGo.transform.position = positio
tempGo.transform.rotation = Quatern
tempGo.SetActive(true);
return tempGo;
}

2.销毁对象

延时销毁可使用回调(invoke)或协程;

public void Destory(GameObject destoryGo)
{
destoryGo.SetActive(false);
} /// <summary>将对象归入池中<summary>
public void Destory(GameObject tempGo, float delay)
{
StartCoroutine(DelayDestory(tempGo,delay));
}
/// <summary>延迟销毁</summary>
private IEnumerator DelayDestory(GameObject destoryGO, float delay)
{
yield return new WaitForSeconds(delay);
Destory(destoryGO);
}

3.清空池

/// <summary>清空某类游戏对象</summary>
public void Clear(string key)
{
pool.Remove(key);
}
/// <summary>清空池中所有游戏对象</summary>
public void ClearAll()
{
pool.Clear();
}

四、测试代码

两个按钮分别创建方块和球,每次创建更改一次位置;鼠标射线点击延迟1s销毁;

public class Test : MonoBehaviour
{
public Button btnCube;
public Button btnSphere;
void Start()
{
GameObjectPool.I.InitPath();
GameObjectPool.I.Add("cube",10);
GameObjectPool.I.Add("sphere",10);
btnCube.onClick.AddListener(OnBtnCube);
btnSphere.onClick.AddListener(OnBtnSphere);
} private Vector3 deltaPos = new Vector3(1, 1, 1);
private Vector3 pos =new Vector3(-10,0,0);
private void OnBtnCube()
{
GameObject go = GameObjectPool.I.CreateObject("cube", pos, Vector3.zero); go.transform.SetParent(null);
SceneManager.MoveGameObjectToScene(go, SceneManager.GetSceneByName("1"));
go.transform.position += deltaPos;
pos = go.transform.position;
} private Vector3 pos1 =new Vector3(0,0,0);
private void OnBtnSphere()
{
GameObject go = GameObjectPool.I.CreateObject("sphere", pos1, Vector3.zero); go.transform.SetParent(null);
SceneManager.MoveGameObjectToScene(go, SceneManager.GetSceneByName("1"));
go.transform.position += deltaPos;
pos1 = go.transform.position;
} private void Update()
{
if(Input.GetMouseButtonDown(0)){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
if(Physics.Raycast(ray,out hitInfo)){
Debug.DrawLine(ray.origin,hitInfo.point);
GameObject gameObj = hitInfo.collider.gameObject;
Debug.Log("click object name is " + gameObj.name);
GameObjectPool.I.Destory(gameObj,1);
}
}
}
}

Unity——对象池管理的更多相关文章

  1. Unity对象池管理

    链接: http://www.xuanyusong.com/archives/2925 http://www.xuanyusong.com/archives/2974 https://www.cnbl ...

  2. Unity 对象池 生产 保存

    Unity对象池主要是保存那些常用的物体,避免他们在不断销毁和创造中损坏性能. 主要思路为:创造物体时,判断是否存在,如果存在则调用并使其显示.如果不存在则创造一个新的. 当销毁时,调用协程延时隐藏物 ...

  3. Unity实现”对象池管理器“

    前言:警告!这可能是坨屎,空闲时间写成,仅作娱乐 在Unity中生成或销毁一个物体会占用较大的资源,如果是制作FPS射击游戏,子弹生成更是雪上加霜.所以我自己写了一个PoolManager,不能和网上 ...

  4. Unity3D 游戏开发构架篇 —— 动态大场景生成 = 区域加载+对象池管理

    项目做一个类似无尽模式的场景,想了一想,其实方法很简单,做一个相关的总结. 主要先谈一谈构架,后期附上代码. 一.区域加载 其实无尽场景的实现很简单,因为屏幕限制,那么不论何时何地,我们只能看到自己的 ...

  5. Unity ----- 对象池GameObjectPool

    孙广东 2014.6.28 非常早之前看到的外国文章,认为不错,分享一下. 对象池在AssetStore中也是有非常多插件的,可是有些重了.自己写一个轻量的岂不是非常好. 当你须要创建大量某种类型对象 ...

  6. Unity 对象池的使用

    在游戏开发过程中,我们经常会遇到游戏发布后,测试时玩着玩着明显的感觉到有卡顿现象.出现这种现象的有两个原因:一是游戏优化的不够好或者游戏逻辑本身设计的就有问题,二是手机硬件不行.好吧,对于作为程序员的 ...

  7. Unity对象池的实现

    对象池是一个单例类: using System.Collections; using System.Collections.Generic; using UnityEngine; public cla ...

  8. 游戏设计模式——Unity对象池

    对象池这个名字听起来很玄乎,其实就是将一系列需要反复创建和销毁的对象存储在一个看不到的地方,下次用同样的东西时往这里取,类似于一个存放备用物质的仓库. 它的好处就是避免了反复实例化个体的运算,能减少大 ...

  9. Unity 游戏框架搭建 (二十) 更安全的对象池

    上篇文章介绍了,只需通过实现IObjectFactory接口和继承Pool类,就可以很方便地实现一个SimpleObjectPool.SimpleObjectPool可以满足大部分的对象池的需求.而笔 ...

随机推荐

  1. 面向对象之编写驱动程序--中断(linux系统、s3c6410开发板)

    /*------------------------- *先申明下,本人是个菜鸟,刚开始接触驱动程序编写,交代下开发环境(主机系统redhat6.3,开发板ARM-s3c6410) 以watchdog ...

  2. Vue.JS快速上手(组件生命周期)

    一.什么是组件 组成网页独立功能基本单元(片段), 复用.维护.性能, Vue.js中的组件就是一个Vue的实例,Vue中的组件包含data/methods/computed. 一个Vue.js的应用 ...

  3. 微信小程序 div选中效果

    ._left{ position: relative; margin-top: 40rpx; width: 40%; height: 350rpx; border-radius: 12rpx; tex ...

  4. minicom-linux下USB转串口配置

    现在的笔记本越做越薄,好些电脑已经没有串口了,做硬件开发会非常头疼,不过有了USB转串口设备,PC机只需要有USB接口就可以了.在linux下我们使用minicom与目标设备通信,在此记录一下linu ...

  5. Python3-sqlalchemy-orm 创建关联表带外键并插入数据

    #-*-coding:utf-8-*- #__author__ = "logan.xu" import sqlalchemy from sqlalchemy import crea ...

  6. Linux常用命令 - 五种创建文件命令详解

    21篇测试必备的Linux常用命令,每天敲一篇,每次敲三遍,每月一循环,全都可记住!! https://www.cnblogs.com/poloyy/category/1672457.html 创建文 ...

  7. github上使用C语言实现的线程池

    网上介绍线程池的知识很多,但是在代码实现上介绍的又不是那么多.而且给人的一种感觉就是:你的这种实现是正规的方式还是你自己的实现? 如果有这么个疑问,且想找一个靠谱的代码拿来使用,那么这个项目是个不错的 ...

  8. 针对Autocad 2014 第二次安装不上的问题

    针对Autocad 2014 第二次安装不上的问题 1. 以下为卸载过程,不用管. 2. 卸载完之后,右击"开始",点击"运行",得到下图:   并输入:&qu ...

  9. 如何将 Ubuntu 版本升级到新版本

    @ 目录 0.将 Ubuntu 版本升级到新版本的注意事项 1.以图形方式升级到 Ubuntu 20.04(适用于桌面用户) 2.使用命令行升级到 Ubuntu 21.10 本教程通过从 Ubuntu ...

  10. ZBLOG PHP调用相关文章列表以及上一篇下一篇文章代码

    如果是比较小的个人博客.专题类网站项目,老蒋还是比较喜欢使用ZBLOG PHP程序的,无论是轻便度还是易用性上比WordPress简单很多,虽然WP的功能很强大,比如强大的插件和主题丰富功能是当前最为 ...