前几天我在博客里面分享了为什么Unity实例化很慢的原因,并且也分享了一个缓存池的工具。有朋友给我留言说PoolManager插件非常好用,我抽空研究了一下确实很好用。PoolManager目前的最新版本是5.5.2 我有幸在网络上找到了破解版本,文章最后我会放出来不过还是希望大家支持正版嘿嘿。
PoolManager5 介绍: https://www.assetstore.unity3d.com/en/#!/content/1010
为什么Unity实例化对象慢的原因请看我之前的文章 http://www.xuanyusong.com/archives/2925
缓存池我们主要关注的几个事情 1.怎么把游戏对象保存进缓存池 2.怎么把游戏对象从缓存池里面去出来 3.如何智能删除缓存池。很期待,因为PoolManager都满足了这几个需求。如下图所示,创建一个空的GameObjcet 接着把Spawn Pool脚本绑上去。
PoolName:缓存池的唯一名称。
MatchPoolScale:勾选后实例化的游戏对象的缩放比例将全是1,不勾选择用Prefab默认的。
MachPool Layer:勾选后实例化的游戏对象的Layer将用Prefab默认的。
Don’t Reparent:勾选后实例化的对象将没有父节点,通通在最上层,建议不要勾选。
Don’t Destroy On Load:这个就不用我解释了吧?切换场景不施放。
Pre-Prefab Pool Options :缓存池列表,意思就是缓存列表里面可以放各种类型的Prefab。右边有个 “+”按钮点击就添加每个类型的Prefab了,后面会介绍脚本怎么动态添加。
prefab:可以直接把工程里的Prefab直接拖进来。
preloadAmount:缓存池这个Prefab的最大保存数量。
preloadTime:如果都选表示缓存池所有的gameobject可以“异步”加载。
preloadFrames:每几帧加载一个。
preloadDelay:延迟多就开始加载。
limitInstance:是否开始实例的限制功能。
limit Amount:限制缓存池里最大的Prefab的数量,它和上面的preloadAmount是有冲突的,如果同时开启则以limitAmout为准。
limitFIFO:如果我们限制了缓存池里面只能有10个Prefab,如果不勾选它,那么你拿第11个的时候就会返回null。如果勾选它在取第11个的时候他会返回给你前10个里最不常用的那个。
cullDespawend:是否开启缓存池智能自动清理模式。
cull Above:缓存池自动清理,但是始终保留几个对象不清理。
cull Delay:每过多久执行一遍自动清理,单位是秒。
cullMaxPerPass:每次自动清理几个游戏对象。
补充一下,这里我们说的自动清理,就是当池子里面的对象setActive(false)也就是目前不用的时候,poolManager会根据上述参数自动清理这些对象,清理也就是Destroy()掉。
上面我详细的把PoolManager核心的参数统统介绍了一遍。上面的做法我们是在游戏运行前提前去初始化已知的游戏对象,可是实际游戏中往往我们需要动态的去载入一些无法提前预知的游戏对象,所以初始化内存池的操作我建议还是在脚本里面来完成。
如下图所示,我们在Hierarchy视图里面就创建一个PoolManager对象,上面挂上SpawnPool脚本,标记它为Don’tDestroyOnLoad状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
using UnityEngine; using System.Collections; using PathologicalGames; public class NewBehaviourScript : MonoBehaviour { SpawnPool spawnPool; PrefabPool refabPool; void Start() { spawnPool = PoolManager.Pools["Shapes"]; refabPool = new PrefabPool(Resources.Load<Transform>("momo")); } void OnGUI() { if(GUILayout.Button("初始化内存池")) { if(!spawnPool._perPrefabPoolOptions.Contains(refabPool)) { refabPool = new PrefabPool(Resources.Load<Transform>("momo")); //默认初始化两个Prefab refabPool.preloadAmount = 2; //开启限制 refabPool.limitInstances = true; //关闭无限取Prefab refabPool.limitFIFO = false; //限制池子里最大的Prefab数量 refabPool.limitAmount =5; //开启自动清理池子 refabPool.cullDespawned = true; //最终保留 refabPool.cullAbove = 10; //多久清理一次 refabPool.cullDelay = 5; //每次清理几个 refabPool.cullMaxPerPass =5; //初始化内存池 spawnPool._perPrefabPoolOptions.Add(refabPool); spawnPool.CreatePrefabPool(spawnPool._perPrefabPoolOptions[spawnPool.Count]); } } if(GUILayout.Button("从内存池里面取对象")) { ///从内存池里面取一个GameObjcet Transform momo = spawnPool.Spawn("momo"); } if(GUILayout.Button("清空内存池")) { //清空池子 spawnPool.DespawnAll(); } } } |
spawnPool.Despawn() 可以单独从池子里面清空某一个Prefab。
spawnPool.Insert() 还可以插入在池子里面某个序列上。
最后是完整的游戏代码,并且包括PoolManager5的插件。 大家来下载吧。
http://pan.baidu.com/s/1gdEG7dx
- 本文固定链接: https://www.xuanyusong.com/archives/2974
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
这部分源码我仔细看了下,感觉preloadFrames这个参数就不是 每几帧加载一个的意思啊,下面这部分代码,明明是每帧加载一个,而且是分成几次循环来完成的,完全不知道有什么意义,是我理解有问题么,希望momo大大不吝赐教! private IEnumerator PreloadOverTime() { yield return new WaitForSeconds(this.preloadDelay); Transform inst; // subtract anything spawned by other scripts, just in case int amount = this.preloadAmount – this.totalCount; if (amount <= 0) yield break; // Doesn’t work for Windows8… // This does the division and sets the remainder as an out value. //int numPerFrame = System.Math.DivRem(amount, this.preloadFrames, out remainder); int remainder = amount % this.preloadFrames; int numPerFrame = amount / this.preloadFrames; // Reduce debug spam: Turn off this.logMessages then set it back when done. this.forceLoggingSilent = true; int numThisFrame; for (int i = 0; i < this.preloadFrames; i ) { // Add the remainder to the *last* frame numThisFrame = numPerFrame; if (i == this.preloadFrames – 1) { numThisFrame = remainder; } for (int n = 0; n < numThisFrame; n ) { // Preload… // This will parent, position and orient the instance // under the SpawnPool.group inst = this.SpawnNew(); if (inst != null) this.DespawnInstance(inst, false); yield return null; } // Safety check in case something else is making instances. // Quit early if done early if (this.totalCount > this.preloadAmount) break; } // Restore the previous setting this.forceLoggingSilent = false; }
这部分源码我仔细看了下,感觉preloadFrames这个参数就不是 每几帧加载一个的意思啊,下面这部分代码,明明是每帧加载一个,而且是分成几次循环来完成的,完全不知道有什么意义,是我理解有问题么,希望momo大大不吝赐教! private IEnumerator PreloadOverTime() { yield return new WaitForSeconds(this.preloadDelay); Transform inst; // subtract anything spawned by other scripts, just in case int amount = this.preloadAmount – this.totalCount; if (amount <= 0) yield break; // Doesn’t work for Windows8… // This does the division and sets the remainder as an out value. //int numPerFrame = System.Math.DivRem(amount, this.preloadFrames, out remainder); int remainder = amount % this.preloadFrames; int numPerFrame = amount / this.preloadFrames; // Reduce debug spam: Turn off this.logMessages then set it back when done. this.forceLoggingSilent = true; int numThisFrame; for (int i = 0; i < this.preloadFrames; i++) { // Add the remainder to the *last* frame numThisFrame = numPerFrame; if (i == this.preloadFrames – 1) { numThisFrame += remainder; } for (int n = 0; n < numThisFrame; n++) { // Preload… // This will parent, position and orient the instance // under the SpawnPool.group inst = this.SpawnNew(); if (inst != null) this.DespawnInstance(inst, false); yield return null; } // Safety check in case something else is making instances. // Quit early if done early if (this.totalCount > this.preloadAmount) break; } // Restore the previous setting this.forceLoggingSilent = false; }
我也不用这个插件了。。 pool其实没多少代码, 自己实现一个就OK
哦,好吧,谢谢,实际我也没用这个插件,只是想看看源码,看看别人的思路。
https://github.com/ihaiucom/ihaiu.PoolManager我在Unity PoolManager基础上改的。可以对普通Class 缓存。欢迎使用,如有改良想法求分享。
https://raw.githubusercontent.com/ihaiucom/ihaiu.PoolManager/master/PoolManager/Assets/Ihaiu/doc/IhaiuPoolManager.pdf简单的API文档
preload部分有错误,按本文例子应该是:最多两帧能加载完50个实例,1分钟之后开始加载。 请看http://docs.poolmanager.path-o-logical.com/home/per-prefab-options
momo你好,我想做到的是Spawn多个包含动画的Object,每一个在动画播放完毕之后被销毁。然后我在动画结束后将其设为Inactive,但是好像不能自动帮我清理啊。于是我只好在动画播放完毕后手动调用Despawn函数,可是这不就和Destroy没区别嘛。该怎么解决呢?
momo,用完的对象有没有试过用Despawn放回到池中?我总是感觉这重新放回到池中的对象再拿出来还是和全新的不一样。你再实际使用中有没有用过Despawn放回池的操作?
现在内存池都自己来写了,。
那你自己写的池 也是只能把简单对象放回池中准备下次用吧。 并不能将复杂的对象还原成全新的状态吧?
通过Recource.Load加载的spine 无法被真正的释放掉,即使跨场景也还是在内存里面而AssetBundle加载的也有点问题松神遇到过没?
Resources.UnloadUnusedAssets()
最近在研究这个插件, 出了个问题:重用之前Item的时候, 在Scrollview 中拖拽的时候 scrollview 的clip功能对Item中的icon失效, 也就是说超过scrollview范围后 还是能看到item的icon… 请问楼主有遇到这样的情况没, 不知道如何下手解决这个bug
using PathologicalGames;这句怎么出错,找不到
我也引这个包出错,但是程序能正常运行,咋整?
同MonoDevelop提示出错,但是U3D并没有报错怎么回事、、、
mo神,这个能搞web么,Prefab的数目有没有什么限制
又想用 但是觉得使用了插件自己其实什么都不明白
下载下来的PoolManager5.package包含中文,无法解压!
解压路径不能包含中文!
大神:refabPool = new PrefabPool(Resources.Load(“momo”)); 在WIN7 4.2.1下怎么有错误呢?
不知道为什么总是获取资源会报错,如果直接拖进面板里就可以。。。不解
spawnPool = PoolManager.Pools[“Shapes”]; 这一个池子中只能放一种prefab?
做跑酷的时候 自己代码里面实现过这么个东西,刚看到还有这么个东西 ,
前两天正好下载了这个插件,可以跟着鱼松大大的脚步学习下了~~嚯嚯
兄弟在那里下载的呀!能给个链接吗?
第一次坐沙发 嘿嘿 最近在做跑酷无限场景正好可以用到这个 陌神~
问下啊!池不是解决相同prefab问题的吗? 跑酷难道不是prefab不同拼接到一起的吗?
哦 看上面的回答解决了。。原来一个池子里可以放不同的预制件!666