1. 程式人生 > >unity物件池技術原理雜談

unity物件池技術原理雜談

首先我們來談一談物件池技術的介紹:由於Cpu回收遊戲物件和建立遊戲物件,涉及到記憶體的分配和回收,研究過操作的同學應該知道當應用程式也就是我們的遊戲需要生產一個怪物的時候,我們首先會和作業系統申請一份記憶體區域準備存放我們的遊戲怪物,這個時候作業系統會去檢測有沒有容的下我們怪物記憶體大小啊,這個操作就是細活,cpu這個時候會進行許多的工作,當我們怪物掉血死忙的時候我們需要把怪物從螢幕中清除出去,如果我們直接Destory(銷燬物件,0f)掉,我們的作業系統會去查詢各種表,這個表是記錄那些記憶體被使用,如果回收了會被標誌為空閒,並且如果當前回收的記憶體附近也是有空間記憶體,還會進行記憶體合併。這個是非常吃cpu的,儘管unity會進行優化等cpu空閒的在去合併空閒記憶體。
基於上述CPU的銷燬,我們引進物件池技術,我們可以預先生產10個怪物,然後禁用也就是讓他在記憶體中,但是不參與和CPU的互動。當我們遊戲回合開始的時候我們需要出怪的時候我們不是直接去例項化對應的數量,而是通過物件池去取出物件需要的怪物數量,當怪物死忙的時候我們不是去銷燬而是告訴物件池你來回收他。有一點,我們的物件池會傳遞到出怪的全部場景。很明顯我們看到的情況是用記憶體換CPU的運作。這個時候我們的池子裡預先生產的怪物數量比例特別重要,一要考慮記憶體不能暫用過多,二是不能出現預先的準備不足還要經常例項化那物件池技術沒有多大效果。
物件池每個人的設計要根據實際需求,比如你的遊戲在很長一段時間並沒有怪物的產出,這個時候你可以清理一些空閒出記憶體後續使用。
如果我們物件池想管理不同的物件,比如怪物,音樂資源,等,我們可以根據他進行池子分類,有怪物子池子和音樂子池子。然後統一交給父池子管理。
理論太多頭也暈,下面上主要的程式碼:
子池子
public class SubPool
{
Transform m_parent;

//預設
GameObject m_prefab;

//集合
List<GameObject> m_objects = new List<GameObject>();

//名字標識
public string Name
{
    get { return m_prefab.name; }
}

//構造
public SubPool(Transform parent, GameObject prefab)
{
    this.m_parent = parent;
    this.m_prefab = prefab;
}

//取物件
public GameObject Spawn()
{
    GameObject go = null;

    foreach (GameObject obj in m_objects)
    {
        if (!obj.activeSelf)
        {
            go = obj;
            break;
        }
    }

    if (go == null)
    {
        go = GameObject.Instantiate<GameObject>(m_prefab);
        go.transform.parent = m_parent;
        m_objects.Add(go);
    }

    go.SetActive(true);
    go.SendMessage("OnSpawn", SendMessageOptions.DontRequireReceiver);
    return go;
}

//回收物件
public void Unspawn(GameObject go)
{
    if(Contains(go))
    {
        go.SendMessage("OnUnspawn", SendMessageOptions.DontRequireReceiver);
        go.SetActive(false);
    }
}

//回收該池子的所有物件
public void UnspawnAll()
{
    foreach(GameObject item in m_objects)
    {
        if (item.activeSelf)
        {
            Unspawn(item);
        }
    }
}

//是否包含物件
public bool Contains(GameObject go)
{
    return m_objects.Contains(go);
}

}

下面逐一分析子池子程式碼:我們給了子池子一些關鍵字m_parent這個是父池子傳給我的,用於子池子造的怪物需要放的位置,我們unity一般是說這裡這裡寫圖片描述
不能讓例項出來的物件在層級面板位置亂放,不方便查詢和管理。
第二個欄位就是怪物的預設肯定是給這個子池子的,不然子物件池在你發出Spawn()指令取怪物的時候怎麼例項化呢。當然你是可以通過程式碼去拿到的,這裡我們選擇外界直接填充到這個欄位裡,當前子池子就可以隨意的去造物件。
第三欄位m_objects 儲存了當前例項化出來的全部怪物例項,還有一個名字的屬性,我們直接用預設名稱了。由於我們對池子是根據不同物件型別進行分類,那麼名字肯定是唯一的,這個時候我們可以拿這個名字和字典的物件例項去一一對應,也就是索引,不知道你們還記得那個雜湊函式不。我們把通過一個名字等於是記憶體編號直接可以讀取記憶體裡面的資料也就是怪物。這個查詢效率是非常高的。
接下來就是子池子對外有個建構函式以及需要的外界進行輸入的資料定義。
下面到了重點就是生產怪物和回收怪物待續…………………..