关于Unity3D中对象池的创建与回收

写的第一篇博客,说实话是有点激动的,以后每个周会留下我的一些学习笔记与感想,将会一直学习下去,欢迎一起交流学习, QQ:1059213621
对象池:在激活对象时,它从池中提取。在停用对象时,它放回池中,等待下一个请求。
作用:我的认识不够全面,单纯的认为是为了避免节约电脑内存的一种方法,使用对象池后,就不需要生成对象,然后再销毁,不断的创建和销毁本身是很消耗电脑内存的。(如有更好的更深度的认识欢迎交流)

首先是新建一个工程,在Assets下创建一个文件夹命名为Resources(创建这个文件夹的作用在于存放我们的预设体和脚本,当然生成的对象也要在这个文件夹里面用来Resources.Load),然后在Hierarchy面板里面创建一个Sphere(创建一个球),然后把这个球拖成预设体,
本次一共有五个脚本,分别为:
Subpool:对象池用于存放 相同类型 的游戏对象,不需要继承与MonoBehaviour;
IControl:接口类 : 用于管理对象的卵生和回收;
PoolControll:用于管理存放各种类型的游戏对象的对象池 管理类以K-Value来管理;
Sphere 和 Player脚本用来测试,将这两个脚本挂载到Sphere的身上,连续按下空格键实现对象池的回收和创建效果(当对象生成3s后,及活性设置为false),可以亲自尝试一下,
接下来是代码实现:
创建一个脚本命名为 Subpool

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// 
/// 1、从对象池中取一个游戏对象
/// 2、回收某一个游戏对象
/// 3、回收所有游戏对象
/// 4、检查某个游戏对象是否在池子里
/// 
public class Subpool {

    //对象池,里面存放场景中所需要的游戏对象
    List pool = new List ();
    //要创建的游戏物体的预设体
    GameObject prefab;

    //返回预设体的名字,预设体的名字和对象池的名字一致
    //在管理对象池的类里面,可以通过预设体的名字找到相对应的对象池
    public string name{

        get{

            return prefab.name;
        }
    }
    //自定义构造方法
    public Subpool(GameObject obj){

        prefab = obj;
    }

    //1、从对象池中获取一个对象

    public GameObject SubPoolSpawn(){

        GameObject obj = null;

        //遍历集合中所有的对象。如果有,就拿来用,如果没有,就创建
        foreach (GameObject item in pool) {

            //如果游戏对象处于未激活状态,说明该对象可用
            if (item.activeSelf == false) {

                obj = item;
                break;
            }
        }
        //对象池里面没有可用的对象
        if (obj == null) {

            //创建一个新的游戏对象
            obj = GameObject.Instantiate(prefab) as GameObject;
            //把新创建的游戏对象加入到池子里面
            pool.Add(obj);
        }
        //游戏对象的状态设置为激活状态
        obj.SetActive (true);
        //通过子类实例化接口对象,子类的脚本组件继承并实现了接口中的方法
        // control里面存的就是该类实现的方法
        //这个地方的游戏对象暂时就是一个子弹,但是需要继承IControl接口
        IControl control = obj.GetComponent();
        if (control != null) {

            control.Spwan ();
        }


        return obj;
    } 

    /// 2、回收某一个游戏对象
    public void SubPoolUnSpawn(GameObject obj){

        //如果对象池的集合包含该游戏对象
        if (SubpoolContains(obj)) {
            IControl control = obj.GetComponent ();
            control.UnSpwan ();
        }
        //设置激活性
        obj.SetActive(false);
    }

    // 3、回收所有游戏对象
    public void SubPoolUnSpawnAll(GameObject obj){

        //遍历对象池
        foreach (GameObject item in pool) {
            if (item.activeSelf == true) {
                //回收对象
                SubPoolUnSpawn (item);
            }
        }
    }
    // 4、检查某个游戏对象是否在池子里
    public bool SubpoolContains(GameObject obj){
        //返回
        return pool.Contains (obj);
    }
}

然后继续创建一个脚本命名为 IControl这是一个接口类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//接口类 : 用于管理对象的卵生和回收
public interface IControl {

    //卵生对象
    void Spwan();
    //回收对象
    void UnSpwan();
}

再创建一个脚本(命名为 : PoolControl)用于管理存放各种类型的游戏对象的对象池,管理类以K-Value来管理脚本内容是:
1、是一个单例类;
2、有添加对象池的方法;
3、通过找到对象调用对象池里面创建的游戏对象的方法返回;
4、回收游戏对象;
下面是具体脚本内容:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PoolControll{

    #region 单例
    //内建静态实例
    private  static  PoolControll instance;
    //构造⽅方法必须设为私有
    private PoolControll(){

        } 
    public static PoolControll Instance
        {
            get{  
                if(instance == null) {
                instance = new PoolControll();//为实例初始化
                }
                return  instance;
            }
        }

    #endregion


    //创建字典,根据预设体的名字,找到对象池
    //存放各种类型的的对象池的集合
    Dictionary<string,Subpool> poolDic = new Dictionary<string, Subpool>();
    //1、添加对象池,外界不能来调用
    private void Register(string name){
        //根据名字去创建池子
        GameObject obj = Resources.Load(name) as GameObject;
        Subpool pool = new Subpool (obj);
        //把池子添加到字典里
        poolDic.Add(name,pool);

    }
    //2、获取对象池里面额游戏对象
    public GameObject Spawn(string name){

        //如果没有这个游戏对象对应的池子
        if (!poolDic.ContainsKey(name)) {
            Register (name);
        }
        //根据名字找到池子
        Subpool pool = poolDic[name];
        return pool.SubPoolSpawn ();
    }
    //回收一个游戏对象
    public void UnSpawn(GameObject obj){
        //遍历所有的池子
        foreach (Subpool pool in poolDic.Values) {

            //如果对象池里面包含这个游戏对象
            if (pool.SubpoolContains(obj)) {
                pool.SubPoolUnSpawn (obj);
                break;
            }
        }
    }
}

然后再次创建两个脚本命名为 :SpherePlayer
注意:这个脚本用来测试对象池是否成功
Sphere脚本如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour,IControl {

    void Start () {

    }


    //卵生对象
    public  void Spwan(){
        //为了测试,我们在取出一个对象后,让它3S中收回
        Invoke ("BulletUnSpawn", 3f);
        print ("从对象池中取出一个游戏对象");

    }
    //回收对象
    public  void UnSpwan(){

        print ("把游戏对象回收到对象池了");

    }
    void BulletUnSpawn(){

        //回收游戏对象
        PoolControll.Instance.UnSpawn(gameObject);
        //重置游戏对象
        transform.position = Vector3.zero;
    }
    void Update () {

        transform.position += Vector3.forward * Time.deltaTime * 50;

    }

}

Player脚本如下所示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour {

    // Update is called once per frame
    void Update () {
        if (Input.GetKeyDown(KeyCode.Space)) {

            PoolControll.Instance.Spawn ("Sphere");
        }
    }
}

你可能感兴趣的:(学习笔记)