Unity实现一个简易的对象池
一、为什么要使用对象池
在我们的开发中,我们经常会对大量相同的物品进行销毁和创建,例如FPS游戏中的子弹,往往需要大量创建和销毁,这对于我们系统内存和性能的消耗非常大。故而我们使用对象池技术来对这些物体进行优化管理。
二、开发思路
将GameObject的实例化和销毁改为激活和失活处理。
首先我们将从对象池中查找是否有想要成成的GameObject,如果有则激活该GameObject代替重新实例化新的GameObject。如果没有则实例化一个新的GameObject放到对象池中进行失活处理。当有GameObject需要销毁时,我们将GameObject进行失活处理放进对象池中等待下次使用。
三、使用教学
首先创建ObjPool脚本,不需要继承MonoBehaviour(也可继承,继承后需要放到)
采取单例模式(对象池是管理整个游戏的,全局应当只有一个实例)
使用字典和列表对资源进行存储(对象池中肯能会有多种不同的对象需要管理,所以我们采取字典存取不通过的对象池,列表存取不同对象池对应的资源)
为了防止大家不理解,我先介绍一下两个字典分别的作用
pool用于存储回收来的物品,因为资源种类不唯一,所以以键值对的形式保存不同的对象池(例 pool(bullet,bulletList).
prefabs用于保存最初加载时需要实例化资源。
接下来需要三个方法用于获取资源,加载资源和回收资源。
GetObj(string path)用于获取资源用于从对象池中获取闲置资源
GetPrefabs(string path)用于加载资源用于在对象池中没有对应资源的时候生成对应资源(不用手动调用,该方法在获取资源方法中自动判断调用)
RecycleObj(GameObject obj)用于回收资源用于把无用的待销毁的资源回收到对象池以备下次使用
如果想要GameObject定时回收到Pool,可以在GameObjec的组件t中继承了Monobehaviour的方法中通过协程调用回收资源方法。
附源码(感谢浏览)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjPool
{
private static ObjPool instance;
public static ObjPool Instacne
{
get
{
if (instance == null)
{
instance = new ObjPool();
}
return instance;
}
}
private ObjPool()
{
pool = new Dictionary<string, List<GameObject>>();
prefabs = new Dictionary<string, GameObject>();
}
private Dictionary<string, List<GameObject>> pool;//对象池
private Dictionary<string, GameObject> prefabs;//预制体
/// <summary>
/// 获取GameObject
/// </summary>
public GameObject GetObj(string path)
{
//判断对象池中时候有闲置的GameObject
//有则返回并从对象池中移除
//无则返回GetPrefabs实例化的资源
if (pool.ContainsKey(path))
{
if (pool[path].Count > 0)
{
GameObject result = pool[path][0];
result.SetActive(true);
pool[path].Remove(result);
return result;
}
}
return GetPrefabs(path);
}
/// <summary>
/// 实例化资源
/// </summary>
public GameObject GetPrefabs(string path)
{
GameObject prefab = null;
if (prefabs.ContainsKey(path))
prefab = prefabs[path];
else
{
prefab = Resources.Load<GameObject>(path);
prefabs.Add(path, prefab);
}
GameObject go = Object.Instantiate(prefab);
//改名(去除 Clone)
go.name = path;
return go;
}
/// <summary>
/// 回收资源
/// </summary>
public void RecycleObj(GameObject obj)
{
obj.SetActive(false);
if (pool.ContainsKey(obj.name))
{
pool[obj.name].Add(obj);
}
else
{
pool.Add(obj.name, new List<GameObject>() { obj });
}
}
}