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

来源:互联网 发布:阿里云控制台 编辑:程序博客网 时间:2024/06/02 06:24

写的第一篇博客,说实话是有点激动的,以后每个周会留下我的一些学习笔记与感想,将会一直学习下去,欢迎一起交流学习, 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;/// <summary>/// 1、从对象池中取一个游戏对象/// 2、回收某一个游戏对象/// 3、回收所有游戏对象/// 4、检查某个游戏对象是否在池子里/// </summary>public class Subpool {    //对象池,里面存放场景中所需要的游戏对象    List<GameObject> pool = new List<GameObject> ();    //要创建的游戏物体的预设体    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<IControl>();        if (control != null) {            control.Spwan ();        }        return obj;    }     /// 2、回收某一个游戏对象    public void SubPoolUnSpawn(GameObject obj){        //如果对象池的集合包含该游戏对象        if (SubpoolContains(obj)) {            IControl control = obj.GetComponent<IControl> ();            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");        }    }}
0 0
原创粉丝点击