*更新日期2015/06/13
物件池是一個有效率且節省資源的用法。這個範例是一個簡易的物件池系統,並有參數可以控制。
他可以在載入場景時就預先實體化物件,而不是在需要實體化物件時才Instantiate,這會造成在實體物件時導致系統要與顯示卡同步所產生的LAG情況。
也可以減少物件一直被Destory再次Instantiate物件。在GC還沒啟動時,持續造成記憶體肥大與效能上的浪費。
使用方法與配置圖
1.ObjectDeck:存放要被實體化的物件(Perfab)
2.Pool:存放物件池的位置(一定要指定)
3-1.初始數量:載入場景就會實體化的固定數量。
3-2.清理上限:達到這個上限值物件池將會清理物件。
3-3.清理時間:等待X秒,並達到物件池清理上限,才會清理。
3-4.保留數量:物件池清理後,會保留下來的物件數量。
4.SpawnHere:這是要產生的位置。可以自行任意配置,不一定要照本篇這樣使用。
using UnityEngine; using System.Collections.Generic; using System.Linq; /* *************************************************************** * -----Copyright © 2015 Gansol Studio. All Rights Reserved.----- * ----------- CC BY-NC-SA 4.0 ------------- * ----------- @Website: EasyUnity@blogspot.com ------------- * ----------- @Email: GansolTW@gmail.com ------------- * ----------- @Author: Krola. ------------- * *************************************************************** * Description * *************************************************************** * * 物件池 提供一個高效率的物件生成、回收方式 * 支援多種物件的物件池 * 每種物件的數量控制是固定的(個別不同數量請自行修改) * * ***************************************************************/ public class PoolManager : MonoBehaviour { private Dictionary<string, object> _tmpDict; private Dictionary<int, string> _dictObject; private GameObject clone; private byte objectID; // 取得的ID 須自行改寫 private string objectName; // 取得的 物件名稱 private float _lastTime; private float _currentTime; [Tooltip("物件池位置")] public GameObject Pool; [Tooltip("物件匣")] public GameObject[] ObjectDeck; [Tooltip("產生數量")] public int spawnCount = 5; [Tooltip("物件池上限(各種類分開)")] public int clearLimit = 5; [Tooltip("物件池上限(各種類分開)")] public int clearTime = 10; [Tooltip("物件池保留量(各種類分開)")] public int reserveCount = 2; private bool _poolingFlag = false; // 初始化物件池 public bool poolingFlag { get { return _poolingFlag; } } void Awake() { _lastTime = 0; _currentTime = 0; clearTime = 10; _poolingFlag = false; // 初始化物件池 _dictObject = new Dictionary<int, string>(); _tmpDict = new Dictionary<string, object>(); Debug.Log(ObjectDeck.Length); // 加入字典 for (int item=0;item < ObjectDeck.Length;item++) { _dictObject.Add(item, ObjectDeck[item].name); } // 生出 預設數量的物件 foreach (KeyValuePair<int, string> item in _dictObject) { clone = new GameObject(); clone.name = item.Value; clone.transform.parent = Pool.transform; clone.layer = clone.transform.parent.gameObject.layer; clone.transform.localScale = Vector3.one; for (int i = 0; i < spawnCount; i++) { clone = (GameObject)Instantiate(ObjectDeck[item.Key]); // 等傳老鼠ID名稱近來這要改 clone.name = item.Value; clone.transform.parent = Pool.transform.FindChild(item.Value).transform; clone.transform.localScale = Vector3.one; clone.transform.gameObject.SetActive(false); // 新版 子物件隱藏 } } Debug.Log("pooling Completed ! "); _poolingFlag = true; } // 每一次顯示一個GameObject。如果GameObject不足,Spawn一個物件並顯示。 // 回傳 ( GameObject / null ) public GameObject ActiveObject(int objectID) { _dictObject.TryGetValue(objectID, out objectName);//等傳老鼠ID名稱近來這要改miceName if (Pool.transform.FindChild(objectName).childCount == 0) { clone = (GameObject)Instantiate(ObjectDeck[objectID], Vector3.zero, Quaternion.identity); clone.name = objectName; clone.transform.parent = Pool.transform.FindChild(objectName).transform; clone.transform.localScale = Vector3.one; return clone; } for (int i = 0; i < Pool.transform.FindChild(objectName).childCount; i++) { GameObject obj; obj = Pool.transform.FindChild(objectName).GetChild(i).gameObject; if (obj.name == objectName && !obj.transform.gameObject.activeSelf) { obj.transform.gameObject.SetActive(true); return obj; } } return null; } // 每一次顯示一個GameObject。如果GameObject不足,Spawn一個物件並顯示。 //回傳 ( GameObject / null ) public GameObject ActiveObject(string objectName) { int objectID = _dictObject.FirstOrDefault(x => x.Value == objectName).Key; // 找Key if (Pool.transform.FindChild(objectName).childCount == 0) { clone = (GameObject)Instantiate(ObjectDeck[objectID], Vector3.zero, Quaternion.identity); clone.name = objectName; clone.transform.parent = Pool.transform.FindChild(objectName).transform; clone.transform.localScale = Vector3.one; return clone; } for (int i = 0; i < Pool.transform.FindChild(objectName).childCount; i++) { GameObject obj; obj = Pool.transform.FindChild(objectName).GetChild(i).gameObject; if (obj.name == objectName && !obj.transform.gameObject.activeSelf) { obj.transform.gameObject.SetActive(true); return obj; } } return null; } void Update() { _currentTime = Time.time; if (_currentTime - _lastTime > clearTime) // 達到清除時間時 { for (int i = 0; i < Pool.transform.childCount; i++) // 跑遍動態池 { if (Pool.transform.GetChild(i).childCount > clearLimit) // 如果動態池超過限制數量 { for (int j = 0; j < Pool.transform.GetChild(i).childCount - reserveCount; j++) // 銷毀物件 { Destroy(Pool.transform.GetChild(i).GetChild(j).gameObject); } } } _lastTime = _currentTime; } } }
using UnityEngine; using System.Collections; using System.Collections.Generic; public class TEST : MonoBehaviour { public GameObject spawnHere; // 這是要把物件 Active的位置(你可以放到任何地方) PoolManager poolManager; GameObject clone; // 暫存clone物件 GameObject[] tmpObject; // 暫存物件 bool flag; void Start() { flag = true; tmpObject = new GameObject[10]; poolManager = GetComponent<PoolManager>(); } void Update() { if (poolManager.poolingFlag && flag) // 如果物件池 初始化完成 (注意:poolManager.poolingFlag = true 時才可以使用物件池) { flag = false; Debug.Log("Active Object!"); clone = (GameObject)poolManager.ActiveObject(0); // 啟動物件Cat clone.transform.parent = spawnHere.transform; clone.transform.localPosition = Vector3.zero; // 生10個會超過物件池基本數量 就會在實體化新的物件出來 for (int i = 0; i < 10; i++) { clone = (GameObject)poolManager.ActiveObject(0); // 啟動物件Cat clone.transform.parent = spawnHere.transform; clone.transform.localPosition =new Vector3(i,i,i); tmpObject[i] = clone; // 暫存物件 等等用來示範丟回物件池 } clone = (GameObject)poolManager.ActiveObject(1); // 啟動物件Rabbit clone.transform.parent = spawnHere.transform; clone.transform.localPosition = Vector3.one; } } void OnGUI() { if (GUI.Button(new Rect(100, 100, 100, 100), "Recover")) { for (int i = 0; i < 10; i++) { clone = tmpObject[i]; clone.transform.parent = poolManager.Pool.transform.FindChild(clone.name); // 把物件 丟回物件池 clone.SetActive(false); // 並讓他看不見 } // 經過 一段時間(可自訂) 物件池會清理掉多的物件 並保留(可自訂數量) 的物件 } } }
0 ♥:
張貼留言