对象池原理

对象池模块结构如下:

对象池原理_第1张图片

对象池管理者管理各类对象池,所有池子存入字典。通过key索引获取。对于需要频繁创建的东西配置相应的对象池,。如角色,炮弹等。各类对象池内存有对应的对象,并且开放相应的获取和回收接口。由对象池管理者统一管理。

对象 可以通过resources加载或者AB包方式。这里采用resource加载。对象信息报含有资源路径,资源名称,初始化的个数即池子里存放个数,对象object和需要挂载的脚本等等信息。

/// 
/// 资源对象,对象池中分配的
/// 
[Serializable]
public class SourceObject
{
    public string sourceDirect; //资源路径
    public string sourceName; //资源的名称
    public GameObject prefab;//prefab引用
    public int preAllocCount = 8;//初始化时预分配对象数量
    public int autoIncreaseCount = 8;//池中可增加对象数量
    public Type scriptType = null;	//对象挂载的脚本名称,反射获取
}
using UnityEngine;
using System.Collections;
using System;

//预设信息,用来回收时调用此信息
public class PrefabInfo : MonoBehaviour
{
    public string sourceName;
    //[HideInInspector]
    public float lifetime = 0;  //-1表示不执行OnEnable
    private ParticleSystem ps = null;   //回收特效要根据特效的播放时间
    private Coroutine waitCorou = null; //执行的协程
    private event ObjectPoolMgr.RecycleBack recycleBack = null;    //回收时的回调
    public bool isRecycle = true;   //是否已经回收的标志位

    public virtual void Init(string sourceName)
    {
        this.sourceName = sourceName;
        isRecycle = true;
        ps = GetComponent();
    }

    public virtual void OnEnable()
    {
        if (lifetime == -1)
            return;
        if (lifetime > 0)
        {
            Recycle(lifetime);
        }
        else if (ps != null)
        {
            //ps.Stop(true);
            //ps.Play(true);
            if (!ps.isPlaying)
                ps.Play(true);
            if (!ps.main.loop)
            {
                waitCorou = StartCoroutine(recyclePS());
            }
        }
    }

    public virtual void OnDisable()
    {
        if (waitCorou != null)
            StopCoroutine(waitCorou);
    }

    private IEnumerator recycleWaitTime(float lifetime)
    {
        yield return new WaitForSeconds(lifetime);
        ObjectPoolMgr._Instance.Recycle(this, recycleBack);
    }

    private IEnumerator recyclePS()
    {
        while (ps.isPlaying)
            yield return null;
        ps.Stop(true);
        ObjectPoolMgr._Instance.Recycle(this, recycleBack);
    }

    //主动回收,外部调用
    public void Recycle(float waitTime = 0)
    {
        if (isRecycle)
            return;

        if (waitCorou != null)
            StopCoroutine(waitCorou);

        if (waitTime == 0)   //立即回收
        {
            ObjectPoolMgr._Instance.Recycle(this, recycleBack);
        }
        else if (waitTime > 0)   //等待回收
        {
            if (!gameObject.activeSelf)
                ObjectPoolMgr._Instance.Recycle(this, recycleBack);
            else
            {
                if (ps != null)
                    ps.Stop();
                waitCorou = StartCoroutine(recycleWaitTime(waitTime));
            }
        }
    }

    //添加回收的回调方法
    public void AddRecycleBack(ObjectPoolMgr.RecycleBack back)
    {
        recycleBack += back;
    }

    //移除回收的回调
    public void RemoveRecycleBack(ObjectPoolMgr.RecycleBack back)
    {
        recycleBack -= back;
    }

    //删除回调
    public void DelRecycleBack()
    {
        recycleBack = null;
    }

}

对象池负责实例化对象,存取等操作。抽象父类,不同对象池可能会有不同其他操作,但是都需要有初始化,获取回收操作。生成的实例对象存入队列。

using UnityEngine;
using System.Collections;
using System;

//对象池的父类
public class ObjectPool : MonoBehaviour
{
    protected SourceObject preSource = null;   //配置的资源信息
    protected Queue queue = new Queue();//用来保存池中对象
    //public int nowCount = 0;    //当前池中对象,测试用*******************************************************

