在游戏开发过程中,我们经常会遇到游戏发布后,测试时玩着玩着明显的感觉到有卡顿现象。出现这种现象的有两个原因:一是游戏优化的不够好或者游戏逻辑本身设计的就有问题,二是手机硬件不行。好吧,对于作为程序员的我们只能从第一个原因着手了,那就开始对着Profiler看性能开销,接下来就开始做各种内存,特效,代码上的优化了。对于这种问题,有经验的开发者在一开始就会做一个规范的设计,就我们的项目而言,设计时包含了角色池,怪物池,特效池,经验池,伤害池......所谓的对象池就是尽可能的复用内存中已经驻留的资源来减少频繁的IO耗时操作。使用对象池可以很好的解决内存上的压力,但是我们自己要维护好池中对象的状态。就粒子特效而言,当粒子特效释放后我们要对它Reset到初始状态,这样才能保证每次释放出的特效播放是正常的。好了,废话不多说了,开始一个简单的小例子,就拿我在项目中做的伤害和经验飘字为例。说到这个伤害和经验飘字,尤其是在MMO或者ARPG游戏中太常见了,进入自动战斗后,服务器会频繁的告诉客户端打怪耗了多少血获得了多少经验所以客户端要做的表现是很频繁的。我们不可能根据收到服务器的消息立刻去实例和销毁对应的飘字吧?这样还有一个问题,由于网络消息太快了,客户端不做处理的话一坨就叠加到一块了,,,我们自己都看不先去何况玩家呢?对于这个处理上,我选择使用一个队列,将服务器下发的消息分类入队,开一个协程去处理队列的信息同时控制好处理间隔时间,实例化的飘字预制放到经验池中,复用池中空闲的对象。简单的经验池,开始撸代码。
1,建一个简单的界面
2,我们先创建一个对象池
创建简单吧,接下来取到这个池的对象。
ExpPool = PoolManager.Pools["ExpPool"];
向池子中添加我们要复用的对象,例如粒子,模型,音频,,,等等。怎么添加呢?
ExpPool = PoolManager.Pools["ExpPool"];//获取对象池 if (!ExpPool._perPrefabPoolOptions.Contains(prefabPool)) { prefabPool = new PrefabPool(Resources.Load<Transform>("LabExp"));//加载本地预制 //默认初始化一个Prefab prefabPool.preloadAmount = 1; //开启限制 prefabPool.limitInstances = true; //关闭无限取Prefab prefabPool.limitFIFO = false; //限制池子里最大的Prefab数量 prefabPool.limitAmount = 10; //开启自动清理池子 prefabPool.cullDespawned = true; //最终保留 prefabPool.cullAbove = 10; //多久清理一次 prefabPool.cullDelay = 5; //每次清理几个 prefabPool.cullMaxPerPass = 5; //初始化内存池 ExpPool._perPrefabPoolOptions.Add(prefabPool);//添加到池中 ExpPool.CreatePrefabPool(ExpPool._perPrefabPoolOptions[ExpPool.Count]); } else { Debug.Log("Already in prefabPool!"); }
3,添加完成了,那么接下来该去对象池中取对象了。
Transform labExp = ExpPool.Spawn("LabExp");
此处LabExp是加入到对象池的对象名称,也就是我本地经验飘字预制的名称。
4,最后一步对象状态初始化。
IEnumerator ResetPrefab(Transform obj) { yield return new WaitForSeconds(2f); obj.GetComponent<TweenPosition>().ResetToBeginning(); obj.GetComponent<TweenScale>().ResetToBeginning(); obj.GetComponent<TweenAlpha>().ResetToBeginning(); ExpPool.Despawn(obj); }
将使用过后的对象还原到开始状态,好了,一个简单的对象池可以使用了!
对了还有重要的一步:记得给对象池的父节点加上一个Panel,这样不会影响的其他界面组建的重绘。
PS:如果本文写的有不正确的地方记得@我,共同学习!
工程地址:https://github.com/wuzhangwuzhang/ExpPoolManager.git