本文章由cartzhang编写,转载请注明出处。 所有权利保留。
文章链接:http://blog.csdn.net/cartzhang/article/details/54096845
作者:cartzhang

unity商店里面有各种各样的对象池,有smart pool,有pollmanager等各个版本。
本来不太喜欢重复制作轮子,因为个人觉得以解决问题为中心,能用别人的成果,就是很好快捷的方法。

但是这个下面的制作对象池,是团队里的一个同学,最初作为学习unity的一个方法,我们开始一直使用的unity商店里提供的poolmanger的一个版本,但是这个同学很不满意,觉得它的不好用,自己也希望尝试来做一个,于是乎就自己做了一个。
再后来他写完了,让我帮忙看看,我就把它做了一些使用方法上的快捷和整理,对里面的部分代码进行了稍微的修改。

在这里对这位同学表示感谢,辛苦!
文章链接:http://blog.csdn.net/cartzhang/article/details/54096845

一、 什么是对象池

在激活对象时,它从池中提取。在停用对象时,它放回池中,等待下一个请求。

当调用对象时,不使用常规的new 构造子的方式,而是通过一个对象池操作。即如果池中存在该对象,则取出;如果不存在,则新建一个对象并存储在池中。当使用完该对象后,则将该对象的归还给对象池。

以上就是对象池的概念。

二、代码设计

对于这个simple pool,我们使用了LinkedList作为存放对象的容器的。
LinkedList底层采用链表存储元素,所以对于频繁的增删操作效率很高。
为什么使用LinkedList而不是List,因为之前的Pool 对象池就是使用的List,而它的删除效率是线性的,而linkedlist是常量,对删除和插入速度都比较快。
下面List 和LinkedList消耗时间对比:

Append

LinkedList.AddLast(item) constant time

List.Add(item) amortized constant time, linear worst case

Prepend

LinkedList.AddFirst(item) constant time

List.Insert(0, item) linear time

Insertion

LinkedList.AddBefore(node, item) constant time

LinkedList.AddAfter(node, item) constant time

List.Insert(index, item) linear time

Removal

LinkedList.Remove(item) linear time

LinkedList.Remove(node) constant time

List.Remove(item) linear time

List.RemoveAt(index) linear time

Count

LinkedList.Count constant time

List.Count constant time

Contains

LinkedList.Contains(item) linear time

List.Contains(item) linear time

Clear

LinkedList.Clear() linear time

List.Clear() linear time

参考网址:http://stackoverflow.com/questions/169973/when-should-i-use-a-list-vs-a-linkedlist

其实这里选择LinkedList只是因为这个同学觉得List的删除太慢,之前影响过我们,所以它觉得链表应该会好些,效果确实是好了很多。但是不完全是因为使用了链表,而是因为这个对象池的代码里,没有做过多的查询,你可以看到contain,linkedlist和list效果应该差别不大。
使用了只有三个方法:AddLast,Remove,Clear,并且Remove使用的还是Remove(value),so…。但是对于内存的使用,不需要开辟连续内存是有好处的。因为list的地址是一个,首地址。而linkedlist可以使用其他碎片地址。

三、实现代码

总共的实现脚本有三个,在scripts文件夹下;测试脚本两个,在scripts/demo文件夹下。

1. ObjectPool.cs

一开始申请两个链表,一个存放使用对象,一个存放未使用对象。需要从对象池内取,就看看有没有可用的,没有就产生一个,有就取出一个。用完了,需要返回,就直接从使用的列表中删除,转移到未使用的链表中。

实现的代码在ObjectPool.cs文件中。

这个文件中,唯一需要注意是就是延时回池的过程中,可能被其他触发回池,或多次延迟回池,这样可能需要多次回池造成回池失败,还需要查询来判断是否已经回池。即使可以查询是否已经回池,也会有第一次已经回池,延时还没执行到,第二次又取了出去,刚取出没有多久,第一次的延时回池到了,又回池了。这个说起来,挺拗口的,但是在实际中真的有这样的情况。

怎么解决多次回池,我们借鉴或说是直接拿来用的是poolmanager的处理方法。

