Unity_设计模式_对象池_09

原本用拖拽操作实现的克隆非常消耗资源,点击进入GameObject你就会发现每次克隆需要进行很多操作。
所以此时我们就引用了对象池的概念:
对象池是一个集合,用来存放一些需要大量重复使用的游戏对象

在FPS游戏中,我们需要大量的生成子弹,特效,敌人等,如果我们频繁的创建和销毁会很消耗CPU的性能,我想一想可不可以像我们用的白酒瓶一样回收利用,
你用这个瓶子的时候,你需要从消毒柜中取出,如果没有的话,我们使用新造的瓶子,往里边加白酒,然后对酒瓶进行封盖。用完之后,你需要对瓶子进行回收,回收后清洗,消毒,烘干,放入消毒柜,准备进行下一次使用,酒厂也不会把用过的完好的瓶子摔了再造新的,这样既消耗成本也浪费资源和时间。

我们程序中也可以使用这样的思路,例如我们在塔防游戏里边使用的敌人游戏对象,再具体一点《兽人必须死》游戏里的那个恶魔小鬼,反正都是一个预制体克隆出来的,恶魔小鬼在实例化的时候,会根据你选择的难度,给他们赋不同的血量等属性,游戏里,你建造的箭塔会攻击这个恶魔小鬼,这个恶魔小鬼死亡之后,我们不要销毁它,把这个恶魔小鬼激活状态关闭,存放在某个地方,再次需要使用的时候,我们把那些回收的恶魔小鬼,重新激活,并给它赋一些属性,如血量,状态等属性修改一下,继续使用。这个可以有效的避免重复创建和消耗产生的性能消耗。

