物件池使用例項
阿新 • • 發佈:2019-01-01
轉自:
http://www.taidous.com/forum.php?mod=viewthread&tid=41439&extra=page%3D1&page=1
當遊戲中需要發射子彈(gameobject)等操作的時候,不停的Instantiate和destroy就會很耗效能,如果又是多人遊戲,那多人同時Instantiate和destroy子彈,配置不高的裝置可能會炸,同時這種大量的建立和銷燬時不必要的。
這裡可以用到類似於iOS程式設計中uitableview中對cell的類似於迴圈利用的機制,這裡面叫物件池,就是說建立子彈物件並使用完後不進行銷燬,而是用SetActive方法來改變其啟用狀態,等再次需要使用時再進行啟用圖中紅圈部分就是建立進物件池的物件,當足夠多後就能實現迴圈利用而不是無限增加。
我們要建立一個字典,字典中與key值對應的是陣列(arraylist)(例:key為手槍子彈 對應arraylist[手槍子彈,手槍子彈,手槍子彈。。。。。。 ])。
arraylist就是用來裝重複利用的子彈gameobjet的。
物件池個人感覺就是一種對gameobject的利用機制,可能還可以用很多方法實現。
下面就直接上程式碼,寫了三個指令碼:
1.pool指令碼,註釋已經詳細到話癆了:
using UnityEngine;using System.Collections;
using System.Collections.Generic;
public class pool : MonoBehaviour {
public static pool instance; //建立一個字典dic ,作為池
public static Dictionary<string, ArrayList> dic = new Dictionary<string, ArrayList>(); void Start () {
instance = this; //使自身可被呼叫
}
Debug.Log(key); //輸出預設體名(這個沒用 就是輸出來看看 就是NSLog)
GameObject go; //建立返回值物件 //拼接製作dic的key名,因為instantiate出的gameobject都會自動命名為gameobject(Clone),這裡是為了通下面return方法裡給key的命名匹配 string GameObjectName = key + "(Clone)"; //如果字典裡有gameobjectname這個key 並且key對應的陣列不為空(有該種類子彈,且該種類子彈中有《已經建立過的》(未啟用)的子彈gameobject)
if (dic.ContainsKey(GameObjectName) && dic[GameObjectName].Count > 0)
{
ArrayList list = dic[GameObjectName]; //從gameobjectname這個key位置取出陣列
go = (GameObject)list[0]; //取出一號位的子彈
list.RemoveAt(0); //從列表中去除這個子彈(拿出來用)
go.SetActive(true); //使用時啟用
go.transform.position = position; //引數賦值於子彈
go.transform.rotation = rotation;
} else { Debug.Log("chi"+key); //在給定位置建立一個resources中名為給定key的預設體的gameobject
go = Instantiate(Resources.Load(key), position, rotation) as GameObject;
} return go;//返回建立的東西 }
//函式(方法) 名return(可自定義) 引數是需要取消啟用的物件g
//將需要取消啟用的物件取消啟用
public static GameObject Return(GameObject g) {
//獲取gameobject的名字,會是一個在上面get方法裡建立的(預設體的)gameobject,名字會是gameobject(Clone);
string key = g.name;
if (dic.ContainsKey(key)) //如果字典裡有這個key { //就在這個key所對應的陣列中加入這個g(g就是已經用完的子彈,放在數組裡的gameobjet都是不銷燬只是取消啟用等待再次利用的gameobject)
dic[key].Add(g);
} else {dic[key] = new ArrayList() { g }; //建立一個這個key的arraylist 並把g加進去
}
g.SetActive(false); //不銷燬而是取消啟用
return g; //返回g }
====================================================================
2.子彈建立(子彈建立方法其實在pool中(是建立或啟用) 就是這裡呼叫一下 給引數 然後給子彈一個動力)指令碼
[C#] 純文字檢視 複製程式碼
using UnityEngine;
using System.Collections;
public class creatzidan : MonoBehaviour { //這個指令碼掛到任意一個geamobject上 我掛在camera上
public GameObject zidan; //拖入子彈預設體
public Transform startPlace; //拖入子彈開始位置,給一個空物體位置,然後拖個空物體進來
void Update () {
if (Input.GetKeyDown(KeyCode.Space)) { //獲取空格鍵輸入 (發射鍵)
GameObject AZiDan = pool.Get(zidan.name, startPlace.position, Quaternion.identity); //呼叫pool的get方法建立一個子彈
AZiDan.GetComponent<Rigidbody>().AddForce(Vector3.forward * 30, ForceMode.Impulse); //給子彈剛體一個力(發射)
}
}
}
====================================================================
3.子彈自動“銷燬”指令碼 (同樣是呼叫了pool中的方法 (其實並不是銷燬 是取消啟用) )
[C#] 純文字檢視 複製程式碼
using UnityEngine;
using System.Collections;
public class desttoryy : MonoBehaviour { //這個指令碼掛到子彈上,讓子彈在啟用後n秒自動“銷燬”(進入不啟用狀態)
IEnumerator destoryy() //建立延時操作destoryy()
{
yield return new WaitForSeconds(3f);
pool.Return(this.transform.gameObject); //呼叫取消啟用方法取消啟用自身
}
void Update () {
StartCoroutine(destoryy()); //執行延時操作
}
}
====================================================================
最後囉嗦一句:根本原理就是:打一顆 “5mm子彈” 就建立一個gameobject,這 “5mm顆子 彈” 需要銷燬的時候不銷燬它,把它的啟用狀態變為false,然後把它存入 “5mm子彈” 陣列中,當你再打出一顆“5mm子彈”的時候,不需要建立一顆新的“5mm子彈”,只需要把剛才那顆未啟用“5mm子彈”從ArrayList裡拿出來啟用一下,然後刪除掉ArrayList裡關於這個gameobje的資料就行了,然後這顆子彈再銷燬。。。。如此往復,子彈多了也同理。