前言
游戲中骡湖,經(jīng)常會大量頻繁的創(chuàng)建、銷毀游戲?qū)ο螅ㄗ訌棥R血粒子特效等)咐旧,這會帶來一定的性能開銷,此時绩蜻,我們可以利用對象池技術(shù)來優(yōu)化.
實現(xiàn)對象池的步驟
1. 首先铣墨,使用一個數(shù)據(jù)結(jié)構(gòu)直接存儲對象,為了降低裝箱办绝、拆箱操作伊约,使用List<GameObject>來存儲姚淆。
2. 其次,使用字典Dictionary<string,List<GameObject>>來存儲多個對象屡律。
3. 然后腌逢,從對象池中提取對象,如果對象池中已經(jīng)存在超埋,則激活該對象搏讶,并且從List集合中移除,否則霍殴,創(chuàng)建新的對象(OutPool方法實現(xiàn)該功能)媒惕。
4. 最后,將不用的對象再加入到對象池繁成,加入之前吓笙,先判斷該對象對應(yīng)的鍵是否已經(jīng)存在,如果存在巾腕,就直接添加進(jìn)對應(yīng)鍵的值中面睛,否則,創(chuàng)建新的鍵值對尊搬。(JoinPool方法實現(xiàn)該功能)
代碼
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// 對象池單例類
/// </summary>
public class ObjectPoolSingleton
{
//存儲多個對象(存儲一個也可以哦)
//使用字典存儲對象名與對象
//1叁鉴、鍵用的字符串,保存對象的名字佛寿,可以通過名字來從Resources文件夾動態(tài)加載資源
//2幌墓、用泛型集合直接存儲對象,降低裝箱冀泻、拆箱次數(shù)
private Dictionary<string, List<GameObject>> pools;
#region 單例
private static ObjectPoolSingleton instance;
private ObjectPoolSingleton()
{
//初始化對象池
pools = new Dictionary<string, List<GameObject>>();
}
public static ObjectPoolSingleton Instance
{
get { return instance = instance ?? new ObjectPoolSingleton(); }
}
#endregion
/// <summary>
/// 出對象池(激活對象)
/// </summary>
/// <param name="objName">對象的名稱</param>
/// <param name="pos">位置</param>
/// <param name="qua">旋轉(zhuǎn)</param>
/// <returns></returns>
public GameObject OutPool(string objName, Vector3 pos, Quaternion qua)
{
//首先根據(jù)名稱判斷字典里有沒有該對象
if (pools.ContainsKey(objName))
{
//有,再判斷個數(shù)(想想常侣,為什么要判斷個數(shù),難道還會為0弹渔?)
if (pools[objName].Count > 0)
{
//獲得第集合第一個對象
GameObject currentObj = pools[objName][0];
//提取了胳施,就應(yīng)該將其從集合中移除
pools[objName].Remove(currentObj);
//激活該對象
currentObj.SetActive(true);
//初始化該對象的位置、旋轉(zhuǎn)信息
currentObj.transform.position = pos;
currentObj.transform.rotation = qua;
return currentObj;
}
}
//沒有肢专,怎么辦呢舞肆,創(chuàng)建一個,我們這里是用Resources動態(tài)加載要實例化的對象
GameObject newObj = GameObject.Instantiate(Resources.Load<GameObject>(objName), pos, qua) as GameObject;
return newObj;
}
/// <summary>
/// 進(jìn)對象池
/// </summary>
/// <param name="obj">要加入的對象</param>
public void JoinPool(GameObject obj)
{
//隱藏對象
obj.SetActive(false);
//去掉對象名稱后的‘(Clone)’
string objName = obj.name.Substring(0, obj.name.Length - 7);
//首先判斷字典中是否已經(jīng)有了該對象
if (pools.ContainsKey(objName))
{
//有了,就添加到對應(yīng)鍵的集合里
pools[objName].Add(obj);
}
else
{
//沒有,添加新的鍵值對
pools.Add(objName, new List<GameObject>() {obj});
}
}
}
該腳本可以添加到創(chuàng)建的空物體身上博杖,注意游戲場景中必須要有帶有碰撞器的對象存在椿胯,不然,射線射誰呢剃根?
測試代碼
using UnityEngine;
using System.Collections;
//游戲控制腳本哩盲,可以添加到創(chuàng)建的空物體身上
public class GameController : MonoBehaviour
{
void Update()
{
if (Input.GetMouseButtonDown(0))
{
//從攝像機(jī)發(fā)出一條射線
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
//是否碰撞到帶有碰撞器的對象
if (Physics.Raycast(ray, out hit, Mathf.Infinity))
{
//從對象池中提取對象
GameObject currentObj = ObjectPoolSingleton.Instance.OutPool("Sphere",
Camera.main.transform.position, Quaternion.identity);
//球?qū)ο蟮乃俣纫跏蓟癁?,不然,會在原來基礎(chǔ)上再次添加力
currentObj.GetComponent<Rigidbody>().velocity = Vector3.zero;
//給對象一個力
currentObj.GetComponent<Rigidbody>().AddForce(ray.direction*1200);
}
}
}
}
}
該腳本掛載到球預(yù)設(shè)體身上(注意:球要添加剛體組件种冬,需要添加力镣丑,并且該預(yù)設(shè)體要放在Resources文件夾下,需要動態(tài)加載娱两,名稱要與你提取對象所傳入的字符串名稱相同)
using UnityEngine;
using System.Collections;
//該腳本掛載到球預(yù)設(shè)體身上(球要添加剛體組件,需要添加力)
public class Bullet : MonoBehaviour {
//注意:必須OnEnable回調(diào)函數(shù)里金吗,此函數(shù)在腳本生命周期里是可以循環(huán)調(diào)用的十兢,對象SetActive(true)
//時,就會調(diào)用
void OnEnable()
{
StartCoroutine("Join");
}
IEnumerator Join()
{
yield return new WaitForSeconds(2.5f);
//延時2.5S后進(jìn)對象池摇庙,你就看不見了
ObjectPoolSingleton.Instance.JoinPool(gameObject);
}
}
寫在最后
###代碼虐我千百遍旱物,催我快點找初戀###