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. webapp网络定位

    1 <script> 2 var x=document.getElementById("demo"); 3 function getLocation() 4 { 5 i ...

  2. java web课程设计(简单商城的前后端双系统,基于maven三模块开发)

    1.系统分析 1.1需求分析 实现一个简单但功能完整的商城项目,从设计到实现,规范化完成该项目,锻炼javaweb项目的编写能力,理解软件工程的软件设计思想 1.2编程技术简介 本次课程主要使用的软件 ...

  3. 如何让BootStrap栅格之间留出空白间隙呢?

    BootStrap栅格之间留出空隙 BootStrap栅格系统可以把我们的container容器划分为若干等分,如果想要每个部分之间留出一定的空隙,我们很可能首先想到的方法就是用margin外边距来使 ...

  4. RabbitMq安装(单点与集群)rabbitMq以及状态查询

    集群进入某个节点查看指令:rabbitmqctl cluster_status单机版:docker run -d --name rabbit \-e RABBITMQ_DEFAULT_USER=adm ...

  5. Linux命令集锦之·字符截取命令

    时间:2018-11-15 记录:byzqy 字符截取命令: cut.printf.awk.sed cut $ cut [选项] 文件名 选项: -f 列号:提取第几列: -d 分隔符:按照指定分隔符 ...

  6. VS C++ C# 混合编程

    创建C++ DLL 注意,32bit和64bit之间不兼容 创建普通dll工程 设置Properties -> Configuration Properties -> General -& ...

  7. 云效x钉钉:让研发工作更简单

    云效x钉钉:让研发工作更简单,奔走相告,云效&钉钉集成实现组织架构.成员同步以及消息通知啦! 我们知道云效致力于智能化.安全可追溯.高效.简单.灵活,「云效新一代企业级DevOps平台」阿里云 ...

  8. Python习题集(十四)

    每天一习题,提升Python不是问题!!有更简洁的写法请评论告知我! https://www.cnblogs.com/poloyy/category/1676599.html 题目 请写一个函数,该函 ...

  9. uniapp获取用户OpenId及用户详情

    页面增加一个按钮 <button type="default" open-type="getUserInfo" @click="getUserI ...

  10. JS001. antd vue遍历setFieldsValue表单键值对无效 ( {} -> new Object() )

    问题代码: const tempFieldsValue = this.form.getFieldsValue() Object.keys(tempFieldsValue).map((k) => ...