在游戲開發過程中,我們經常會遇到游戲發布后,測試時玩着玩着明顯的感覺到有卡頓現象。出現這種現象的有兩個原因:一是游戲優化的不夠好或者游戲邏輯本身設計的就有問題,二是手機硬件不行。好吧,對於作為程序員的我們只能從第一個原因着手了,那就開始對着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