教程链接11:00
一、大致思路:
1.创建一个字典保存所有对象池,并将对象池与对象池名称联系起来。
2.单例模式来储存数据。
3.一个方法调用对象池的对象,一个方法将弃用的对象放回对象池。
4.管理实例化的对象,让其在运行窗口上看起来不杂乱。
5.对象池的使用。
二、观前提示:
注意代码中的数据与游戏物体的关系
这里我们希望在窗口中通过“ObjectPool”来作为不同对象池的父物体。将每个对象池物体的名字都设置为相应预制体的名字+"Pool",并作为相应对象的父物体。效果如下。
实际对象池的数值储存情况如下
三、代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPool
{
private static ObjectPool instance;//储存当前实例
//通过字典可以快速的根据名称查找到相应对象池,使用队列可以方便的删减元素(无需指定元素)
private Dictionary<string, Queue<GameObject>> objectPool = new Dictionary<string, Queue<GameObject>>();
private GameObject pool;//作为所有对象池的父物体,便于管理。
//单例模式
public static ObjectPool Instance
{
get
{
if (instance == null)
{
instance = new ObjectPool();
}
return instance;
}
}
先初步写一下调用方法
public GameObject GetObject(GameObject prefab)
{
GameObject _object;//稍后我们将所取出的对象绑定在该物体上返回
/*现在已经知道了所需的游戏对象,我们要从对象池中获得这个对象。
现在分为三种情况:
①相应对象池中有剩余对象
②相应对象池中没有剩余对象
③没有相应对象池
对应的处理办法:
①取出相应对象池的对象,激活,并返回
②实例化一个对象,并将其放入对象池中,执行①
③实例化一个对象,(创建新的对象池)并将其放入对象池中,执行①
使用if区分不同的处理方法,将共同的处理方法放在外面
这里在PushObject中创建新的对象池,可能是为了精简下代码(也有可能有其他理由,望指出)
*/
if (objectPool.ContainsKey(prefab.name)==false||objectPool[prefab.name].Count == 0)//③
{
_object = GameObject.Instantiate(prefab);//实例化一个所需对象
//稍后向此处插入代码设置新对象的父子关系,维持unity中游戏对象的整洁性
PushObject(_object);//将对象放入对象池中
}
_object = objectPool[prefab.name].Dequeue();//取出相应对象并激活
_object.SetActive(true);
return _object;
}
再编写"PushObject"
/*我们得到了需要放入对象池的对象,
现存在两种情况
①存在对应对象池
②不存在对应对象池
对应的处理办法
①将对象放入相应对象池中并使其失效
②向字典中添加新的对象池元素,执行①*/
public void PushObject(GameObject prefab)
{
string _name = prefab.name.Replace("(Clone)", string.Empty);//实例化的物体后都会带有“(Clone)”
if (objectPool.ContainsKey(_name) == false)//②
{
objectPool.Add(_name, new Queue<GameObject>());//向字典中添加新的对象池元素
}
//将对象放入相应对象池中并使其失效
objectPool[_name].Enqueue(prefab);
prefab.SetActive(false);
}
现在一个基本的对象池就已经成型了,但我们还需要让编辑窗口看起来没那么杂乱,所以要分配不同对象之间的关系。因为物体实例化发生在GetObject方法中,所以我选择在这个方法中进行分配,分配位置上面已经标明。
if (pool == null)
{
pool = new GameObject("ObjectPool");//创建一个物体管理所有对象池
}
//寻找并绑定相应对象池物体,如果对象物体不存在则创建一个对象池物体
GameObject childPool = GameObject.Find(prefab.name + "pool");
if (!childPool)
{
childPool = new GameObject(prefab.name + "pool");
}
//设置好他们的关系
childPool.transform.SetParent(pool.transform);
_object.transform.SetParent(childPool.transform);
这是全部的代码,可以再阅读试试是否已经理解
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPool
{
private Dictionary<string, Queue<GameObject>> objectPool = new Dictionary<string, Queue<GameObject>>();
private GameObject pool;
private static ObjectPool instance;
public static ObjectPool Instance
{
get
{
if (instance == null)
{
instance = new ObjectPool();
}
return instance;
}
}
public GameObject GetObject(GameObject prefab)
{
GameObject _object;
if (!objectPool.ContainsKey(prefab.name)|| objectPool[prefab.name].Count == 0)//③
{
_object = GameObject.Instantiate(prefab);
if (pool == null)
{
pool = new GameObject("ObjectPool");
}
GameObject childPool = GameObject.Find(prefab.name + "pool");
if (!childPool)
{
childPool = new GameObject(prefab.name + "pool");
}
childPool.transform.SetParent(pool.transform);
_object.transform.SetParent(childPool.transform);
PushObject(_object);
}
_object = objectPool[prefab.name].Dequeue();
_object.SetActive(true);
return _object;
}
public void PushObject(GameObject prefab)
{
string _name = prefab.name.Replace("(Clone)", string.Empty);
if (objectPool.ContainsKey(_name) == false)
{
objectPool.Add(_name, new Queue<GameObject>());
}
objectPool[_name].Enqueue(prefab);
prefab.SetActive(false);
}
}
最后,我们需要调用该类中的方法,使用单例调用
ObjectPool.Instance.GetObject(bulletPrefab);
四、感想:
好爽!!!!!!!!!!!!
|