关于对象池的初步理解与使用

来源:互联网 发布:物美价廉的男装淘宝店 编辑:程序博客网 时间:2024/06/18 17:58
在我们使用对象池之前我们需要知道以下两点:
1.什么是对象池?
  池(Pool),与集合在某种意义上有些相似。 水池,是一定数量的水的集合;内存池,是一定数量的已经分配好的内存的集合;线程池,是一定数量的已经创建好的线程的集合。那么,对象池,顾名思义就是一定数量的已经创建好的对象(Object)的集合[1]。
  在面向对象过程中,如果一种对象,你要经常使用,并且需要反复创建、销毁,这样子一方面开销会比较大,另一方面会产生很多内存碎片,程序运行时间一过长,性能就会下降。这个时候,就产生了对象池。我们可以事先创建好一批对象,并且放在一个集合中(对象池),以后每当程序需要使用到对象的时候,我们不是创建一个对象,而是从对象池里获取,程序用完该对象后,再把该对象归还给对象池。这样,就会少了很多的关于创建或者销毁的调用,在一定程度上提高了系统的性能,尤其在动态内存分配比较频繁的程序中效果较为明显。

2.Unity3d中的对象池
  在使用unity3d做游戏时,经常有同一个Prefab用到多次,需要反复实例化(Instantiate)。但实例化是很消耗资源的,所以在游戏加载时把一批Prefab实例化好放在对象池中,游戏中用的时候拿出来,不用的时候放回去,避免反复申请和销毁。
  存入对象池的元素应具有如下特征:1>场景中大量使用 2>存在一定的生命周期,会较为频繁的申请和释放。

下面不多说直接上代码:

usingSystem.Collections;
usingSystem.Collections.Generic;
usingUnityEngine;
publicclassObjectPoolManager:MonoBehaviour{
   // 继承于monoBehaviour的单例可以简化为这样,方便使用
   publicstaticObjectPoolManagerInstance;
   // 定义一个大池子
   privateDictionary<string,List<GameObject>>pool;
   voidAwake(
    {
       Instance=this;
    }
   voidStart()
    {
       pool=newDictionary<string,List<GameObject>>();
    }
   
   // 两个主要方法,存、取
   // 取对象
   publicGameObjectGetObjectFromPool(stringobjName,Vector3pos,Quaternionqua)
    {
       GameObjectgo;
       // 当池子中有相应的键值对,并且里面有可以使用的对象,则直接拿出来用
       if(pool.ContainsKey(objName) && pool[objName].Count> 0)
        {
           // 把相应的键值对中的第一个对象取出来,并从池子中移除
           go=pool[objName][0];
           pool[objName].RemoveAt(0);
           // 激活这个对象
           go.SetActive(true);
        }
       else
        {
           // 若不满足上面条件,则实例化一个新的对象出来
           go=Instantiate(Resources.Load(objName)asGameObject);
        }
       // 设置一下得到的对象的位置以及旋转角度
       go.transform.position=pos;
       go.transform.rotation=qua;
       returngo;
    }
   // 存对象(参数为我们即将存入的对象)
   publicvoidPushObjectToPool(GameObjectgo)
    {
       stringprefabName=go.name.Split('(')[0];
       // 判断池子中有没有相应的键值对,没有则创建一个新的键值对,有则直接往里存
       if(pool.ContainsKey(prefabName))
        {
           pool[prefabName].Add(go);
        }
       else
        {
           // 在池子中创建一个新的键值对,并初始化List
           pool[prefabName] = new List<GameObject>() {go};
        }
       // 取消激活该对象
       go.SetActive(false);
    }
}



usingSystem.Collections;
usingSystem.Collections.Generic;
usingUnityEngine;
publicclassMyFight:MonoBehaviour{
   // 定义即将生成的预制体名字
   conststringredBullet="RedBullet";
   conststringblueBullet="BlueBullet";
   // 获取两种子弹生成的位置及角度信息
   publicTransformredBulletPos;
   publicTransformblueBulletPos;
       // Use this for initialization
       voidStart() {
              
       }
       
       // Update is called once per frame
       voidUpdate() {
       // 按下鼠标左键生成红色子弹
       if(Input.GetMouseButtonDown(0))
        {
           // 生成的操作就是取对象的操作
           GameObjectgo=ObjectPoolManager.Instance.GetObjectFromPool(redBullet,redBulletPos.position,redBulletPos.rotation);
           // 给子弹加力度
           go.GetComponent<Rigidbody>().AddForce(go.transform.forward* 500);
           // 让子弹一秒钟之后消失(放入池子)
           StartCoroutine(DestroyBullet(go));
        }
       // 鼠标右键生成蓝色子弹
       if(Input.GetMouseButtonDown(1))
        {
           // 生成的操作就是取对象的操作
           GameObjectgo=ObjectPoolManager.Instance.GetObjectFromPool(blueBullet,blueBulletPos.position,blueBulletPos.rotation);
           // 给子弹加力度
           go.GetComponent<Rigidbody>().AddForce(go.transform.forward* 500);
           // 让子弹一秒钟之后消失(放入池子)
           StartCoroutine(DestroyBullet(go));
        }
       }
       
   IEnumeratorDestroyBullet(GameObjectgo)
    {
       yieldreturnnewWaitForSeconds(1);
       // 重置子弹的速度为0
       go.GetComponent<Rigidbody>().velocity=Vector3.zero;
       ObjectPoolManager.Instance.PushObjectToPool(go);
    }
}