Unity简单对象缓冲池技术

一、建立对象缓冲池脚本

/***
 *
 *  Title: 
 *         预加载与对象缓冲池技术
 *         
 *                  对象缓冲池管理器        
 * 
 *  Description:
 *        基本原理:
 *        通过池管理思路,在游戏初始化的时候,生成一个初始的池存放我们要复用的元素。
 *        当要用到游戏对象时,从池中取出;不再需要的时候,不直接删除对象而是把对象重新回收到“池”中。
 *        这样就避免了对内存中大量对象的反复实例化与回收垃圾处理,提高了资源的利用率。      
 *
 *  Date: 2018
 * 
 *  Version: 1.0
 *
 *  Modify Recorder:
 *     
 */
using UnityEngine;
using System.Collections.Generic;

public class ObjectPoolManager : MonoBehaviour{
        public GameObject ObjPrefab;                                           //池中所使用的元素预设
        public Transform TranObjPrefabParent;                                  //池中所使用的元素预设的父对象
        public int InitialCapacity;                                            //初始容量

        private int _startCapacityIndex;                                       //初始下标
        private List<int> _avaliableIndex;                                     //可用“池”游戏对象下标
        private Dictionary<int, GameObject> _totalObjList;                     //池中全部元素的容器


        /// <summary>
        /// 初始化缓冲池
        /// </summary>
        void Awake(){
            _avaliableIndex = new List<int>(InitialCapacity);
            _totalObjList = new Dictionary<int, GameObject>(InitialCapacity);
            //初始化池
            expandPool();
        }

        /// <summary>
        /// 取得游戏对象。
        /// </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);
            //指定Id的游戏对象下标,重行进入可用“池”下标集合中
            _avaliableIndex.Add(id);
        }

        /// <summary>
        /// 扩展池
        /// </summary>
        private void expandPool(){
            int start = _startCapacityIndex;
            int end = _startCapacityIndex + InitialCapacity;

            for (int i = start; i < end; i++){
                //加入验证判断,避免在多个请求同时触发扩展池需求
                if (_totalObjList.ContainsKey(i))
                continue;
                GameObject newObj = Instantiate(ObjPrefab) as GameObject;
                //生成的池对象增加父对象,容易查看与检查。
                newObj.transform.parent = TranObjPrefabParent.transform;
                //每一个生成的对象,设置暂时不可用。
                newObj.SetActive(false);
                //下标记入“池”可用下标集合中。
                _avaliableIndex.Add(i);
                //新产生的对象,并入本池容器集合中。
                _totalObjList.Add(i, newObj);
            }
            //扩展“初始下标”。
            _startCapacityIndex = end;
        }
    }//Class_end

二、给池中的预设对象添加回收脚本

/***
 *
 *  Title: 
 *         预加载与对象缓冲池技术
 *
 *  Description:
 *        功能:
 *            回收对象脚本
 *
 *  Date: 2018
 * 
 *  Version: 1.0
 *
 *  Modify Recorder:
 *     
 */

using UnityEngine;
using System.Collections;

public class DestroyObjUseBufferPool : MonoBehaviour 
{
    public GameObject GoPoolManager;                       //池管理器
    private ObjectPoolManager _PoolManagerObj;             //对象池管理器
    private int _IntBulletID = 0;                          //子弹ID编号 

    void Start()
    {
        _PoolManagerObj = GoPoolManager.GetComponent<ObjectPoolManager>();
    }

    /// <summary>
    /// 游戏对象超出摄像机可视范围,则此对象进行“回收”。
    /// </summary>
    void OnBecameInvisible()
    {
        _PoolManagerObj.RecyleObj(_IntBulletID);
    }

    /// <summary>
    /// 接收本脚本所属对象的ID编号,用于回收使用。
    /// </summary>
    /// <param name="intBulleteNumber"></param>
    public void ReceiveBulletID(int intBulleteNumber)
    {
        _IntBulletID = intBulleteNumber;
    }
}