对象池的基本模式:
IpoolObject(进行约束行为,也可以用抽象类)
///
/// 放在对象池里面的对象必须实现的接口
///
public interface IPoolObject {
///
/// Object初始化时调用
///
void Init();
///
/// Object回收时调用
///
void Release();
BasePoolObject(需要将此脚本挂载到预制体上)
using UnityEngine;
using System.Collections;
public class BasePoolObject : MonoBehaviour,IPoolObject {

public void Init ()
{
    Debug.Log("初始化对象,比如位置");
}

public void Release ()
{
    Debug.Log("释放对象");
}

}
ObjectPool(进行逻辑编程)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class ObjectPool : MonoBehaviour {

/// <summary>
/// 预生成的个数
/// </summary>
public int preNum;
/// <summary>
/// 对象列表
/// </summary>
public  Queue<GameObject> pool = new Queue<GameObject>();
/// <summary>
///要放入的对象的预置
/// </summary>
public GameObject  poolObjectPefab;
void InitPool(){
    for(int i=0; i<preNum;i++)
    {
        GameObject obj = GameObject.Instantiate(poolObjectPefab);

        IPoolObject comp = obj.GetComponent<IPoolObject>();

        if(comp==null)
        {
            Debug.LogError("预置上必须绑有实现了IPoolObject接口的类");

        }
        comp.Init();
        pool.Enqueue(obj);
        obj.SetActive(false);       
    }
}
/// <summary>
/// 创建一个对象
/// </summary>
/// <returns>从池里取出对象.</returns>
public  GameObject RequestObject(){
    GameObject obj;
    if(pool.Count!=0)
    {
        obj = pool.Dequeue();

    }else{

        obj = GameObject.Instantiate(poolObjectPefab);
    }
    IPoolObject comp = obj.GetComponent<IPoolObject>();
    if(comp==null)
    {
        Debug.LogError("预置上必须绑有实现了IPoolObject接口的类");

    }
    obj.SetActive(true);
    comp.Init();
    return obj;
}
/// <summary>
/// 回收对象
/// </summary>
/// <param name="obj">Object.</param>
public void RecoverObject(GameObject obj){

    IPoolObject comp = obj.GetComponent<IPoolObject>();
    if(comp==null)
    {
        Debug.LogError("预置上必须绑有实现了IPoolObject接口的类");
    }
    pool.Enqueue(obj);
    comp.Release();
    obj.SetActive(false);

}
void Awake () {

    InitPool();

}   
// Update is called once per frame
void Update () {    
}

}

Test(测试)
using UnityEngine;
using System.Collections;
public class Test : MonoBehaviour {

public ObjectPool pool1;
public ObjectPool pool2;
void Start () {
    GameObject obj =pool1.RequestObject();
    pool1.RecoverObject(obj);
}   
// Update is called once per frame
void Update () {

}

}

using UnityEngine;
using System.Collections;
public interface IPoolObjec{

void EnterPool();
void ExitPool();
}
using UnityEngine;
using System.Collections;
using System;
public class BasePoolObject : MonoBehaviour,IPoolObjec {

public void EnterPool()
{
    Debug.Log("huishou");
}

public void ExitPool()
{
    Debug.Log("huoqu");
}

void OnMouseDown()
{
    Pool.instance.Recycle(this.gameObject);
}

}

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Pool : MonoBehaviour

{
//实现了类似单例

 public static Pool instance;
void Awake()
{
    instance = this;
    //初始化,意义是在游戏开始初期就将所有需要的资源加载出来
    Init();
}
public int initCount;
//产生什么预制体
public GameObject objPrefab;
//存到哪里
public Queue<GameObject> queue = new Queue<GameObject>();

//进货
public void Init()
{
    //将接口当成标签使用,进行判断
    IPoolObjec ipoolObject = objPrefab.GetComponent<IPoolObjec>();
    if (ipoolObject!=null)
    {
        //生成适当的预制体进行储存(initCount)
        for (int i = 0; i < initCount; i++)
        {
            GameObject obj = GameObject.Instantiate(objPrefab);
            //两种方式防止对象影响游戏(放置不可能出现在游戏界面的位置(2))
            //obj.transform.position = new Vector3(10000000, 10000, 10000);

            //产生并禁用(1)
            obj.SetActive(false);
            obj.transform.position = new Vector3(2 * i, 0, 0);
            queue.Enqueue(obj);
        }
    }
    else
    {
        Debug.Log("不是我想要,初始化失败");
        return;
    }
}
//出仓
public GameObject GetObject()
{
    GameObject result = null;
    //判断是否还剩余预制体,有就用,没有就产生
    if (queue.Count>=1)
    {
        //如果有就激活并进行初始化操作,并将队列中的移除
        result = queue.Dequeue();
        result.SetActive(true);
        result.GetComponent<IPoolObjec>().ExitPool();
    }
    else
    {
       //一般设置恰当就不会发生这种情况(此时我们还可以对接口进行判断类似69)
        result = GameObject.Instantiate(objPrefab);
        result.GetComponent<IPoolObjec>().ExitPool();
    }
    return result;
}
//回收
public void Recycle(GameObject obj)
{
    //进行回收判断
    IPoolObjec ipoolObiect = obj.GetComponent<IPoolObjec>();
    if (ipoolObiect!=null)
    {
        //将对象失活,并加入队列()
        obj.SetActive(false);
        ipoolObiect.EnterPool();
        queue.Enqueue(obj);
    }
}

}
using UnityEngine;
using System.Collections;
public class Test : MonoBehaviour {

// Update is called once per frame
void Update () {
    //进行按键回收我们需要在BasePoolObject中添加以下代码
    //void OnMouseDown()
    //{
    //    Pool.instance.Recvcle(this.gameObject);
    //}
    if (Input.GetMouseButtonDown(1))
    {
        Debug.Log("na");
        Pool.instance.GetObject();
    }
    if (Input.GetMouseButtonDown(0))
    {
        Debug.Log("shou");
        Pool.instance.Recycle(gameObject);
    }
}

}

这是一种子弹移动的方式(此时给预制体添加刚体时我们要注意,我们要将Use Gravity 取消勾选)
using UnityEngine;
using System.Collections;
public class Weapon : MonoBehaviour {

// Use this for initialization
void Start () { 
}   
// Update is called once per frame
void Update () {
    if (Input.GetMouseButtonDown(0))
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        GameObject bullt = Pool.instance.GetObject();
        bullt.transform.position = ray.origin;
        bullt.GetComponent<Rigidbody>().AddForce(ray.direction * 20);
    }

}

}
using UnityEngine;
using System.Collections;
using System;
public class BasePoolObject : MonoBehaviour, IpoolObject
{

public void EnterPool()
{
    Debug.Log("回收");
}
public void ExitPoll()
{
    Debug.Log("获取");
}
void OnMouseDown()
{
    Pool.instance.Recycle(this.gameObject);
}
void OnTriggerEnter(Collider other)
{
    if (other.tag.Equals("Wall"))
    {
        Pool.instance.Recycle(this.gameObject);
    }
}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值