1. 程式人生 > >物件池使用例項

物件池使用例項

轉自: 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; 
//節省效能的方法,important,物件池 
public class pool : MonoBehaviour {  
       public static  pool instance;                //建立一個字典dic ,作為池
       public static  Dictionary<string, ArrayList> dic = new Dictionary<string, ArrayList>();
     void Start () {  
           instance = this;    //使自身可被呼叫 
       }
//方法:呼叫後會返回一個屬於需要的種類(dic的key值(實際為key + "(Clone)"))的 敵人或子彈(即gameobject)。 //key是子彈或敵人預設體的名字,預設體放在Resources中 //方法名get(可以自定義) 返回值為 引數為(obj名(子彈 敵人種類 dic的key),啟用位置,啟用角度) public static GameObject Get(string key, Vector3 position, Quaternion rotation) {  
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的資料就行了,然後這顆子彈再銷燬。。。。如此往復,子彈多了也同理。