1. 程式人生 > >Unity3D-物件池技術

Unity3D-物件池技術

什麼是物件池
物件池定義:物件池就存放需要被反覆呼叫資源的一個空間,當一個物件回大量生成的時候如果每次都銷燬建立會很費時間,通過物件池把暫時不用的物件放到一個池中(也就是一個集合),當下次要重新生成這個物件的時候先去池中查詢一下是否有可用的物件,如果有的話就直接拿出來使用,不需要再建立,如果池中沒有可用的物件,才需要重新建立,利用空間換時間來達到遊戲的高速執行效果,在FPS遊戲中要常被大量複製的物件包括子彈,敵人,粒子等
廢話不多說直接上程式碼
Icontrol
using UnityEngine;
using System.Collections;
///
/// 掛載物件:不掛載
/// 作用:介面類,方便其他指令碼繼承此介面
/// 注意:
///
public interface IControl
{
//生成遊戲物件的方法
void Spawn();
//銷燬遊戲物件
void UnSpwan();
}
SubPool


using UnityEngine;
using System.Collections;
using System.Collections.Generic;
///
/// 掛載物件:不掛載
/// 作用:物件池類。
/// 注意:
///
public class SubPool
{
//物件池裡面存放場景中需要的遊戲物體
List pool = new List ();
//要建立的遊戲物體的預設體
GameObject prefab;
//返回預設體的名字,預設體的名字和物件池的名字相同
//在管理物件池的類裡面,可以通過預設體的名字找到相對應的物件池
public string Name {
get {
return prefab.name;
}
}
//構造方法
public SubPool (GameObject mPrefab)
{
prefab = mPrefab;//傳遞預設體引數
}
//從物件池裡面拿到一個遊戲物體
public GameObject SubPoolSpawn (Transform pos)
{
GameObject obj = null;
//遍歷物件池找預設體
foreach (GameObject item in pool) {
//如果該物件未啟用,說明該物件沒有被使用
if (item.activeSelf == false) {
obj = item;
obj.transform.position = pos.position;
obj.transform.rotation = pos.rotation;
break;//跳出該迴圈
}
}
//找不到要用的遊戲物件
if (obj == null) {
//建立一個新的遊戲物件
obj = GameObject.Instantiate (prefab, pos.position, Quaternion.identity)as GameObject;
//把新建立的遊戲物件放到集合裡面
pool.Add (obj);
}
obj.SetActive (true);//處於啟用狀態
//通過子類例項化介面物件,子類的指令碼元件實現繼承
//並實現了接口裡面的方法,control裡面存的就是該、
//子類所實現的方法

    IControl control = obj.GetComponent<IControl> ();
    if (control != null) {
        //呼叫遊戲物件實現的方法
        control.Spawn ();
    }
    return obj;
}
//回收遊戲物件
public void SubPoolUnSpawn (GameObject obj)
{
    //如果物件池集合裡面包含了該物體
    if (pool.Contains (obj)) {
        IControl control = obj.GetComponent<IControl> ();
        if (control != null) {
            control.UnSpwan ();
        }
        obj.SetActive (false);
        obj.transform.position = Vector3.zero;
    }
}
//回收所有的遊戲物件
public void SubPoolUnsPawnAll ()
{
    //遍歷集合中所有的遊戲物件
    foreach (GameObject item in pool) {
        if (item.activeSelf) {
            SubPoolUnSpawn (item);
        }
    }
}

/// <summary>
/// 某個物件是否在物件池裡面
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public bool Contains (GameObject obj)
{
    //池子裡面是否有物件
    return pool.Contains (obj);
}

}
PoolControl
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
///
/// 掛在物件:C#類,不掛載
/// 作用:物件池管理類,減少程式碼耦合度
/// 注意:不繼承MonoBehaviour
///
public class PoolControl
{

private static PoolControl instances;//單例模式

private PoolControl ()
{
}

public static PoolControl Instance {
    get {
        if (instances == null) {
            instances = new PoolControl ();
        }
        return instances;
    }
}
//建立字典,根據預設體名字找到相對應的物件
Dictionary<string, SubPool> poolDic = 
    new Dictionary<string, SubPool> ();

/// <summary>
/// 得到物件池中的遊戲物件
/// </summary>
/// <param name="name">預設體的名字</param>
/// <returns></returns>
public GameObject Spawn (string name, Transform pos)
{
    SubPool subpool;
    //如果字典包含該key的值
    if (!poolDic.ContainsKey (name)) {
        //在字典裡面新增一個物件池
        RegisterSubPools (name);
    }
    subpool = poolDic [name];
    return subpool.SubPoolSpawn (pos);
}

/// <summary>
///  新增物件池的方法
/// </summary名字
void RegisterSubPools (string name)
{
    //通過名字載入預設體
    GameObject mprefab = Resources.Load (name) as GameObject;
    //根據預設體建立對應的物件池
    SubPool subpool = new SubPool (mprefab);
    //將物件池新增到字典中
    poolDic.Add (name, subpool);
}

///回收物件的方法
public void UnSpwan (GameObject obj)
{
    //遍歷所有的物件池看那個物件池包含該遊戲物體
    foreach (SubPool item in poolDic.Values) {
        //如果該物件池包含了該物體
        if (item.Contains (obj)) {
            //呼叫該物件池回收遊戲物體的方法
            item.SubPoolUnSpawn (obj);
            break;
        }
    }
}

}
PlayerScript
using UnityEngine;
using System.Collections;
using UnityEngine.WSA;
///
/// 掛載物件:需要產生子彈的遊戲物體上
/// 作用:控制遊戲物體的旋轉移動和子彈的發射
/// 注意:
///
public class PlayerScript : MonoBehaviour
{
public Transform pos;

void Update ()
{
    float v = Input.GetAxis ("Vertical");
    float h = Input.GetAxis ("Horizontal");
    if (v != 0 || h != 0) {
        transform.Translate (transform.forward * v * Time.deltaTime * 10f);
        transform.Rotate (new Vector3 (0, h, 0) * Time.deltaTime * 30f);
    }
    if (Input.GetKeyDown (KeyCode.Space)) {
        PoolControl.Instance.Spawn ("Bullet", pos);
    }
}

}

重點內容
using UnityEngine;
using System.Collections;
using System;
///
/// 掛載物件:子彈
/// 作用:子彈的生成與子彈的運動方向
/// 注意:
///
public class Bullet : MonoBehaviour,IControl
{
// public Transform pos;

public void Spawn ()
{
    Debug.Log ("從物件池裡面取出一個遊戲物體");
    //三秒鐘銷燬
    Invoke ("DeleteSelf", 2f);
}

public void UnSpwan ()
{
    Debug.Log ("把遊戲物體放入物件池");
}

void DeleteSelf ()
{
    PoolControl.Instance.UnSpwan (gameObject);

}
void Update ()
{
    transform.Translate (transform.right * Time.deltaTime * 4);
}

}
遊戲執行效果圖如下
執行效果圖
子彈發射位置