Unity 对象池简单使用
2016-05-23 12:28
543 查看
在 unity 中,我们会遇到一种情况,就是需要不断的创建一些对象,然后又要不断的销毁这些对象。例如:射击游戏里的子弹,这需要我们不断的大量产生,又要大量的销毁。
我们知道 unity 实例化一个 GameObject,它就会占用一定内存,而当他被 Destroy 时,其实它并不会立即销毁,还存在内存中,而是会等到下一次 垃圾回收(GC)时才会真正的销毁。
所以在这个过程中就会出现一个问题,当我们需要大量创建一些对象,又要销毁对象时,游戏就有可能因为资源不足而卡顿一下。这在游戏中是绝对不允许出现的情况。为了解决这样的问题,我们需要事先把这些对象创建好,使用的时候在来调用这些对象。就要用到一个对象池的概念。
我们做一个简单的例子来看一下效果。打开unity新建一个3D工程。在场景中新建一个cube,然后把它作为prefab删掉面板上的cube,在新建一个空物体,我们要让它作为要生产的物体的父物体。新建一个SimplePool脚本添加给摄像机
然后再写一个 TestPool 脚本给摄像机添加:
最后设置好相应的参数:
然后运行程序 ;
我们可以看见差距是非常大的,差不多有8倍之大。
最后,我写的那个还只是简单的对象池脚本,更复杂的我目前也不会,但是,现在这个应该也能在平时练习中进行使用,大家可以把它当作模板进行适当的修改,就可以修改成自己的版本了。
工程地址:http://pan.baidu.com/s/1i49XsG1 密码:wa3g
本博客用作新手学习讨论,如有不好或错误的地方也请指出来,谢谢。
我们知道 unity 实例化一个 GameObject,它就会占用一定内存,而当他被 Destroy 时,其实它并不会立即销毁,还存在内存中,而是会等到下一次 垃圾回收(GC)时才会真正的销毁。
所以在这个过程中就会出现一个问题,当我们需要大量创建一些对象,又要销毁对象时,游戏就有可能因为资源不足而卡顿一下。这在游戏中是绝对不允许出现的情况。为了解决这样的问题,我们需要事先把这些对象创建好,使用的时候在来调用这些对象。就要用到一个对象池的概念。
我们做一个简单的例子来看一下效果。打开unity新建一个3D工程。在场景中新建一个cube,然后把它作为prefab删掉面板上的cube,在新建一个空物体,我们要让它作为要生产的物体的父物体。新建一个SimplePool脚本添加给摄像机
using UnityEngine; using System.Collections; using System.Collections.Generic; public class SimplePool : MonoBehaviour { public Transform parent; //父物体 public GameObject cube; //要生产的对象 public int poolSize; //容量池的容量大小 private List<GameObject> poolList = new List<GameObject>(); //用来存放生产的对象 /// <summary> /// 创建对象 /// </summary> /// <param name="count">创建的数量</param> /// <returns></returns> public List<GameObject> CreateObject (int count) { //用来接收创建的对象列表 List<GameObject> tempObject = new List<GameObject>(); //循环创建 for (int i = 0; i < count; i ++) { //接收单个对象 GameObject go = Instantiate(cube); //默认设置不显示 go.SetActive(false); //设置父物体 go.transform.parent = parent; //添加到临时列表 tempObject.Add(go); } //把创建好的对象全部添加到对象列表中 poolList.AddRange(tempObject); return tempObject; } /// <summary> /// 得到对象 /// </summary> /// <param name="count">要得到的数量</param> /// <returns></returns> public List<GameObject> GetObject (int count) { //返回所有 对象列表 poolList 中的未激活的对象 List<GameObject> tempObject = poolList.FindAll(g => !g.activeSelf); //如果需要得到的数量大于未激活的数量 if (count > tempObject.Count) { //创建不足的对象 List<GameObject> newTempObject = CreateObject(count - tempObject.Count); //把创建的不足的对象添加到临时对象列表 tempObject.AddRange(newTempObject); //循环把需要得到的对象设为显示 foreach (var gg in tempObject) { gg.SetActive(true); } return tempObject; } //如果需要的数量不大于对象列表中的未激活的对象 直接返回临时对象列表 else { return tempObject; } } /// <summary> /// 销毁对象 /// </summary> /// <param name="destroyGo">要销毁的列表</param> public void DestroyObject (List<GameObject> destroyGo) { //循环设置为不显示 foreach (GameObject gg in destroyGo) { gg.SetActive(false); } } }
然后再写一个 TestPool 脚本给摄像机添加:
using UnityEngine; using System.Collections; using System.Collections.Generic; public class TestPool : MonoBehaviour { public GameObject cube; //要创建的对象 public Transform parent; //父物体 public SimplePool simplePool; public int loopCount; //循环次数 List<GameObject> testList = new List<GameObject>(); //存放创建的对象 // Use this for initialization void Start () { //得到现在的系统时间作为开始时间 System.DateTime startTime = System.DateTime.Now; TestCreate(loopCount, simplePool.poolSize); TestDestroy(testList); System.DateTime endTime = System.DateTime.Now; //输出调用方法所用的时长 Debug.Log("不用对象池使用的时长为:" + (endTime - startTime).TotalMilliseconds + ".ms"); System.DateTime startTime2 = System.DateTime.Now; TestPoolScripts(loopCount, simplePool.poolSize); System.DateTime endTime2 = System.DateTime.Now; //输出调用方法所用的时长 Debug.Log("使用对象池使用的时长为:" + (endTime2 - startTime2).TotalMilliseconds + ".ms"); } /// <summary> /// 测试方法,测试同时创建 n 个对象 /// </summary> /// /// <param name="loopCount">循环次数</param> /// <param name="count">每次生成的数量</param> void TestCreate (int loopCount, int count) { for (int i = 0; i < loopCount; i ++) { for (int j = 0; j < count; j++) { GameObject go = Instantiate(cube); go.transform.parent = parent; testList.Add(go); } } } /// <summary> /// 销毁独享 /// </summary> /// <param name="destroyGO">要销毁的列表</param> void TestDestroy (List<GameObject> destroyGO) { for (int i = 0; i < destroyGO.Count; i ++) { Destroy(destroyGO[i]); } } /// <summary> /// 使用对象池 /// </summary> /// /// <param name="loopCount">循环次数</param> /// <param name="count">每次生成的数量</param> void TestPoolScripts (int loopCount, int count) { for (int i = 0; i < loopCount; i++) { List<GameObject> t = simplePool.GetObject(count); simplePool.DestroyObject(t); } } }
最后设置好相应的参数:
然后运行程序 ;
我们可以看见差距是非常大的,差不多有8倍之大。
最后,我写的那个还只是简单的对象池脚本,更复杂的我目前也不会,但是,现在这个应该也能在平时练习中进行使用,大家可以把它当作模板进行适当的修改,就可以修改成自己的版本了。
工程地址:http://pan.baidu.com/s/1i49XsG1 密码:wa3g
本博客用作新手学习讨论,如有不好或错误的地方也请指出来,谢谢。
相关文章推荐
- Python动态类型的学习---引用的理解
- 土人系列AS入门教程 -- 对象篇
- IE7降低内存和降低CPU的几个技巧
- C#托管堆对象实例包含内容分析
- 如何高效的使用内存
- DOS下内存的配置
- C#实现获取不同对象中名称相同属性的方法
- XP/win2003下发现1G的内存比512M还慢的解决方法
- javascript asp教程第十一课--Application 对象
- PowerShell中使用Out-String命令把对象转换成字符串输出的例子
- PowerShell实现动态获取当前脚本运行时消耗的内存
- VBS教程:对象-正则表达式(RegExp)对象
- C#实现把dgv里的数据完整的复制到一张内存表的方法
- SQL语句实现查询SQL Server内存使用状况
- C#检查指定对象是否存在于ArrayList集合中的方法
- sql2008启动代理未将对象应用到实例解决方案
- C#编程自学之类和对象
- C语言内存对齐实例详解
- C++中对象的常引用、动态建立和释放相关知识讲解
- 深入学习C语言中memset()函数的用法