你使用对象池了吗

什么是对象池?
对象池,简单的说就是一种为了避免重复创建,删除对象的解决方案。它可以通过复用游戏对象,一定程度上提高游戏性能,避免内存消耗,特别针对任何频繁创建删除对象的情景。这符合了性能优化中对脚本优化的理念。是居家旅行...哦不...游戏开发必备技能。
对象池的实现原理?
创建复用对象的集合,通过查找和设置集合元素的active状态,达到和创建、删除一样的视觉效果。



这里先通过一个射击子弹的简单例子,从不用对象池,到给子弹创建对象池,去繁就简的一步步呈现对象池使用过程,深化理解。


不用对象池的小白脚本
Control.cs

...
public class Control:MonoBehaviour{
     public  GameObject bulletPrb;
     void Update(){
          if(Input.GetMouseButton(0))
                  Fire();
  }
     void Fire(){
      Instantiate(bulletPrb);
  }
}

Bullet.cs

...
public class Bullet:Monobehaviour{
     void Start(){
      Invoke("Destroy",2);
  }
     void Destroy(){
      Destroy(gameObject);  
  }
}

这里很容易的脑补出Hierarchry下,bullet对象一直在创建,销毁,创建,销毁。。。

使用对象池的一阶脚本
Control.cs

...
using System.Collections.Generic;

public class Control:MonoBehaviour{
     public  GameObject bulletPrb;

     public int poolingCapacity = 20;
     public List pool;
   
     void Start(){                 //创建对象池,并将对象设为不可见
          pool = new List()
          for(int i=0 ; i

Bullet.cs

...
public class Bullet:Monobehaviour{
     void OnEnable(){
      Invoke("Destroy",2);
  }
     void Destroy(){
       //Destory(gameObject);
       gameObject.SetActive(false);    //只要隐藏掉就好,对象还在对象池中
  }
     void OnDisable{
        CancelInvoke();
  }
}

这样对象池的功能算是实现了。然而它是被构建在控制脚本中的,这样显然不行。这就像编程小白把所有语句写在主函数中一样,这不符合面向对象的思想!因此,需要第三步

使用对象池的二阶脚本
新建一个ObjectBulletPool.cs 并挂载到新建的空物体ObjectPooler上

 ...
using System.Collections.Generic
public class ObjectPool: MonoBehaviour{
        public static ObjectPool current;

        public GameObject objectPrb;          //将被放入对象池中的预制体
        public int poolCapacity = 20;
        public List pool;
        public bool willgrow = true;           //池子容量不够时,是否自动扩展池子

        void Awake(){
            current = this;
     }
         void Start(){
             for(int i = 0 ; i

简化 Control.cs

...
using System.Collections.Generic;

public class Control:MonoBehaviour{
/*
     public  GameObject bulletPrb;
     public int poolingCapacity = 20;
     public List pool;
   
     void Start(){                 //创建对象池,并将对象设为不可见
          pool = new List()
           for(int i=0 ; i

不用改 Bullet.cs

...
public class Bullet:Monobehaviour{
     void OnEnable(){
      Invoke("Destroy",2);
  }
     void Release(){
       //Destory(gameObject);
       gameObject.SetActive(false);    //只要隐藏掉就好,对象“回到”对象池中
  }
     void OnDisable{
        CancelInvoke();
  }
}

多说一句,如果你能发射不同类型的子弹怎么办?
解决思路:将子弹类型bulletPrb对象改成数组,在GetPooledObject()函数中传入子弹类型的参数,然后遍历数组匹配子弹类型,return出去。

小结:
这个对象池其实是固定的,一旦创建就不用删除,这样便于复用创建好的对象。使用对象其实就是在对象池中搜索没有active的对象并激活获取到它好进行操作。释放对象就是让他失活,好被以后搜索复用。
Ok,看到这里,对象池的基本用法就掌握了,在实际项目中需求会更加多变,但是万变不离本质。高阶运用也是从低阶进化的!



高阶运用请看这位老兄的文章: unity中的通用对象池

你可能感兴趣的:(你使用对象池了吗)