1.简单介绍
在Unity开发过程中,对象池是一种很好的能用于减少内存开销的方式。在许多场景中,比如角色射击出去的子弹,以及在游戏运行过程中频繁生成的敌人…如果在运行时实时在场景中Instance和Destory,在场景中需要实时生成的GameObject数量比较多的情况下,会增加内存的开销和影响游戏的性能。使用对象池可以很好的对这些需要实时刷新的游戏对象进行管理,在需要时从对象池中取(也就是SetActive(true)),不需要时回收到对象池中(也就是SetActive(false))。
2.思路
以下分了三个类来实现对象池的例子。 1.Pool(对象池类) 其中主要有获取对象GetObject()、回收对象ReleaseObject()、清空对象池ClearPool()三个方法。 2.PoolManager(对象池管理类) 用于管理所有的对象池,方法看代码有详细介绍 3.ObjectPoolTest(测试类) 用于测试对象池
代码实现
1.Pool
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Pool
{
int maxCount;
public string prefabPath;
List<GameObject> usingList = new List<GameObject>();
List<GameObject> freeList = new List<GameObject>(0);
public Pool(int count)
{
this.maxCount = count;
}
public GameObject GetObject()
{
GameObject obj = null;
if(freeList.Count > 0)
{
obj = freeList[0];
usingList.Add(obj);
freeList.RemoveAt(0);
}
else
{
if (usingList.Count >= maxCount)
return obj;
GameObject prefab = Resources.Load<GameObject>(prefabPath);
obj = GameObject.Instantiate(prefab);
usingList.Add(obj);
int instanceID = obj.GetInstanceID();
PoolManager.Instance.instanceIDToPathDic.Add(instanceID, prefabPath);
}
return obj;
}
public void ReleaseObject(GameObject obj)
{
usingList.Remove(obj);
freeList.Add(obj);
}
public void ClearPool()
{
foreach (var item in usingList)
GameObject.Destroy(item);
foreach (var item in freeList)
GameObject.Destroy(item);
usingList.Clear();
freeList.Clear();
}
}
2.PoolManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PoolManager
{
static PoolManager instacne;
public static PoolManager Instance
{
get
{
if (instacne == null)
instacne = new PoolManager();
return instacne;
}
}
public Dictionary<string, Pool> allPoolDic = new Dictionary<string, Pool>();
public Dictionary<int, string> instanceIDToPathDic = new Dictionary<int, string>();
public GameObject GetObjFormPoll(string prefabPath)
{
GameObject obj = null;
if(allPoolDic.ContainsKey(prefabPath))
{
Pool pool = allPoolDic[prefabPath];
obj = pool.GetObject();
}
else
{
int maxCount = 5;
Pool pool = new Pool(maxCount);
pool.prefabPath = prefabPath;
allPoolDic.Add(prefabPath, pool);
obj = pool.GetObject();
}
if (obj != null)
obj.SetActive(true);
return obj;
}
public void ReleaseObjToPool(GameObject obj)
{
if (obj == null)
return;
int instanceID = obj.GetInstanceID();
if(instanceIDToPathDic.ContainsKey(instanceID))
{
string prefabPath = instanceIDToPathDic[instanceID];
if(allPoolDic.ContainsKey(prefabPath))
{
Pool pool = allPoolDic[prefabPath];
pool.ReleaseObject(obj);
obj.SetActive(false);
}
}
}
public void ClearAllPool()
{
foreach (var item in allPoolDic.Values)
item.ClearPool();
allPoolDic.Clear();
instanceIDToPathDic.Clear();
}
}
3.ObjectPoolTest
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPoolTest : MonoBehaviour
{
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
Vector3 pos = new Vector3(Random.Range(-5, 5), Random.Range(-5, 5), Random.Range(-5, 5));
GameObject obj = PoolManager.Instance.GetObjFormPoll("Cube");
obj.transform.position = pos;
}
if(Input.GetKeyDown(KeyCode.R))
{
GameObject obj = GameObject.Find("Cube(Clone)");
PoolManager.Instance.ReleaseObjToPool(obj);
}
}
}
4.测试结果
可以看到,无论我们按几次空格键,场景中最多只会生成5个对象,因为限制了对象池最大数量为5,当你不需要使用时,就按R把对象隐藏起来,而不是直接删除掉。下次需要用到对象的时候直接将状态设置为显示,而不是重新实例化。
|