    //对象池初始化
    public virtual void Init(SourceObject source)
    {
        preSource = source;
        if (preSource.prefab == null)
            Debug.LogError("初始化对象池失败,预设体为null => " + preSource.sourceName.ToString());
        for (int i = 0; i < preSource.preAllocCount; i++)
        {
            //实例化
            GameObject returnObj = Instantiate(preSource.prefab, new Vector3(0, 0, 0), Quaternion.identity) as GameObject;
            returnObj.name = preSource.sourceName;
            PrefabInfo pre = null;
            if (preSource.scriptType != null)
                pre = returnObj.AddComponent(preSource.scriptType) as PrefabInfo;
            else
                pre = returnObj.AddComponent();
            pre.Init(preSource.sourceName);
            queue.Enqueue(pre);//入队,可进行reset
            returnObj.SetActive(false); //不显示
            returnObj.transform.SetParent(transform, true);

        }
        //nowCount = queue.Count;
    }

    public virtual PrefabInfo alloc(float lifetime)
    {
        //使用PrefabInfo脚本保存returnObj的一些信息
        PrefabInfo info = null;
        if (queue.Count > 0)
        {
            //池中有待分配对象
            info = (PrefabInfo)queue.Dequeue();//分配
        }
        else
        {
            //池中没有对象了,实例化一个
            GameObject returnObj = Instantiate(preSource.prefab, new Vector3(0, 0, 0), Quaternion.identity) as GameObject;
            if (preSource.scriptType != null)
                info = returnObj.AddComponent(preSource.scriptType) as PrefabInfo;
            else
                info = returnObj.AddComponent();
            info.Init(preSource.sourceName);
            returnObj.transform.SetParent(transform, true);
            returnObj.SetActive(false);//防止挂在returnObj上的脚本自动开始执行
        }

        info.lifetime = lifetime;
        info.isRecycle = false;
        info.gameObject.SetActive(true);  //显示
        ObjectPoolMgr._Instance.AddPrefabInfo(info);    //保存
        return info;
    }

    public virtual void recycle(PrefabInfo obj)
    {
        //待分配对象已经在对象池中
        if (queue.Contains(obj))
        {
            Debug.LogWarning("the obj " + obj.name + " be recycle twice!");
            return;
        }
        if (queue.Count >= preSource.preAllocCount + preSource.autoIncreaseCount)
        {
            Destroy(obj.gameObject);//当前池中object数量已满,直接销毁
        }
        else
        {
            queue.Enqueue(obj);//入队,并进行reset
            obj.transform.SetParent(transform, true);
            obj.gameObject.SetActive(false);
        }
        //nowCount = queue.Count;
    }

}

管理者

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;

/// 
/// 资源对象,对象池中分配的
/// 
[Serializable]
public class SourceObject
{
    public string sourceDirect; //资源路径
    public string sourceName; //资源的名称
    public GameObject prefab;//prefab引用
    public int preAllocCount = 8;//初始化时预分配对象数量
    public int autoIncreaseCount = 8;//池中可增加对象数量
    public Type scriptType = null;	//对象挂载的脚本名称,反射获取
}

public class ObjectPoolMgr : MonoBehaviour
{
    private static ObjectPoolMgr instance = null;
    public static ObjectPoolMgr _Instance
    {
        get
        {
            return instance;
        }
    }

    private Dictionary DictPool = new Dictionary();  //对象池字典
    public List activeList = new List();    //从对象池中分配显示的对象
    public delegate void RecycleBack(); //回收前的操作

    // Use this for initialization
    public IEnumerator Init()
    {
        instance = this;

        ////初始化玩家模型
        //SourceObject sourceInfo = new SourceObject()
        //{
        //    sourceDirect = "Prefabs/Model/",
        //    sourceName = "Player01",
        //    preAllocCount = 0,
        //    autoIncreaseCount = 0,
        //    scriptType = typeof(AnimatorCallBack),
        //};
        //yield return StartCoroutine(InitPool(sourceInfo));
        yield return null;
    }

    ////初始化场景跳板对象池
    //public IEnumerator  InitBoardPool(SceneData data)
    //{
    //    Debug.Log("初始化跳板");
    //    SourceObject sourceInfo = null;
    //    for (int i = 0; i < data.boardIDs.Length; i++)
    //    {
    //        int boardId = data.boardIDs[i];
    //        BoardData item = GameDataManager.localData.boardDataBase.GetDataByID(boardId);
    //        sourceInfo = new SourceObject()
    //        {
    //            sourceDirect = data.GetBoardPath (),
    //            sourceName = item.model,
    //            preAllocCount = 2,
    //            autoIncreaseCount = 2,
    //            scriptType = typeof(BoardItem),
    //        };
    //        yield return StartCoroutine(InitPool(sourceInfo));
    //    }
    //}

