Unity簡單物件緩衝池技術
阿新 • • 發佈:2018-11-07
一、建立物件緩衝池指令碼
/*** * * Title: * 預載入與物件緩衝池技術 * * 物件緩衝池管理器 * * Description: * 基本原理: * 通過池管理思路,在遊戲初始化的時候,生成一個初始的池存放我們要複用的元素。 * 當要用到遊戲物件時,從池中取出;不再需要的時候,不直接刪除物件而是把物件重新回收到“池”中。 * 這樣就避免了對記憶體中大量物件的反覆例項化與回收垃圾處理,提高了資源的利用率。 * * Date: 2018 * * Version: 1.0 * * Modify Recorder: * */ using UnityEngine; using System.Collections.Generic; public class ObjectPoolManager : MonoBehaviour{ public GameObject ObjPrefab; //池中所使用的元素預設 public Transform TranObjPrefabParent; //池中所使用的元素預設的父物件 public int InitialCapacity; //初始容量 private int _startCapacityIndex; //初始下標 private List<int> _avaliableIndex; //可用“池”遊戲物件下標 private Dictionary<int, GameObject> _totalObjList; //池中全部元素的容器 /// <summary> /// 初始化緩衝池 /// </summary> void Awake(){ _avaliableIndex = new List<int>(InitialCapacity); _totalObjList = new Dictionary<int, GameObject>(InitialCapacity); //初始化池 expandPool(); } /// <summary> /// 取得遊戲物件。 /// </summary> /// <returns></returns> public KeyValuePair<int, GameObject> PickObj(){ //容量不夠,進行“池”擴充套件 if (_avaliableIndex.Count == 0) expandPool(); //取得一個可用的池下標數值 int id = _avaliableIndex[0]; //“可用池下標”集合,刪除對應下標 _avaliableIndex.Remove(id); //設定“池”物件可用。 _totalObjList[id].SetActive(true); //從“池”中提取一個物件返回。 return new KeyValuePair<int, GameObject>(id, _totalObjList[id]); } /// <summary> /// 回收遊戲物件 /// </summary> /// <param name="id"></param> public void RecyleObj(int id) { //設定對應物件不可用(即:放回池操作) _totalObjList[id].SetActive(false); //指定Id的遊戲物件下標,重行進入可用“池”下標集合中 _avaliableIndex.Add(id); } /// <summary> /// 擴充套件池 /// </summary> private void expandPool(){ int start = _startCapacityIndex; int end = _startCapacityIndex + InitialCapacity; for (int i = start; i < end; i++){ //加入驗證判斷,避免在多個請求同時觸發擴充套件池需求 if (_totalObjList.ContainsKey(i)) continue; GameObject newObj = Instantiate(ObjPrefab) as GameObject; //生成的池物件增加父物件,容易檢視與檢查。 newObj.transform.parent = TranObjPrefabParent.transform; //每一個生成的物件,設定暫時不可用。 newObj.SetActive(false); //下標記入“池”可用下標集合中。 _avaliableIndex.Add(i); //新產生的物件,併入本池容器集合中。 _totalObjList.Add(i, newObj); } //擴充套件“初始下標”。 _startCapacityIndex = end; } }//Class_end
二、給池中的預設物件添加回收指令碼
/*** * * Title: * 預載入與物件緩衝池技術 * * Description: * 功能: * 回收物件指令碼 * * Date: 2018 * * Version: 1.0 * * Modify Recorder: * */ using UnityEngine; using System.Collections; public class DestroyObjUseBufferPool : MonoBehaviour { public GameObject GoPoolManager; //池管理器 private ObjectPoolManager _PoolManagerObj; //物件池管理器 private int _IntBulletID = 0; //子彈ID編號 void Start() { _PoolManagerObj = GoPoolManager.GetComponent<ObjectPoolManager>(); } /// <summary> /// 遊戲物件超出攝像機可視範圍,則此物件進行“回收”。 /// </summary> void OnBecameInvisible() { _PoolManagerObj.RecyleObj(_IntBulletID); } /// <summary> /// 接收本指令碼所屬物件的ID編號,用於回收使用。 /// </summary> /// <param name="intBulleteNumber"></param> public void ReceiveBulletID(int intBulleteNumber) { _IntBulletID = intBulleteNumber; } }
三、編寫好物件緩衝池的內容之後就需要配合專案使用(以射擊專案為例)
/*** * * Title: * 預載入與物件緩衝池技術 * * Description: * 功能: * 學習“物件緩衝池”技術 * 利用緩衝池實現射擊程式碼 * * Date: 2018 * * Version: 1.0 * * Modify Recorder: * */ using UnityEngine; using System.Collections; using System.Collections.Generic; public class ShottingUseBufferPool : MonoBehaviour{ public Texture Texture_ShootingCursor; //射擊瞄準星 public GameObject G0_CubeOrigianl; //射擊原型物體 public Transform Tran_TargetWallParentPosition; //靶牆陣列父物件 public Transform Tran_BulletParentPosition; //子彈陣列父物件 private Vector3 _VecRayPosion; //射線透射的座標 public GameObject GoPoolManager; //池管理器 public GameObject GoBulletPrefabsOriginal; //子彈原型(預設) private ObjectPoolManager boPoolManager; //池管理器物件 private GameObject goCloneBullete; //克隆的子彈 /// <summary> /// 初始化場景 /// </summary> void Start(){ //隱藏滑鼠。 Cursor.visible = false; //取得池管理器 boPoolManager = GoPoolManager.GetComponent<ObjectPoolManager>(); //建立射擊目標靶牆 for (int j = 1; j <= 5; j++) { for (int i = 1; i <= 5; i++) { GameObject goClone = (GameObject)Instantiate(G0_CubeOrigianl); goClone.transform.position = new Vector3(G0_CubeOrigianl.transform.position.x + i, G0_CubeOrigianl.transform.position.y + j, G0_CubeOrigianl.transform.position.z); //確定子彈的父物件 goClone.transform.parent = Tran_TargetWallParentPosition; } } }//Start_end /// <summary> /// 繪製射擊游標 /// </summary> void OnGUI(){ Vector3 vecPos = Input.mousePosition; GUI.DrawTexture(new Rect(vecPos.x - Texture_ShootingCursor.width / 2, Screen.height - vecPos.y - Texture_ShootingCursor.height / 2, Texture_ShootingCursor.width, Texture_ShootingCursor.height), Texture_ShootingCursor); }//OnGUI_end /// <summary> /// 射擊邏輯處理 /// </summary> void Update(){ //射線處理 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { //獲取射線碰撞到碰撞體的方位 _VecRayPosion = hit.point; } //如果滑鼠點選左鍵,則發射子彈。 if (Input.GetMouseButtonDown(0)){ //建立子彈 KeyValuePair<int, GameObject> kvObj = boPoolManager.PickObj(); if (kvObj.Value != null){ goCloneBullete = kvObj.Value; goCloneBullete.SendMessage("ReceiveBulletID", kvObj.Key); } //新增子彈剛體 if (!goCloneBullete.GetComponent<Rigidbody>()){ goCloneBullete.AddComponent<Rigidbody>(); } //子彈的位置 goCloneBullete.transform.position = new Vector3(Camera.main.transform.position.x, Camera.main.transform.position.y, Camera.main.transform.position.z + 0.3F); //給子彈加“力” goCloneBullete.GetComponent<Rigidbody>().AddForce((_VecRayPosion - goCloneBullete.transform.position) * 10F, ForceMode.Impulse); } }//Update_end }//Class_end
注意:該內容來自《Unity3D/2D遊戲開發從0到1》27章