3.对象池模块
3.1 知识点
对象池模块的作用
- 节约性能,减少 CPU 和内存消耗
对象池示意图
对象池
导入命名空间和引用
引用了必要的命名空间,包括 System.Collections
、System.Collections.Generic
和 UnityEngine
。
定义 BaseGameObjectPool 类
创建名为 BaseGameObjectPool 的 C# 类,用于实现游戏对象池。
类属性和字段
声明了三个类属性:
- gameObjectPath:存储游戏对象的资源路径。
- baseGameObjectPoolNode:表示游戏对象池的根节点。
- baseGameObjectPoolGameObjectList:用于存储游戏对象的列表。
构造函数
定义了一个构造函数,用于初始化游戏对象池。
构造函数接受三个参数:
- baseGameObjectPoolManagerNode:表示游戏对象池的管理节点。
- gameObjectPath:游戏对象的资源路径。
- gameObject:初始的游戏对象。
在构造函数中执行以下步骤:
- 创建一个名为
${gameObjectPath} BaseGameObjectPoolNode
的新 GameObject,并将其设为根节点。 - 将 gameObjectPath 属性设置为传入的资源路径。
- 将根节点设为传入的管理节点的子节点。
- 初始化 baseGameObjectPoolGameObjectList,创建一个空的游戏对象列表。
- 调用 ReleaseGameObject 方法将初始游戏对象添加到游戏对象池中。
ReleaseGameObject 方法
用于将游戏对象释放到对象池中。
接受一个参数:gameObject,表示要释放的游戏对象。
在方法内部执行以下操作:
- 将游戏对象设置为不活跃状态(禁用)。
- 将游戏对象添加到游戏对象列表 baseGameObjectPoolGameObjectList 中。
- 将游戏对象的父节点设置为游戏对象池的根节点,使其成为对象池的一部分。
GetGameObject 方法
用于从对象池中获取游戏对象。
不接受任何参数。
在方法内部执行以下操作:
- 声明一个名为 gameObject 的局部变量,并初始化为 null。
- 从游戏对象列表 baseGameObjectPoolGameObjectList 中获取第一个游戏对象。
- 从游戏对象列表中移除该游戏对象。
- 将游戏对象设置为活跃状态(激活)。
- 将游戏对象的父节点设置为 null,使其脱离对象池的控制。
- 返回获取的游戏对象。
对象池管理器
定义 BaseGameObjectPoolManager 类
创建名为 BaseGameObjectPoolManager 的 C# 类,用于管理多个游戏对象池。
类属性和字段
baseGameObjectPoolDictionary:声明一个私有字段,用于存储游戏对象池的字典。字典的键是游戏对象的资源路径,值是对应的游戏对象池。
baseGameObjectPoolManagerNode:声明一个私有字段,表示游戏对象池管理器的根节点。
GetGameObject 方法
用于从游戏对象池中获取游戏对象。
接受两个参数:
- gameObjectPath:游戏对象的资源路径。
- callBack:回调函数,用于在获取游戏对象后执行自定义操作。
在方法内部执行以下操作:
- 检查游戏对象池字典中是否包含指定资源路径的对象池。
- 检查对象池中是否有可用的游戏对象(通过检查对象池的游戏对象列表)。
- 如果有可用的游戏对象,调用回调函数并传递该游戏对象。
- 如果没有可用的游戏对象,通过资源管理器异步加载游戏对象,加载完成后设置名称为资源路径,然后调用回调函数并传递加载的游戏对象。
ReleaseGameObject 方法
用于释放游戏对象到对象池中。
接受两个参数:
- gameObjectPath:游戏对象的资源路径。
- gameObject:要释放的游戏对象。
在方法内部执行以下操作:
- 检查游戏对象池管理器的根节点是否已创建,如果未创建,则创建一个新的根节点。
- 检查游戏对象池字典中是否包含指定资源路径的对象池。
- 如果包含,将游戏对象释放到对应的对象池中。
- 如果不包含,创建一个新的对象池,并将游戏对象添加到该对象池中,然后将对象池添加到字典中。
Clear 方法
用于清空游戏对象池管理器的状态。
在方法内部执行以下操作:
- 清空游戏对象池字典,删除所有对象池。
- 重置对象池管理器的根节点为 null,以便在需要时重新创建。
进行测试
创建延迟释放脚本,创建方块和球体预制体到Resources下并挂载延迟释放
public class TestGameObjectPoolDelayRelease : MonoBehaviour
{
void OnEnable()
{
Invoke("Release", 3);
this.transform.position = new Vector3(Random.Range(-5f, 5f), Random.Range(-5f, 5f), Random.Range(-5f, 5f));
Debug.Log($"this.gameObject.name:{this.gameObject.name} this.transform.position:{this.transform.position}");
}
void Release()
{
BaseGameObjectPoolManager.Instance.ReleaseGameObject(this.gameObject.name, this.gameObject);
}
}
在 Update 方法中,鼠标左右键随机生成方块和球体
if (Input.GetMouseButtonDown(0))
{
BaseGameObjectPoolManager.Instance.GetGameObject("Test/Cube", (gameObject) =>
{
gameObject.transform.eulerAngles = new Vector3(Random.Range(-5f, 5f), Random.Range(-5f, 5f), Random.Range(-5f, 5f));
Debug.Log($"this.gameObject.name:{this.gameObject.name} this.transform.eulerAngles:{this.transform.eulerAngles}");
});
}
if (Input.GetMouseButtonDown(1))
{
BaseGameObjectPoolManager.Instance.GetGameObject("Test/Sphere", (gameObject) =>
{
gameObject.transform.localScale = new Vector3(Random.Range(-5f, 5f), Random.Range(-5f, 5f), Random.Range(-5f, 5f));
Debug.Log($"this.gameObject.name:{this.gameObject.name} this.transform.localScale:{this.transform.localScale}");
});
}
点击后可以看到,假如池下有对象会拿池中的对象
3.2 知识点代码
BaseGameObjectPool
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 基础游戏对象池类
public class BaseGameObjectPool
{
// 游戏对象的资源路径
public string gameObjectPath;
// 游戏对象池的根节点
public GameObject baseGameObjectPoolNode;
// 存储游戏对象的列表
public List<GameObject> baseGameObjectPoolGameObjectList;
// 构造函数,用于初始化游戏对象池
public BaseGameObjectPool(GameObject baseGameObjectPoolManagerNode, string gameObjectPath, GameObject gameObject)
{
// 创建游戏对象池的根节点,并命名
baseGameObjectPoolNode = new GameObject($"{gameObjectPath} BaseGameObjectPoolNode");
this.gameObjectPath = gameObjectPath;
// 将游戏对象池的根节点设为传入的管理节点的子节点
baseGameObjectPoolNode.transform.parent = baseGameObjectPoolManagerNode.transform;
// 初始化游戏对象列表
baseGameObjectPoolGameObjectList = new List<GameObject>();
// 将传入的游戏对象添加到游戏对象池中
ReleaseGameObject(gameObject);
}
// 释放游戏对象到对象池中
public void ReleaseGameObject(GameObject gameObject)
{
// 将游戏对象设置为不活跃状态
gameObject.SetActive(false);
// 将游戏对象添加到对象池列表中
baseGameObjectPoolGameObjectList.Add(gameObject);
// 将游戏对象的父节点设为对象池的根节点
gameObject.transform.parent = baseGameObjectPoolNode.transform;
}
// 从对象池中获取游戏对象
public GameObject GetGameObject()
{
GameObject gameObject = null;
// 从对象池列表中取出第一个游戏对象
gameObject = baseGameObjectPoolGameObjectList[0];
// 从对象池列表中移除该游戏对象
baseGameObjectPoolGameObjectList.RemoveAt(0);
// 将游戏对象设置为活跃状态
gameObject.SetActive(true);
// 将游戏对象的父节点设为null,使其脱离对象池的控制
gameObject.transform.parent = null;
// 返回获取的游戏对象
return gameObject;
}
}
BaseGameObjectPoolManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
// 游戏对象池管理器类,继承自 C# 基础单例类
public class BaseGameObjectPoolManager : BaseSingletonInCSharp<BaseGameObjectPoolManager>
{
// 存储游戏对象池的字典,键为游戏对象的资源路径,值为游戏对象池
private Dictionary<string, BaseGameObjectPool> baseGameObjectPoolDictionary = new Dictionary<string, BaseGameObjectPool>();
// 游戏对象池管理器的根节点
private GameObject baseGameObjectPoolManagerNode;
// 从对象池中获取游戏对象的方法,包括资源路径和回调函数
public void GetGameObject(string gameObjectPath, UnityAction<GameObject> callBack)
{
// 检查游戏对象池字典中是否包含指定资源路径的对象池,并且对象池中是否有可用的游戏对象
if (baseGameObjectPoolDictionary.ContainsKey(gameObjectPath) && baseGameObjectPoolDictionary[gameObjectPath].baseGameObjectPoolGameObjectList.Count > 0)
{
// 如果有可用的游戏对象,调用回调函数返回游戏对象
callBack(baseGameObjectPoolDictionary[gameObjectPath].GetGameObject());
}
else
{
// 如果没有可用的游戏对象,通过资源管理器异步加载游戏对象
BaseResourceManager.Instance.LoadAsync<GameObject>(gameObjectPath, (gameObject) =>
{
// 设置加载的游戏对象的名称为资源路径
gameObject.name = gameObjectPath;
// 调用回调函数返回加载的游戏对象
callBack(gameObject);
});
}
}
// 释放游戏对象到对象池的方法,包括资源路径和游戏对象
public void ReleaseGameObject(string gameObjectPath, GameObject gameObject)
{
// 如果游戏对象池管理器的根节点尚未创建,创建一个新的根节点
if (baseGameObjectPoolManagerNode == null)
{
baseGameObjectPoolManagerNode = new GameObject("BaseGameObjectPoolManagerNode");
}
// 检查游戏对象池字典中是否包含指定资源路径的对象池
if (baseGameObjectPoolDictionary.ContainsKey(gameObjectPath))
{
// 如果包含,将游戏对象释放到对应的对象池中
baseGameObjectPoolDictionary[gameObjectPath].ReleaseGameObject(gameObject);
}
else
{
// 如果不包含,创建一个新的对象池,并添加到对象池字典中
baseGameObjectPoolDictionary.Add(gameObjectPath, new BaseGameObjectPool(baseGameObjectPoolManagerNode, gameObjectPath, gameObject));
}
}
// 清空游戏对象池管理器的方法
public void Clear()
{
baseGameObjectPoolDictionary.Clear(); // 清空对象池字典
baseGameObjectPoolManagerNode = null; // 重置对象池管理器的根节点
}
}
Lesson03_对象池模块
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson03_对象池模块 : MonoBehaviour
{
void Update()
{
if (Input.GetMouseButtonDown(0))
{
BaseGameObjectPoolManager.Instance.GetGameObject("Test/Cube", (gameObject) =>
{
gameObject.transform.eulerAngles = new Vector3(Random.Range(-5f, 5f), Random.Range(-5f, 5f), Random.Range(-5f, 5f));
Debug.Log($"this.gameObject.name:{this.gameObject.name} this.transform.eulerAngles:{this.transform.eulerAngles}");
});
}
if (Input.GetMouseButtonDown(1))
{
BaseGameObjectPoolManager.Instance.GetGameObject("Test/Sphere", (gameObject) =>
{
gameObject.transform.localScale = new Vector3(Random.Range(-5f, 5f), Random.Range(-5f, 5f), Random.Range(-5f, 5f));
Debug.Log($"this.gameObject.name:{this.gameObject.name} this.transform.localScale:{this.transform.localScale}");
});
}
}
}
TestGameObjectPoolDelayRelease
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestGameObjectPoolDelayRelease : MonoBehaviour
{
void OnEnable()
{
Invoke("Release", 3);
this.transform.position = new Vector3(Random.Range(-5f, 5f), Random.Range(-5f, 5f), Random.Range(-5f, 5f));
Debug.Log($"this.gameObject.name:{this.gameObject.name} this.transform.position:{this.transform.position}");
}
void Release()
{
BaseGameObjectPoolManager.Instance.ReleaseGameObject(this.gameObject.name, this.gameObject);
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com