一、建立对象缓冲池脚本
/***
*
* 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章