IEnumerator DelayPushObjectToPool(Transform handleTransform, float delayTime){while (delayTime > 0){yield return null;// If the instance was deactivated while waiting here, just quitif (!handleTransform.gameObject.activeInHierarchy){yield break;}delayTime -= Time.deltaTime;}PushObjectToPool(handleTransform);}

这样若延时时间到,或被回池,就看看场景中是否还可见,若不可见就不进行下面的回池处理了,说明已经回到对象池中了。

2.PoolManager.cs

这个文件中,对上面脚步中的调用,进行了封装。
一开始的调用接口为:
PullObjcetFromPool 和 PushObjectPool 这个四个接口,因为有重载。
但是后来觉得别人写的时候,需要添加命名空间,习惯于Unity的Instantiate有使用的差异,所以就做了GameObject的扩展函数。


/// <summary>
/// 扩展GameObject函数
/// 使用扩展函数方面代码调用,可以Unity的任意代码中,调用对象池来产生和回池对象,
/// 并且不需要调用命名空间等繁琐东西。
/// 代码例子: obj = gameObject.InstantiateFromPool(prefab);
///  gameObject.DestroyToPool(poolObjs[poolObjs.Count - 1], 0.2f);
///  具体可以参考HowToUse脚本和TestEffect。
///  @cartzhang
/// </summary>
public static class GameObjectExten
{/// <summary>/// 调用对象池,产生一对象,并带有位置和旋转等参考/// </summary>/// <param name="gameobject"></param>/// <param name="original"></param>/// <param name="position"></param>/// <param name="rotation"></param>/// <returns></returns>public static GameObject InstantiateFromPool(this GameObject gameobject, Object original, Vector3 position, Quaternion rotation){return PoolManager.PullObjcetFromPool(original as GameObject, position, rotation).gameObject;}/// <summary>/// 调用对象池,产生对象/// </summary>/// <param name="gameobject"></param>/// <param name="original"></param>/// <returns></returns>public static GameObject InstantiateFromPool(this GameObject gameobject, Object original){return PoolManager.PullObjcetFromPool(original as GameObject).gameObject;}/// <summary>/// 对象返回对象池/// </summary>/// <param name="gameobject"></param>/// <param name="obj"></param>public static void DestroyToPool(this GameObject gameobject, Object obj){PoolManager.PushObjectPool((obj as GameObject).transform);}/// <summary>/// 带延时的返回对象池/// </summary>/// <param name="gameobject"></param>/// <param name="obj"></param>/// <param name="t"></param>public static void DestroyToPool(this GameObject gameobject, Object obj, [DefaultValue("0.0F")] float t){PoolManager.PushObjectPool((obj as GameObject).transform, t);}
}

在其他需要调用的脚本中的调用方法:

obj = gameObject.InstantiateFromPool(prefab);
和gameObject.DestroyToPool(poolObjs[poolObjs.Count - 1], 0.2f);

至于gameobject是那个对象,这里不关紧要,因为只是为了引出对象池的调用,gameobject没有实质的参与池的处理。

3.PoolPreCreate.cs

PoolPreCreate.cs 文件,在start游戏开始时候,预先产生一些对象的脚本。

图0

四、样例使用说明代码

HowToUse.cs文件中,说明怎么使用对象池。并起有UI文字提示。

图4

TestEffect.cs脚本文件,测试在协同中一边申请,一边回池会不会造成错误的测试。

五、不足

1.数量控制

没有对池内对象做最大数的处理,只是能实现功能,可以很简洁的使用。对于阶段性使用的对象,并没有做时间段内做整理和处理。

也就是说,若在A阶段,游戏场景中同时需要大量的某个池内O1对象,这时候就出现大量的AO1对象在内存中,但是过了A阶段,不需要A这么多O1对象时候,对象池内没有做操作和优化。

2. 多线程处理

对于多线程的从对象池内取出对象和放进对象,没有做处理,就会出现竞争的情况。

暂时就想到了这些。

所以说,这个是一个simple pool for unity.
虽然有这些不足,但是对于简单的小游戏还是非常实用,用起来也非常简便,简单,简洁。希望大家能够喜欢。

六、工程分享地址:

github地址:https://github.com/cartzhang/simple_pool_bench

可以下载Assets文件,然后用unity测试。

若有问题,请提交问题或代码,非常感谢!!!

七、 参考

[1] http://baike.baidu.com/link?url=56D15ulclFdO8d-HQ6KW0WQGjHwnzztof7FGYUyUC76Ui6J3I_0EU4qSfkXJRY7wDLjaCMN5UZKJb9Nt0WU-PT13GkFFtrBqGC6JIE9-zoIP8SB0KRhdZx8yk9kAFAaY

[2] http://www.111cn.net/net/160/81016.htm

[3] http://www.cnblogs.com/xinye/p/3907642.html

[4] https://msdn.microsoft.com/en-us/library/he2s3bh7(v=vs.110).aspx

[5] http://stackoverflow.com/questions/169973/when-should-i-use-a-list-vs-a-linkedlist

[6] http://www.xuanyusong.com/archives/2974

对象池——Smiple Pool For Unity相关推荐

  1. golang的临时对象池sync.Pool

    今天在写码之时,发现了同事用到了sync.pool.因不知其因,遂Google之.虽然大概知道其原因和用法.还不能融汇贯通.故写此记,方便日后查阅.直至明了. 正文 在高并发或者大量的数据请求的场景中 ...

  2. 【游戏开发实战】Unity循环复用列表,支持不规则尺寸(对象池 | UGUI | ScrollRect | Demo源码)

    文章目录 一.前言 二.使用方法 1.创建Scroll View 2.设置Scroll View参数 2.1.调整宽高 2.2.删除Scrollbar滑块 2.3.设置item模板: Item Tem ...

  3. Golang sync.pool对象池

    概览 Goalng中通过sync.pool提供了对象池的实现来达到对象复用的目的.在netty中,也通过Recycle类实现了类似的对象池实现.在netty的对象池Recycle中,当A线程需要将B线 ...

  4. Unity框架之对象池GameObjectPool

    Unity框架之对象池GameObjectPool 文章目录 Unity框架之对象池GameObjectPool 对象池的核心思想 对象池的使用流程 对象池的设计 通用的对象池框架 对象池的数据结构 ...

  5. java对象工厂池_[转载]Java对象池技术的原理及其实现

    作者:汪永好 出处:计算机与信息技术 责任编辑: 方舟 [ 2006-11-25 07:00 ] 摘 要 :本文在分析对象池技术基本原理的基础上,给出了对象池技术的两种实现方式.还指出了使用对象池技术 ...

  6. java 对象池 博客_Java对象池技术的原理及其实现的小结

    一起学习 Java对象的生命周期大致包括三个阶段:对象的创建,对象的使用,对象的清除.因此,对象的生命周期长度可用如下的表达式表示:T = T1 T2 T3.其中T1表示对象的创建时间,T2表示对象的 ...

  7. java 对象池 实现_Java对象池技术的原理及其实现

    看到一片有关于java 对象基础知识,故转载一下,同时学习一下. 摘 要 本文在分析对象池技术基本原理的基础上,给出了对象池技术的两种实现方式.还指出了使用对象池技术时所应注意的问题. 关键词 对象池 ...

  8. Unity3D 内存优化(一)对象池

    一.定义: 关于U3D内存优化,一直是游戏开发者头疼的事情,由于在项目中我们会频繁地创建和销毁一些对象,例如:怪物模型或者是UI预设体,但是,部分对象在游戏中是会频繁出现的,例如战斗中的小怪物,假如每 ...

  9. Unity中对象池的使用

    unity中用到大量重复的物体,例如发射的子弹,可以引入对象池来管理,优化内存. 对象池使用的基本思路是: 将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用.恰当地使用对象池,可以在 ...

最新文章

  1. 14、Kubernetes持久化存储
  2. DIY最近准备配一台经济型的电脑,查了一下配置如下,总价2481元,自己也不专业,不知道有没有问题...
  3. 使用CFURLCreateStringByAddingPercentEscapes进行URL编码
  4. shell脚本读取csv_shell script 处理 CSV 文件(Excel)
  5. CentOS配置启动ssh与开机自启
  6. FastDFS在项目中的应用
  7. python中什么是实例-在Python中使用’__rsub__’方法的典型实例是什么?
  8. 贝壳宣布内部调查实质性完成
  9. 荣耀Magic 3渲染图曝光:超大主摄暗示顶级成像效果
  10. MD5算法的C++实现
  11. 二建公路工程知识总结_2020二建公路实务:专题突破+高分攻略,拿分90稳过二建...
  12. 32、剑指offer--把数组排成最小的数
  13. MySQL修改表字段的长度
  14. 网易云音乐自建服务器,自建私有云音乐服务–Subsonic
  15. 服务器 cpu型号怎么看,服务器cpu参数肿么看
  16. 计算机考研 专业课 数据结构
  17. 相关性分析:Pearson、Kendall、Spearman
  18. 很全的HTML5功能概述,温故而知新,可以为师矣!
  19. C# DateTime:日期、日期差、时间、时间差
  20. 【问】前台销售时卡顿

热门文章

  1. 应用程序无法正常启动(0xc0000142)。请单击‘确认’关闭应用程序
  2. 解决Visio中的交叉线的措施
  3. 信使服务、防火墙、XP的个性化设置
  4. SQL2 查找入职员工时间排名倒数第三的员工
  5. Access+Vs 数据库增删查改——使用Asp.net的sqldatasource控件,根据如下Universtiy.mdb数据库,处理学生注册选课与授课老师的工作
  6. android变焦,Android开发:控制镜头变焦
  7. 安装算量软件布套管操作
  8. PaddleGan让一部令人难忘的黑白电影重换新生
  9. 19 款仿 Bootstrap 后台管理主题免费下载
  10. Flash小技巧之allowScriptAccess