淺談物件池技術在遊戲中的應用
阿新 • • 發佈:2019-01-29
說到做遊戲,遊戲的優化就至關重要,今天所說的就是關於遊戲優化的一種方式——物件池技術。
物件池技術的主要應用於遊戲中反覆利用的遊戲資源(比如:子彈,技能特效,怪物等等)
物件池的具體思想:
將使用過的資源(會反覆利用的)儲存到池子中,下次需要的時候直接去池子中取出來。
第一步:構建物件池
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 物件池 所有池子都在字典裡 字典裡存的是單個池子的List /// </summary> public class GameObjectPool: MonoBehaviour { /// <summary> /// 單利 /// </summary> private static GameObjectPool instance; /// <summary> /// 獲得單利 /// </summary> public static GameObjectPool Instance { get { if (!instance) { instance = new GameObject("_Pool").AddComponent<GameObjectPool>(); //設定在場景載入中不銷燬物件池 DontDestroyOnLoad(instance.gameObject); } return instance; } } /// <summary> /// 所有池子的字典 /// </summary> Dictionary<string, List<GameObject>> _PoolDic=new Dictionary<string, List<GameObject>>(); /// <summary> /// 獲得池子中的物件 /// </summary> /// <param name="name">物件的名字</param> /// <returns></returns> public GameObject GetObject(string name) { //定義一個儲存物件的容器 GameObject Object; //有這個名字的池子 if (_PoolDic.ContainsKey(name)) { //並且池子中有物件 if (_PoolDic[name].Count > 0) { Object = _PoolDic[name][0]; _PoolDic[name].Remove(_PoolDic[name][0]); } else //並且池子中沒有物件 { Object = GameObject.Instantiate(ResourcesManager.Instance._PrefabsDic[name]); Object.transform.SetParent(transform); } } else//沒有這個池子 { //建立池子 例項物件 _PoolDic.Add(name, new List<GameObject>()); Object = GameObject.Instantiate(ResourcesManager.Instance._PrefabsDic[name]/*這是一個工具類,用於載入物件資源*/); Object.transform.SetParent(transform); } //更改物件的名字 Object.name = name; return Object; } /// <summary> /// 往池子中新增物件 /// </summary> /// <param name="Object"></param> public void SetObject(GameObject go) { go.SetActive(false); //字典中有這個池子 if (_PoolDic.ContainsKey(go.name)) { _PoolDic[go.name].Add(go); } else //字典中沒有這個池子 { //建立新的池子 _PoolDic.Add(go.name,new List<GameObject>()); //將物件加入池子 _PoolDic[go.name].Add(go); } } }
第二部 構建物件池 所需要的資源載入工具
第三步:回收到物件池中的指令碼using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 載入資源用的 /// </summary> public class ResourcesManager : MonoBehaviour { /// <summary> /// 單利的儲存欄位 /// </summary> private static ResourcesManager instance; /// <summary> /// 單利的屬性用於獲取 /// </summary> public static ResourcesManager Instance { get { if (!instance) instance= new GameObject("_ResourcesManager").AddComponent<ResourcesManager>(); return instance; } } /// <summary> /// 儲存所載入的遊戲物件 /// </summary> public Dictionary<string, GameObject> _PrefabsDic=new Dictionary<string, GameObject>(); void Awake () { _PrefabsDic.Add("Cube", Resources.Load<GameObject>("Cube")); _PrefabsDic.Add("Bullet", Resources.Load<GameObject>("Bullet")); } //TODO: 這裡可以直接寫一個根據名字直接載入的方法 /// <summary> /// 根據名字獲取資源 有就直接返回 沒有去載入 /// </summary> /// <param name="name"></param> /// <returns></returns> public GameObject LoadGameObjectByName(string name) { //安全校驗 if (_PrefabsDic.ContainsKey(name)) return _PrefabsDic[name]; _PrefabsDic.Add(name, Resources.Load<GameObject>(name)); return _PrefabsDic[name]; } }
掛載在遊戲物件身上using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 掛在物件上 用於物件的入池 /// </summary> public class SetPool : MonoBehaviour { public float time=3f; private void OnEnable() {//延時呼叫函式 Invoke("SetPoolObject", time); Debug.Log(1); } public void SetPoolObject() { GameObjectPool.Instance.SetObject(gameObject); Debug.Log(2); } }
注意:這裡要回收到物件池身上 要對物件進行初始化處理 也就是恢復到加入池子的狀態
下面是遊戲中的使用案例:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameController : MonoBehaviour {
//這裡用箱子模擬敵人 球模擬子彈
/// <summary>
/// 生成箱子的行數
/// </summary>
public int Row = 5;
/// <summary>
/// 生成箱子的列數
/// </summary>
public int Line = 10;
/// <summary>
/// 生成物體的位置X方向的偏移
/// </summary>
public float Offset=-5f;
/// <summary>
/// 子彈的速度
/// </summary>
public float speed=3f;
/// <summary>
/// 射線
/// </summary>
private RaycastHit hit;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
//具體的引用
GameObject bullet = GameObjectPool.Instance.GetObject("Bullet");
bullet.SetActive(true);
bullet.transform.position = Camera.main.transform.position;
bullet.GetComponent<Rigidbody>().velocity = (hit.collider.gameObject.transform.position - Camera.main.transform.position).normalized * speed * Time.deltaTime;
}
}
}
void Start () {
//生成箱子(敵人) 場景初始化
for (int i = 0; i < Row; i++)
{
for (int j = 0; j < Line; j++)
{
GameObject game= GameObject.Instantiate(ResourcesManager.Instance._PrefabsDic["Cube"]);
game.transform.SetParent(transform);
game.transform.position = new Vector3(Offset + j, 0.5f + i, 0);
}
}
}
}