我们知道不限于工程 代码之中 万事之中 总是不断寻找最好的方案 方法去解决同一样事 当然 一个事物 这样做可以 那样做也行 但是我们所要的解决当然是基于一种理解下 的“最好” 比如 计算1+2+3+...100点结果 可以咯 你可以1+2=3 3+3 =6.。。 对啊 结果是可以出来 但是我们所说的计算这个值绝对是有意义的计算 同样的 在接触一样新事物的时候 我们可能为了实现功能 采取的就是1+2=3 3+3=6.。。。 随着学习的深入与理解 自然而然会有新的方案 没错 在程序中 对象池就是解决重复利用同一资源而出现的新方案 是不是最好 我现在的知识有限 基于目前 我所能用的知识 却是最好的
什么是对象池?我们将需要重复利用对象存储在一个池子中,当需要时在再次使用,而不是每次都实例化一个新的对象。 比如我们在工程中开枪射击所用到的“子弹” 子弹射出去后 会消失 当再次射击 是否重新生成呢? 可不可以把消失的子弹在此拿出来使用呢? 让我们来试一下
我们已子弹为模型-预设体来简单讲解一下
三个脚本
1.ObjectPool脚本 (保存对象到对象池与获取对象)该脚本不需要挂在任何游戏对象上
2.GameManager脚本(加载生成对象)第一次加载预设体 该脚本挂在一个空物体上就行
3.SphereObj脚本 (控制保存到对象池的对象)挂在预设体上
ObjectPool脚本 ()注意 此脚本不继承MonoBehaviour 否则保存到对象池不成功 为什么? 留给读者自己思考一下
usingSystem.Collections;
usingSystem.Collections.Generic;
using UnityEngine ;
public class ObjectPool{
// 创建单例
public static ObjectPool _instant ;
public static ObjectPool GetInstant()
{
if(_instant ==null)
{
_instant = new ObjectPool() ;
}
return _instant ;
}
// 对象池 就是一个字典 键是预设体的名字string类型 值是一个数组存储GameObject的数组
private Dictionary<string,List<GameObject>> pool ;
// 字典需要初始化 在构造方法中初始化
public ObjectPool(){
pool = new Dictionary<string,List<GameObject>>();
}
// 获取对象 也是判断对象池是否有这个对象
public GameObject GetObj(string objName,Vector3pos,Quaternionqua))
{
// 要获取的对象
GameObject currentObj = null ;
// 根据键去判断字典是否有这个对象 也是判断对象池中是否有
if(pool.ContainsKey(objName))
{
// 对象池中有剩余 这句话的意思是说 当我射击子弹很快很快或者需求子弹数大时 对象池存储的对象是否够 不够就重新产生且添加到对象池
if(pool[objName].count>0)
{
//获取当前的对象
currentObj = pool[objName][0] ;
// 一个对象利用完取出去后 就要移除 为啥?不是添加吗 怎么还要从对象池中移除呢 我们说了。有时候需求子弹数很大 利用过的在一定时间内就不能利用了 在后面的方法会在此添加进来
pool[objeName].Remove(currentObj) ;
}
}
// 如果对象为空 意思是第一次程序运行 还没有一个产生 或者是需求大 对象池中没有这么多 对象池就增加对象
if(currentObj==Null)
{
//实例化对象
currentObj = GameManager.instance.Load(objName) ;
// 设置好对象的位置和角度 就是子弹的位置和角度
currentObj.transform.position = pos ;
currentObj.transform.rotation = qua ;
//激活对象
currentObj.SetActive(true);
}
// 保存对象
public void SaveObj(GameObject go)
{
go.setActive(false) ;
//获取对象池名称
stringobjPoolName=go.name.Replace("(Clone)","");
Debug.Log(objPoolName);
//如果该类型的对象池存在
if(pool.ContainsKey(objPoolName))
{
//将对象保存到对象池
pool[objPoolName].Add(go);
}
else
{
//创建对象池,并保存对象到对象池
pool.Add(objPoolName,newList()
{
go
});
Debug.Log(objPoolName);
}
}
2.GameManager脚本
using System.Collections ;
using System.Collections.Generic ;
using UnityEngine ;
public class GameManager:MonBehaviour
{
// 单例
public static GameManager instance ;
void Awake()
{
instance = this ;
}
// 加载并声称对象
public GameObject LoadObj(string objName)
{
// 加载预设体 "Prefab"是创建的文件夹
GameObject currentPrefab = Resources.LoAD<GameObject>("Prefab/"+objName);
return Instantite(currentPregab) ;
}
void Start()
{
}
// 这里我们模拟 每按下空格 产生一个子弹
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
ObjectPool.GetInstant(),GetObj("Sphere",Vector3.zero,Quaternion.identity);
}
}
}
SphereObj脚本 这个是加到对象池中对象所带的脚本 这里我们用到协程 每2s去调用一次 读者可以自己去试一下 看自己按空格的手速有多快 最多能有几个预设体产生 手速越快 对象池能提供的不足 就会重新产生一个来补充 并添加到对象池
usingSystem.Collections;
usingSystem.Collections.Generic;
usingUnityEngine;
publicclassSphereObj:MonoBehaviour{
voidOnEnable()
{
StartCoroutine(Recycle());
}
IEnumeratorRecycle()
{
yieldreturnnewWaitForSeconds(2f);
ObjectPool.GetInstant().SaveObj(gameObject);
}
//Usethisforinitialization
voidStart(){
}
//Updateiscalledonceperframe
voidUpdate(){
}
}