一、框架结构
MotionFramework主要分为两个部分,一部分是核心系统,另一部分是管理器。
Engine
- Core 框架的核心代码,负责游戏模块的创建和管理。在核心系统上,提供了许多管理器
- Engine.AI 包括神经网络、A*算法应用、状态机
- Engine.Animation 动画的细节实现
- Engine.Console 控制台。在游戏运行的时候,通过内置的控制台可以方便查看调试信息。控制台预设了游戏模块,游戏日志,应用详情,资源系统,引用池,游戏对象池等窗口。开发者可以扩展自定义窗口。
- Engine.IO IO相关
- Engine.Network 异步IOCP SOCKET长连接方案,支持TCP和UDP协议。支持同时建立多个通信频道,例如连接逻辑服务器的同时还可以连接聊天服务器。不同的通信频道支持使用不同的网络包编码解码器,开发者可以扩展支持ProtoBuf的网络包编码解码器,也可以使用自定义的序列化和反序列化方案。
- Engine.Reference 用于C#引用类型的对象池,对于频繁创建的引用类型,使用引用池可以帮助减少GC。
- Engine.Utility 工具类
Module
- Extension Unity API拓展
- Module.Audio 音频管理器
- Module.Config 配置管理器
- Module.Console 控制台各面板管理
- Module.Event 事件管理器
- Module.Network 网络管理器
- Module.Pool 对象池管理器
- Module.Resource 资源管理器
- Module.Scene 场景管理器
- Module.Tween 补间管理器
- Module.Window UI窗口管理器
二、代码分析
Core
IModule:模块的接口,包含OnCreate
/OnUpdate
/OnDestroy
/OnGUI
四个方法,所有模块类都需要实现此接口
ModuleSingleton:基于泛型的单例模式类,此类为抽象类,限制类型参数 T 必须实现 IModule 接口
ELogLevel:日志的四个等级,包含信息、警告、错误、异常
MotionLog:日志系统,对四个日志等级分别封装了静态方法,然后调用静态方法的时候会调用该类中注册过的委托方法,基于委托方法的逻辑打印日志
IActivatorServices:一个动态创建实例的接口,包含两个方法,一个是根据类型创建实例,一个是根据类型获取特性,都用于反射
MainThreadSyncContext:一个线程管理类,同步其它线程里的回调到主线程里,实现了一个线程安全的队列
Engine.AI
其中包含神经网络、A*算法、状态机等,这里看看状态机是如何实现的
包含四个类:
IFsmNode:这是一个状态机节点接口,包含节点名称、进入、更新、推出、回调等方法,后面的状态机节点类都要实现该接口
FsmGraph:节点的转换关系类,即每个节点并不能任意转换到其他节点,只有在可转换的关系列表中的节点才能被转换
FiniteStateMachine:实现了有限状态机的基本功能,允许在不同的状态之间进行切换,处理消息,以及维护状态转换消息,提供状态管理机制
ProcedureFsm:流程状态机,管理和调度多个节点的执行。通过使用FiniteStateMachine
,实现状态机的基本逻辑,允许按照添加顺序执行节点
Engine.Reference
包含三个类:
IReference:接口,包含一个释放的方法
ReferenceCollector:引用对象收集器,用栈存储同一类型的引用对象。两个重要属性,内部缓存总数、外部使用总数;两个重要方法,Spwan
申请引用对象,栈中有的话就从栈中弹出,没有的话利用反射获取,Release
回收引用对象,回收到栈中
ReferencePool:引用对象池,用字典记录不同的引用对象类型栈,重要方法,Spwan
申请引用对象,Release
回收引用对象,批量回收列表集合,批量回收数组集合,ClearAll
清空所有对象池
Engine.Utility
计时器:用法比较简单
Module.Event
IEventMessage:所有自定义事件类都要继承该接口
EventGroup:使用一个字典 _cachedListener,将事件类型映射到其监听器列表。依赖 EventManager 进行实际的监听器添加和消息派发,更适合用于需要集中管理某一类事件的情况,例如特定模块或组件的事件处理。
EventManager:事件管理器,是事件系统的核心,负责全局事件的注册、派发和处理。使用一个字典 _listeners
,将事件 ID(通过事件类型的哈希码生成)映射到链表,可以高效地添加和移除监听器。还使用一个 _postWrappers
列表来处理延迟事件,这使得 EventManager
可以在下一帧发送消息,最终发送消息都是调用了SendMessage
方法
Module.Pool
GameObjectCollector: 这个类负责管理一组游戏对象的创建、复用和销毁。它维护一个对象池,存储可以重用的GameObject实例。
- 通过ResourceManager异步加载指定位置的资源
- 提供Spawn方法获取游戏对象,管理缓存队列(Queue)
- 提供Restore和Discard方法处理对象的复用和销毁逻辑
- 提供对象池的状态信息,如是否加载完成、当前缓存数量等
SpawnGameObject:这个类代表从对象池中获取的单个游戏对象实例,封装了与该实例相关的状态和数据等。
- 跟踪游戏对象的状态(如是否已回收或丢弃)
- 提供Restore和Discard方法,允许用户回收或丢弃该对象,实际调用的是
GameObjectCollector
的方法 - 允许存储用户自定义数据,并在对象完成时调用用户回调
GameObjectPoolManager:对象池的管理器,负责创建和维护多个GameObjectCollector实例,并提供一个全局接口来访问它们。
- 提供CreatePool方法创建新的对象池,如果已经存在则返回现有池
- 提供Spawn方法用于从指定资源池中获取游戏对象
- 定期检查并自动销毁未被使用的池
- 提供一个集中管理的方式,确保多个对象池的创建和访问都经过GameObjectPoolManager
Module.Scene
AssetScene:该类包含一个场景的信息,属性包括场景资源地址、加载进度、加载是否完成等,
方法包括加载场景、卸载场景、场景加载完成时调用的回调
SceneManager:用于管理多个场景(包括主场景和附加场景),持有对主场景的引用和附加场景的列表。
关键方法包括:
ChangeMainScene
:切换主场景,之前的主场景以及附加场景将会被卸载LoadAdditionScene
:加载附加场景UnLoadAdditionScene
:卸载特定的附加场景GetSceneLoadProgress
:获取指定场景的加载进度CheckSceneIsDone
:检查指定场景是否加载完成TryGetAdditionScene
:尝试根据位置获取附加场景
Module.Audio
EAudioLayer:枚举,音频层级,包括音乐、环境音、语音、音效
AssetAudio:音频资源类,属性包括资源地址、音频层级、资源对象,方法主要包括音频加载、卸载、加载完成后的回调
AudioManager:音频管理器
AudioSourceWrapper 类: 这个私有类封装了一个 AudioSource 对象,并且创建了一个与之关联的空 GameObject,用于播放音频。它存储了音频源的名称和位置。
- 音频播放:
PlayMusic
,PlayAmbient
,PlayVoice
,PlaySound
- 音频资源管理:
PreloadReleaseAll
,Release
- 音量和静音控制:
Mute
,VolumeIsMute
,GetVolume
Module.Resource
资源加载相关就是把YooAsset的调用封装了一下
Module.Window
WindowAttribute:可以作为自定义属性用于类上,包含WindowLayer
和FullScreen
两个属性,前者用于表示窗口的层级,后者用于标记窗口是否为全屏
UIRoot:抽象类,用于管理Unity中UI根对象的加载和实例化
UIWindow:抽象类,表示一个可管理的 UI 窗口,具备异步加载、创建、刷新、销毁以及事件管理等功能。抽象方法 OnCreate、OnRefresh、OnUpdate、OnDestroy:在派生类中实现,分别用于窗口的创建、刷新、更新和销毁的具体逻辑。可以通过继承 UIWindow 创建一个具体的窗口类。
WindowManager:支持窗口的打开、关闭、排序等功能。使用 List<UIWindow>
作为栈来实现窗口的管理。
项目代码的注释很清楚,可参考!!!
三、使用方式
1、Module.Event
事件系统支持可回收事件类,对于定义了IReference的事件类会在广播结束后回收该事件对象。
创建事件管理器
public void Start()
{
// 创建模块
MotionEngine.CreateModule<EventManager>();
}
定义事件类
using MotionFramework.Event;
using MotionFramework.Reference;
public class TestEventMsg : IEventMessage, IReference
{
public string Value;
// 在回收的时候该方法会被执行
public void OnRelease()
{
Value = null;
}
}
订阅事件
using UnityEngine;
using MotionFramework.Event;
public class Test
{
public void Start()
{
EventManager.Instance.AddListener<TestEventMsg>