三、编写好对象缓冲池的内容之后就需要配合项目使用(以射击项目为例)

/***
 *
 *  Title: 
 *         预加载与对象缓冲池技术
 *
 *  Description:
 *        功能:
 *            学习“对象缓冲池”技术
 *            利用缓冲池实现射击代码
 *
 *  Date: 2018
 * 
 *  Version: 1.0
 *
 *  Modify Recorder:
 *     
 */
using UnityEngine;
using System.Collections;
using System.Collections.Generic;   

public class ShottingUseBufferPool : MonoBehaviour{
    public Texture Texture_ShootingCursor;                 //射击瞄准星
    public GameObject G0_CubeOrigianl;                     //射击原型物体
    public Transform Tran_TargetWallParentPosition;        //靶墙数组父对象
    public Transform Tran_BulletParentPosition;            //子弹数组父对象
    private Vector3 _VecRayPosion;                         //射线透射的坐标

    public GameObject GoPoolManager;                       //池管理器  
    public GameObject GoBulletPrefabsOriginal;             //子弹原型(预设) 
    private ObjectPoolManager boPoolManager;               //池管理器对象
    private GameObject goCloneBullete;                     //克隆的子弹

    /// <summary>
    /// 初始化场景
    /// </summary>
    void Start(){
        //隐藏鼠标。
        Cursor.visible = false;

        //取得池管理器
        boPoolManager = GoPoolManager.GetComponent<ObjectPoolManager>();     

        //建立射击目标靶墙
        for (int j = 1; j <= 5; j++)
        {
            for (int i = 1; i <= 5; i++)
            {
                GameObject goClone = (GameObject)Instantiate(G0_CubeOrigianl);
                goClone.transform.position = new Vector3(G0_CubeOrigianl.transform.position.x + i,
                    G0_CubeOrigianl.transform.position.y + j, G0_CubeOrigianl.transform.position.z);
                //确定子弹的父对象
                goClone.transform.parent = Tran_TargetWallParentPosition;
            }
        }
    }//Start_end

    /// <summary>
    /// 绘制射击光标
    /// </summary>
    void OnGUI(){
        Vector3 vecPos = Input.mousePosition;
        GUI.DrawTexture(new Rect(vecPos.x - Texture_ShootingCursor.width / 2,
            Screen.height - vecPos.y - Texture_ShootingCursor.height / 2, Texture_ShootingCursor.width,
            Texture_ShootingCursor.height), Texture_ShootingCursor);
    }//OnGUI_end

    /// <summary>
    /// 射击逻辑处理
    /// </summary>
    void Update(){
        //射线处理
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit))
        {
            //获取射线碰撞到碰撞体的方位
            _VecRayPosion = hit.point;
        }

        //如果鼠标点击左键,则发射子弹。
        if (Input.GetMouseButtonDown(0)){
            //创建子弹
            KeyValuePair<int, GameObject> kvObj = boPoolManager.PickObj();
            if (kvObj.Value != null){
                goCloneBullete = kvObj.Value;
                goCloneBullete.SendMessage("ReceiveBulletID", kvObj.Key);
            }
            //添加子弹刚体
            if (!goCloneBullete.GetComponent<Rigidbody>()){
                goCloneBullete.AddComponent<Rigidbody>();
            }
            //子弹的位置
            goCloneBullete.transform.position = new Vector3(Camera.main.transform.position.x, Camera.main.transform.position.y, Camera.main.transform.position.z + 0.3F);
            //给子弹加“力”
            goCloneBullete.GetComponent<Rigidbody>().AddForce((_VecRayPosion - goCloneBullete.transform.position) * 10F, ForceMode.Impulse);  
        }
    }//Update_end  

}//Class_end

注意:该内容来自《Unity3D/2D游戏开发从0到1》27章 

猜你喜欢

转载自blog.csdn.net/xiaochenXIHUA/article/details/83421931