    /// 
    /// 初始化资源对象池
    /// 
    /// 
    private IEnumerator InitPool(SourceObject sourceObj)
    {
        //加载预设对象
        if (sourceObj.prefab == null)
        {
            var loadOperation = AssetsManager._Instance.LoadAssetAsync(sourceObj.sourceDirect, sourceObj.sourceName, true, null, LoadAssetMode.Sync);
            yield return loadOperation;
            sourceObj.prefab = loadOperation.GetAsset();
        }
        GameObject poolObj = new GameObject(sourceObj.sourceName + "Pool");
        poolObj.transform.SetParent(transform, true);
        ObjectPool pool = null;
        Type t = Type.GetType(sourceObj.sourceName + "ObjectPool"); //获取特殊的对象池
        if (t != null)
            pool = (ObjectPool)poolObj.AddComponent(t);
        else
            pool = poolObj.AddComponent();

        if (DictPool.ContainsKey(sourceObj.sourceName))
            Debug.Log("存在相同的对象池==>>" + sourceObj.sourceName);
        else
        {
            pool.Init(sourceObj);
            DictPool.Add(sourceObj.sourceName, pool);
        }
    }

    /// 
    /// 从对象池申请对象的重载
    /// 
    /// 对象id
    /// 位置信息
    /// 旋转
    /// 活跃时间
    /// 
    public PrefabInfo Alloc(string sourceName, Vector3 pos, Quaternion rot, float lifetime = 0)
    {
        PrefabInfo info = Alloc(sourceName, lifetime);
        if (info != null)
        {
            info.transform.position = pos;
            info.transform.rotation = rot;
        }
        else
            Debug.LogError("无法从对象池获取=>" + sourceName);

        return info;
    }

    /// 
    /// 从对象池申请对象的重载
    /// 
    /// 
    /// lifeTime > 0:lifeTime秒后调用recycle方法回收自己。lifeTime = 0: 不自动回收对象,需游戏主动调用recycle回收。lifeTime< 0: 返回值null。
    /// 
    public PrefabInfo Alloc(string sourceName, float lifetime = 0)
    {
        //根据传入type取出或创建对应类型对象池
        ObjectPool subPool = _getpool(sourceName);
        //从对象池中取一个对象返回
        PrefabInfo returnPre = null;
        if (subPool != null)
            returnPre = subPool.alloc(lifetime);

        return returnPre;
    }

    //回收对象
    public void Recycle(PrefabInfo recyclePre, RecycleBack back = null)
    {
        if (back != null)
        {
            back.Invoke();
        }
        recyclePre.DelRecycleBack();
        recyclePre.isRecycle = true;
        if (string.IsNullOrEmpty(recyclePre.sourceName))
            Destroy(recyclePre.gameObject);    //直接销毁
        else
        {
            activeList.Remove(recyclePre);  //存活对象列表中移除
            ObjectPool returnPool = _getpool(recyclePre.sourceName);
            if (returnPool != null)
                returnPool.recycle(recyclePre);
            else if(recyclePre != null)
                Destroy(recyclePre.gameObject);
        }

    }

    public void Recycle(GameObject obj)
    {
        Recycle(obj.GetComponent());
    }

    ObjectPool _getpool(string sourceName)
    {
        ObjectPool returnPool = null;

        if (!DictPool.TryGetValue(sourceName, out returnPool))
        {
            Debug.LogError("不存在对象池==>>" + sourceName);
        }

        return returnPool;
    }

    //分配的对象要保存
    public void AddPrefabInfo(PrefabInfo pre)
    {
        activeList.Add(pre);
    }

    //回收所有对象
    public void RecycleAll()
    {
        PrefabInfo[] prefabs = activeList.ToArray();    //避免回收时从列表中移除,导致列表遍历出现问题
        for (int i = 0; i < prefabs.Length; i++)
        {
            if (!prefabs[i].isRecycle)
                prefabs[i].Recycle();
        }
        activeList.Clear();
    }

    //移除对象池
    public void RecyclePool(string sourceName)
    {
        ObjectPool pool = _getpool(sourceName);
        if (pool != null)
        {
            DictPool.Remove(sourceName);
            Destroy(pool.gameObject);
        }
    }
}

 

你可能感兴趣的:(代码,对象池)