Unity3D通过对象池模式 管理场景中的元素

来源:互联网 发布:python实现支付宝登录 编辑:程序博客网 时间:2024/04/28 15:01
using UnityEngine;
using System.Collections;
using System.Collections.Generic;


public class ObjPoolMgr : MonoBehaviour
{
    #region 公共属性
    /// <summary>
    /// 池中所使用的元素Prefab
    /// </summary>
    public GameObject ObjPrefab;
    /// <summary>
    /// 初始容量
    /// </summary>
    public int InitialCapacity;
    #endregion


    #region 私有属性
    /// <summary>
    /// 初始下标
    /// </summary>
    private int _startCapacityIndex;
    /// <summary>
    /// 可用下标
    /// </summary>
    private List<int> _avaliableIndex;
    /// <summary>
    /// 池中全部元素
    /// </summary>
    private Dictionary<int, GameObject> _totalObjList;
    #endregion


    #region 事件/重写方法
    void Start()
    {
        _avaliableIndex = new List<int>(InitialCapacity);
        _totalObjList = new Dictionary<int, GameObject>(InitialCapacity);
        ExpandPool();
    }
    #endregion


    #region 公共方法
    /// <summary>
    /// 取得一个物体,返回值 1,obj代表,ID是1的物体被取到,ID可以用来归还物体的时候用到
    /// </summary>
    /// <returns></returns>
    public KeyValuePair<int, GameObject> PickObj()
    {
        if (_avaliableIndex.Count == 0)
            ExpandPool();
        int id = _avaliableIndex[0];
        _avaliableIndex.Remove(id);
        _totalObjList[id].SetActive(true);
        return new KeyValuePair<int, GameObject>(id, _totalObjList[id]);
    }
    /// <summary>
    /// 回收一个物体
    /// </summary>
    /// <param name="id"></param>
    public void RecyleObj(int id)
    {
        _totalObjList[id].SetActive(false);
        _totalObjList[id].transform.parent = transform;
        _avaliableIndex.Add(id);
    }
    #endregion
    //放回池中的时候,我们把元素的父节点也设置为池元素,这样做是避免当元素挂载的对象在内存中被删除的时候,元素也被删除的问题。


    #region 私有方法
    /// <summary>
    /// 扩展池
    /// </summary>
    private void ExpandPool()
    {
        int start = _startCapacityIndex;
        int end = _startCapacityIndex + InitialCapacity;
        for (int i = start; i < end; i++)
        {
            //加入验证判断,避免在极端情况下
            //(1:两次申请同时发起 2:第二次申请的时候,第一次还没有扩展任何元素)时
            //,往字典添加相同的主键,导致游戏报错闪退的问题
            if (_totalObjList.ContainsKey(i))
                continue;


            GameObject newObj = Instantiate(ObjPrefab) as GameObject;
            newObj.SetActive(false);
            _avaliableIndex.Add(i);
            _totalObjList.Add(i, newObj);
        }
        _startCapacityIndex = end;
    }
    #endregion
}


//在游戏场景中,我们有时候会需要复用一些游戏物体,比如常见的子弹、子弹碰撞类,某些情况下,怪物也可以使用池管理,UI部分比如:血条、文字等等


//这些元素共同的特性是:存在固定生命周期,使用比较频繁,场景中大量使用。


//所以,我们就通过池管理思路,在游戏初始化的时候,生成一个初始的池,存放我们要复用的元素,


//当要用到时,从池中取出;生命周期结束,放回到池中。


//代码
//这个池的参数有两个:1池中存放的元素 2 池的初始容量(如果池不够了,则会按照这个容量进行扩展)


//声明方式:
//ObjectPoolManager _bulletPool = GameObject.Find("你挂载的物体名称").GetComponent<ObjectPoolManager>();
//取出元素:
//KeyValuePair<int, GameObject> bulletKV = _bulletPool.PickObj();
//放回:
//_bulletPool.RecyleObj(bulletID);
//适用
//子弹 子弹碰撞特效 攻击特效 被攻击特效 怪物血条(基于NGUI制作) 场景部分文字(施法时、怪物被攻击时,基于NGUI制作) 等等
0 0