推荐阅读
大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。
一、前言
【GameFramework框架】系列教程目录:
https://blog.csdn.net/q764424567/article/details/135831551
二、正文
2-1、介绍
对象池(Object Pool)
技术,相比大家都了解很多了,使用对象池技术的原因在于对象需要存在频繁的创建和销毁。
为了避免GC,而对对象的创建和销毁进行优化,需要时获取,不需要时回收,而不是销毁。
在GameFramework框架中,用到对象池(Object Pool)
共有四处:
- 1、TaskPool 任务池
- 2、RefrencePool 引用池
- 3、 EventPool 事件池
- 4、ObjectPool 对象池
在GameFramework框架中之所以分成4个对象池去做这些事情,也是为了不同的功能差异而实现的。
2-2、使用说明
我们先看一下如何使用GameFramework的对象池,之后再详细分析四个对象池的实现和使用。
这里以StarForce
示例项目为例,StarForce
示例项目使用了ObjectPool
对象池,适用于Unity预制体对象的对象池使用。
下面,就来看一下如何使用的:
1、HPBarItem.cs
HPBarItem.cs
在挂载预制体上,初始化一个使用的血条UI,代码如下:
csharp
namespace StarForce
{
public class HPBarItem : MonoBehaviour
{
[SerializeField]
private Slider m_HPBar = null;
private void Awake();
//初始化赋值
public void Init(Entity owner, Canvas parentCanvas, float fromHPRatio, float toHPRatio);
//回收重置
public void Reset();
}
}
挂载HPBarItem.cs
预制体其实都可以直接用对象池了,但是为了扩展性,需要一个继承ObjectBase类
的HPBarItemObject
来包装HPBarItem.cs
。
2、HPBarItemObject.cs
HPBarItemObject.cs
的作用很简单,就是让ObjectPool
直接管理的是它,它里面包装了HPBarItem
。
csharp
namespace StarForce
{
public class HPBarItemObject : ObjectBase
{
//HPBarItemObject的创建函数
public static HPBarItemObject Create(object target)
{
HPBarItemObject hpBarItemObject = ReferencePool.Acquire<HPBarItemObject>();
hpBarItemObject.Initialize(target);
return hpBarItemObject;
}
//对象的释放函数
protected override void Release(bool isShutdown)
{
HPBarItem hpBarItem = (HPBarItem)Target;
if (hpBarItem == null)
return;
Object.Destroy(hpBarItem.gameObject);
}
}
}
要实现HPBarItemObject
的回收和复用,还需要特定的HPBarComponent类
,用来封装回收和复用操作。
3、HPBarComponent.cs
封装HPBarComponent类
回收和复用操作。
csharp
namespace StarForce
{
public class HPBarComponent : GameFrameworkComponent
{
//复用对象预制体
private HPBarItem m_HPBarItemTemplate = null;
//对象父节点
private Transform m_HPBarInstanceRoot = null;
//对象池
private IObjectPool<HPBarItemObject> m_HPBarItemObjectPool = null;
private void Start()
{
//创建对象池
m_HPBarItemObjectPool = GameEntry.ObjectPool.CreateSingleSpawnObjectPool<HPBarItemObject>("HPBarItem", m_InstancePoolCapacity);
}
//创建HPBarItem对象
public void ShowHPBar(Entity entity, float fromHPRatio, float toHPRatio);
//回收HpBarItem对象
private void HideHPBar(HPBarItem hpBarItem);
//从对象池取对象逻辑(有就复用,没有就创建)
private HPBarItem CreateHPBarItem(Entity entity)
{
HPBarItem hpBarItem = null;
HPBarItemObject hpBarItemObject = m_HPBarItemObjectPool.Spawn();
if (hpBarItemObject != null)
{
hpBarItem = (HPBarItem)hpBarItemObject.Target;
}
else
{
hpBarItem = Instantiate(m_HPBarItemTemplate);
Transform transform = hpBarItem.GetComponent<Transform>();
transform.SetParent(m_HPBarInstanceRoot);
transform.localScale = Vector3.one;
m_HPBarItemObjectPool.Register(HPBarItemObject.Create(hpBarItem), true);
}
return hpBarItem;
}
}
}
总结一下就是,ObjectPoolManager
管理所有继承了ObjectBase
类的对象池,HPBarItemObject
继承了ObjectBase
类,包装了HPBarItem
类,使用HPBarComponent
去封装HPBarItemObject
的回收和复用操作。
这样可拓展性和可维护性非常强,缺点就是对初学者不友好。
2-3、实现及代码分析
2-3-1、TaskPool 对象池
TaskPool.cs
TaskPool是ITaskAgent的集合,负责ITaskAgent的初始化、执行、回收等操作。
csharp
/// <summary>
/// 任务池管理器
/// </summary>
internal sealed class TaskPool<T> where T : TaskBase
{
// 单个任务接口基类
private readonly GameFrameworkLinkedList<ITaskAgent<T>> m_WorkingAgents;
// 要增加的任务代理。
public void AddAgent(ITaskAgent<T> agent){}
// 根据任务的序列编号获取任务的信息。
public TaskInfo GetTaskInfo(int serialId){}
// 移除任务。
public bool RemoveTask(int serialId){}
}
ITaskAgent.cs
ITaskAgent接口就是单个任务的接口基类,下面是主要的三个子类继承:
csharp
1.DownloadAgent:用于服务器文件的下载代理器
2.LoadResourceAgent:用于加载本地AssetBundle资源的加载器
3.WebRequestAgent:web请求代理
2-3-2、RefrencePool 引用池
RefrencePool .cs
引用池管理器,每个ReferenceCollection
都是一个引用池,RefrencePool
对每一个ReferenceCollection
进行管理。
csharp
/// <summary>
/// 任务池管理器
/// </summary>
internal sealed class TaskPool<T> where T : TaskBase
{
// 单个任务接口基类
private readonly GameFrameworkLinkedList<ITaskAgent<T>> m_WorkingAgents;
// 要增加的任务代理。
public void AddAgent(ITaskAgent<T> agent){}
// 根据任务的序列编号获取任务的信息。
public TaskInfo GetTaskInfo(int serialId){}
// 移除任务。
public bool RemoveTask(int serialId){}
}
ReferenceCollection.cs
ReferenceCollection是IReference的一个队列集合:
csharp
//IReference集合
private sealed class ReferenceCollection
{
private readonly Queue<IReference> m_References;
}
IReference.cs
IReference
接口是所有对先吃,引用的T类型的基类接口,继承IReference
接口的子类很多,只要是存在大量的类都可以继承IReference
,这些类的特点就是可以Clear
清除数据后重用:
csharp
PacketHeaderBase:网络消息包头
Event:事件节点
GameFrameworkEventArgs:游戏框架抱哈事件数据的基类
TaskBase:任务基类
Variable:GF变量基类
DataNode:数据节点
EntityInfo:实体信息
Fsm<T>:有限状态机基类
ObjectBase:对象基类
UIFormInfo:界面组信息
LogNode:日志记录节点
WWWFormInfo:www表单信息
2-3-3、EventPool 事件池
EventManager.cs
EventManager
维护了EventPool
,对象池里面存储了游戏中的事件:
csharp
/// <summary>
/// 事件管理器。
/// </summary>
internal sealed class EventManager : GameFrameworkModule, IEventManager
{
private readonly EventPool<GameEventArgs> m_EventPool;
/// 订阅事件处理函数。
public void Subscribe(int id, EventHandler<GameEventArgs> handler);
/// 取消订阅事件处理函数。
public void Unsubscribe(int id, EventHandler<GameEventArgs> handler);
/// 抛出事件,这个操作是线程安全的,即使不在主线程中抛出,也可保证在主线程中回调事件处理函数,但事件会在抛出后的下一帧分发。
public void Fire(object sender, GameEventArgs e);
}
EventPool.cs
EventPool
事件池负责全局游戏的事件的绑定和发送,EventManager
对其进行了封装:
csharp
/// <summary>
/// 事件池。
/// </summary>
/// <typeparam name="T">事件类型。</typeparam>
internal sealed partial class EventPool<T> where T : BaseEventArgs
{
//存储所有(事件,绑定函数)
private readonly GameFrameworkMultiDictionary<int, EventHandler<T>> m_EventHandlers;
//多线程安全事件列表,保证线程安全
private readonly Queue<Event> m_Events;
/// 订阅事件处理函数。
public void Subscribe(int id, EventHandler<T> handler);
/// 取消订阅事件处理函数。
public void Unsubscribe(int id, EventHandler<T> handler);
/// 抛出事件,这个操作是线程安全的,即使不在主线程中抛出,也可保证在主线程中回调事件处理函数,但事件会在抛出后的下一帧分发。
public void Fire(object sender, T e);
/// 处理事件结点。 遍历执行事件回调
private void HandleEvent(object sender, T e);
}
}
2-3-4、ObjectPool 对象池
ObjectPool.cs
ObjectPool
是针对Object的集合,让我们先来看ObjectPool
类的结构:
csharp
/// 泛型T的对象池。
private sealed class ObjectPool<T> : ObjectPoolBase, IObjectPool<T> where T : ObjectBase
{
private readonly GameFrameworkMultiDictionary<string, Object<T>> m_Objects;
private readonly Dictionary<object, Object<T>> m_ObjectMap;
/// 创建对象。
public void Register(T obj, bool spawned);
/// 获取对象。
public T Spawn();
/// 回收对象。
public void Unspawn(T obj);
/// 释放对象池中的可释放对象。
public override void Release();
}
ObjectPool
是一个对象类,适用于泛型类Object
的获取和回收。
ObjectPool
有自动释放机制,在Update
中轮询是否有多余的需要释放的对象。
Object.cs
Object
是IReference
的一个引用,Object
实现了OnSpawn
和OnUnSpawn
事件,方便对象回收和重用时的回调处理。
csharp
internal sealed partial class ObjectPoolManager : GameFrameworkModule, IObjectPoolManager
{
/// 内部对象。
private sealed class Object<T> : IReference where T : ObjectBase
{
private T m_Object;
private int m_SpawnCount;
/// 创建内部对象。
public static Object<T> Create(T obj, bool spawned);
/// 获取对象。
public T Spawn();
/// 回收对象。
public void Unspawn();
/// 释放对象。
public void Release(bool isShutdown);
}
}
三、后记
如果觉得本篇文章有用别忘了点个关注,关注不迷路,持续分享更多Unity干货文章。
你的点赞就是对博主的支持,有问题记得留言:
博主主页有联系方式。
博主还有跟多宝藏文章等待你的发掘哦:
专栏 | 方向 | 简介 |
---|---|---|
Unity3D开发小游戏 | 小游戏开发教程 | 分享一些使用Unity3D引擎开发的小游戏,分享一些制作小游戏的教程。 |
Unity3D从入门到进阶 | 入门 | 从自学Unity中获取灵感,总结从零开始学习Unity的路线,有C#和Unity的知识。 |
Unity3D之UGUI | UGUI | Unity的UI系统UGUI全解析,从UGUI的基础控件开始讲起,然后将UGUI的原理,UGUI的使用全面教学。 |
Unity3D之读取数据 | 文件读取 | 使用Unity3D读取txt文档、json文档、xml文档、csv文档、Excel文档。 |
Unity3D之数据集合 | 数据集合 | 数组集合:数组、List、字典、堆栈、链表等数据集合知识分享。 |
Unity3D之VR/AR(虚拟仿真)开发 | 虚拟仿真 | 总结博主工作常见的虚拟仿真需求进行案例讲解。 |
Unity3D之插件 | 插件 | 主要分享在Unity开发中用到的一些插件使用方法,插件介绍等 |
Unity3D之日常开发 | 日常记录 | 主要是博主日常开发中用到的,用到的方法技巧,开发思路,代码分享等 |
Unity3D之日常BUG | 日常记录 | 记录在使用Unity3D编辑器开发项目过程中,遇到的BUG和坑,让后来人可以有些参考。 |