*更新日期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 ♥:
張貼留言