UnityGameFramework | 学习笔记一文记之

勤做减法;不怕改动。
深入阅读,化为己用。
  • Config 全局配置:一种自己定义的只在软件内部流通;一种读取外部文件(.txt/.bytes)后再去使用
    -> ConfigManager:GetBool/Int/Float/String Add/Remove/HasConfig 是通过字典进行的
    Read/ParseData是通过DataProvider进行的
    所以:通过GameEntry.Config.AddConfig添加的“全局”配置项只能在软件中使用(可跨场景),不会保存到本地
    -> DefaultConfigHelper:这个有Read/ParseData的具体实现,从文本或字节解析之后会通过ConfigManager.AddConfig保存到字典去,读就是解析
    -> ProcedurePreload:LoadConfig函数是加载全局配置项:DefaultConfig.txt,主要是保存的Menu和Main的场景编号,加载之后就可以通过Config.GetInt去取了
    ps:1)Read/ParseData实现中的数据会存到ConfigManager的字典(m_ConfigDatas)中。
    2)IDataProviderHelper被ConfigHelperBase、DataTableHelperBase、LocalizationHelperBase继承,数据表和本地化的逻辑应该和全局配置一致

  • DataNode 数据节点:树形结构
    -> IDataNode:泛型T继承于Variable;Get/SetData;有父有子
    ps:并不能像Config一样跨场景使用:场景A Variable v = new VarInt32();
    v.SetValue(1);
    GameEntry.DataNode.SetData(“1”,v);
    场景B Debug.LogWarning($"{GameEntry.DataNode.GetData(“1”)}");

  • DataTable 数据表:从外部文件(.txt/.bytes)读取数据再去使用
    -> DataTableBase:Add/Remove/HasDataRow定义 Read/ParseData和Config一样通过DataProvider进行
    -> DataTable:有泛型的Read/ParseData实现,是对m_DataSet的一系列操作
    -> IDataRow(GF) <- DataRowBase(UGF) <- DRAircraft(每一张数据表对应的类)这个中会有实现ParseDataRow
    -> DataTableExtension:这个里面有创建数据表的实现
    -> ProcedurePreload:LoadDataTable函数就是加载数据表文件
    ps:DRAircraft(数据表对应的类)中有表数据,DataTableManager中有所有的数据表存在字典(m_DataTables)中

  • Debugger 调试器
    -> 没啥好说的,用就得了;有啥想增减的,自己改。

  • Download 下载:从uri下载文件并保存到path
    -> DownloadManager:Add/RemoveDownload等都是通过TaskPool进行,GetDownloadInfo是调用的m_TaskPool.GetTaskInfo
    -> 有两种下载代理辅助器:WWW、WebRequest,Unity2018.3之前的版本可以使用WWW
    -> 通过DownloadSuccessEventArgs事件类传递的m_DownloadPath(文件保存路径),及相关资源如何下载使用的
    VersionListProcessor/ResourceUpdater(OnDownloadSuccess 把数据写入到m_DownloadPath) -> DownloadManager(OnDownloadAgentSuccess 通过DownloadAgent.Task数据传递) ->
    DownloadComponent(AddDownloadAgentHelper) -> DownloadAgent(Start) -> TaskPool(LinkedListNode.Value <- DownloadTask) ->
    TaskPool(AddTask) -> ResourceLoader(LoadAsset/LoadDependencyAsset/LoadScene)

    VersionListProcessor的UpdateVersionList中有调用:m_DownloadManager.AddDownload,这里m_DownloadPath是组装起来的:ReadWritePath+RemoteVersionListFileName
    DownloadManager.AddDownload:创建一个DownloadTask并放入任务池中,返回下载任务的序列编号

    在ResourceLoader中加载Asset/DependencyAsset/Scene的任务类继承关系:
    IReference <- TaskBase <- DownloadTask
    <- LoadResourceTaskBase <- LoadAssetTask
    <- LoadDependencyAssetTask
    <- LoadSceneTask

    ps:这里DownloadComponent和DownloadManager的AddDownload不像WebRequest一样在流程中有直接调用,那这两个类暴露的接口意义何在?

  • Entity 实体:组件数据。Entity+Component+System(ECS)实体+组件+系统
    -> 实体的显示/隐藏,依附/解绑
    -> Star Force中定义了EntityData,再由具体的游戏物体去继承扩展,每一种物体对应的数据其实就是一张表
    -> Star Force中定义了Entity,是继承于UGF的EntityLogic,再由具体的游戏物体去继承扩展,每一种物体的逻辑是根据游戏的玩法而来
    ps:外部的数据,也就是游戏策划表可以按照框架读取,但是具体怎么使用则是玩法来定了。

  • Event 事件:主要管理框架的各种继承而来的XXXEventArgs
    -> EventArgs/IReference <- GameFrameworkEventArgs <- BaseEventArgs <- GameEventArgs(定义的游戏事件基类)
    -> EventManager:定义了一个事件池,其模式为:允许没有事件处理函数、允许有多个事件处理函数
    订阅、取消订阅、分发、立刻分发都是通过事件池进行处理
    事件池的轮询->管理类的轮询->游戏框架组件的轮询->基础组件的轮询
    -> EventComponent:组件中的函数是调用的管理类的方法进行处理,组件获取方式:GameEntry.Event;管理类获取方式:GameFrameworkEntry.GetModule()

  • FileSystem 文件系统:1)区分不同的平台;2)从dat文件读取对应的文件信息
    -> CommonFileSystemStream(GF)
    -> AndroidFileSystemStream(UGF)
    -> ResourceManager(GetFileSystem) -> FileSystemManager(GetFileSystem/LoadFileSystem) -> FileSystem(Load)
    -> FileSystemComponentInspector:编辑器运行模式下,会在挂载FileSystemComponent的物体上额外绘制以下内容
    1)文件系统数量
    2)每个文件系统读取的路径+文件访问模式+文件数量+最大文件数量
    每个文件系统读取的路径:1)单机包,从StreamingAssets来;2)网络包,从Persistent Data Path来
    文件访问模式:Read;Write;ReadWrite
    文件数量/最大文件数量:与ResourceEditor组织资源的形式有关,可以在ResourceCollection.txt中查看FileSystem所属命名
    ps:Android的尚未测试,IOS的是使用CommonFileSystemStream?

  • Fsm 有限状态机(Finite state machine)
    -> Fsm:Get/SetData 从字典中根据name得到Data/先从字典中根据name得到Data,如果Data不为空,则从引用池中释放,再存入字典
    ChangeState 通过状态类型得到FsmState,离开当前状态,进行新状态
    -> FsmState:这个与Procedure结合的很紧密,流程基类:ProcedureBase : FsmState

  • Localization 本地化:从外部文件(.txt/.bytes)读取数据再去使用
    -> LocalizationManager:Has/Add/RemoveRawString/GetString都是通过字典m_Dictionary进行
    Read/ParseData和Config、DataTable一样通过DataProvider进行
    -> DefaultLocalizationHelper:这个有Read/ParseData的具体实现,但是StarForce读取本地化文件用的是XmlLocalizationHelper,这个根据文件内容格式自定义
    -> XmlLocalizationHelper:这个有ParseData具体Xml文件的实现
    ps:不论从哪个辅助器去实现的Read/ParseData,都是会存到LocalizationManager的字典(m_Dictionary)中。

  • NetWork 网络:协议TCP,兼容IPv4/IPv6,提供Socket长连接;接入protoBuf可派生自Packet
    -> 根据不同的服务类型,进不同的TCP网络频道,连接/收/发是走的Socket那一套;可以根据协议类型扩展udp、kcp等
    ps:需要扩充这个模块,并验证框架性。

  • ObjectPool 对象池:主要处理的游戏对象,比如Asset、Resource、UI等
    -> ObjectPoolManager:创建允许单次/多次获取的对象池
    -> ObjectPoolComponentInspector(StarForce):Entity + UI + HPBar + AssetObject + ResourceObject
    Entity:EntityGroup -> IObjectPool m_InstancePool
    UI:UIManager -> IObjectPool m_InstancePool
    HPBar:HPBarComponent -> IObjectPool m_HPBarItemObjectPool
    AssetObject:ResourceLoader -> IObjectPool m_AssetPool
    ResourceObject:ResourceLoader -> IObjectPool m_ResourcePool

    1)对象池基础属性绘制:Name + Type + AutoReleaseInterval + Capacity + Used Count + CanReleaseCount + ExpireTime + Priority
    2)对象池中有对象时对象情况绘制:PoolObjectName + Locked + Count/InUse + Flag + Priority + LastUseTime

    1.EventPool 事件池:主要处理的各种事件,继承自GameFrameworkEventArgs。
    Subscribe/UnSubscribe:订阅/取消订阅事件;
    Fire/FireNow:抛出/立刻抛出事件去分发处理;
    EventPool的Event是通过ReferencePool创建:Event eventNode = ReferencePool.Acquire();
    轮询处理事件,并在引用池中释放处理过的事件节点。
    2.TaskPool 任务池:主要处理下载逻辑,比如Download、WebRequest等组件模块有使用。
    Add/RemoveTask:增加/移除任务
    ProcessRunningTasks/ProcessWaitingTasks:处理正在运行的任务/处理正在等待的任务
    无论是什么池,都有一堆的存储数据结构去处理各种逻辑。
    无论是对象池、事件池、任务池,创建和释放都是通过引用池进行的。
    ReferencePool.Acquire() Reference.Release(T);

  • Procedure 流程
    Launch -> Splash -> Preload(编辑模式) -> ChangeScene -> Main/Menu -> ChangeScene
    -> InitResource(单机模式) -> Preload
    -> CheckVersion(更新模式) -> UpdateVersion -> VerifyResources
    -> VerifyResources -> CheckResources -> UpdateResources -> Preload
    -> Preload
    -> ProcedureBase:流程基类直接继承有限状态机ProcedureBase : FsmState,
    重载方法的参数ProcedureOwner其实是IFsm
    -> ProcedureManager:
    -> ProcedureBase(OnUpdate) -> FsmState(OnUpdate) -> Fsm(Update) -> FsmManager(Update) -> GameFrameworkModule(Update) -> BaseComponent(Update)
    -> ProcedureComponent:IEnumerator Start会创建流程示例,得到入口流程并从入口流程开始
    -> ProcedureComponentInspector:绘制入口流程下拉框、可获取流程
    ps:Star Force的示例流程是比较完整且规范的,可以以此为基础扩展自己的业务。

  • ReferencePool 引用池:万物皆引用
    -> 有一个是否开启强制检查的开关,打开则会检查引用类型:不能为空、必须是非抽象类、必须有定义
    -> ReferenceCollection:正在使用的引用数量、请求引用数量、释放引用数量、增加引用数量、移除引用数量;
    Acquire:从引用的队列中Dequeue(出队)一个引用出来提供使用,如果队列中没有了,则生成一个;
    Release:如果是强制检查并且队列中已经有这个引用了,则抛出异常;否则把该引用Enqueue(入队);
    Add:把一定数量的引用Enqueue(入队);
    Remove:把一定数量的引用Dequeue(出队)。
    ps:这里的引用:1)IReference;2)T

  • Resource 资源:管理所有的资源类型的Verify、Update、Apply等

    • 资源加载
      编辑模式:ProcedurePreload -> AssetUtility
      单机模式:.dat in StreamingAssets 使用Package单机包
      更新模式:读取远端带crc32名称的GameFrameworkVersion.crc32.dat文件 使用Full远端更新包

      【Resource Builder】
      每一次打包之后Internal Resource Version都会+1,然后保存到GameMain/Config/ResourceBuilder.xml中
      Working:工作路径(manifest,无版本)
      Package:单机包,拷贝到StreamingAssets再打包App(dat Version 有版本)
      Full:远端更新包,放到Web服务器(远端)
      Packed:本地更新包,放到StreamingAssets(本地) 【已移除】

    • 版本更新(增加了GameVersion比对)
      调整BuildInfo.txt和WindowsVersion.txt的json串内容和格式,只需要软件版本和资源版本两个作为更新依据。

      0.1.0(0) 主版本号.子版本号.阶段版本号(资源版本号)
      当ResourceMode = Updatable时,进行版本更新

      先比较软件版本的各个子级版本,如果远端的比本地的大,则更新;
      在软件版本相同的情况下,比较资源版本号,如果远端的比本地的大,则更新;

    • Resource Sync Tools(资源同步工具)
      Remove All Asset Bundle Names in Project:移除项目中所有ab名
      Sync ResourceCollection.xml to Project:同步资源合集配置到项目
      Sync ResourceCollection.xml from Project:从项目同步资源合集配置
      ps:核心组件模块,编辑扩展的重点也是这个,与Pool、Download、WebRequest等有密切联系。

  • Scene 场景:对场景资源的加载/卸载
    -> ProcedureChangeScene(OnEnter -> GameEntry.Scene.LoadScene) -> SceneComponent(LoadScene) -> SceneManager(LoadScene) ->
    ResourceManager(LoadScene) -> ResourceLoader(LoadScene) -> 1)LoadSceneTask放到任务池中轮询处理;2)资源为准备好则使用资源管理器去更新
    -> DefaultLoadResourceAgentHelper.cs的LoadAsset中:SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive),是附加加载的

  • Setting 游戏配置项:1)从GameFrameworkSetting.dat中存取数据;2)使用PlayerPrefs存取数据
    -> SettingComponent:Has/RemoveSetting Get/SetInt Get/SetFloat Get/SetBool Get/SetString Get/SetObject
    -> 调用关系:SettingComponent -> ISettingManager -> SettingManager -> ISettingHelper -> SettingHelperBase
    -> DefaultSettingHelper
    -> PlayerPrefsSettingHelper
    -> DefaultSettingHelper:通过DefaultSetting中的SortedDictionary(m_Settings)进行存取
    -> PlayerPrefsSettingHelper:通过Unity的PlayerPrefs完成对游戏项目的本地化存取,具体保存的路径可查看官方文档:
    https://docs.unity3d.com/ScriptReference/PlayerPrefs.html

  • Sound 声音
    -> DefaultSoundHelper(ReleaseSoundAsset) -> ResourceComponent(UnloadAsset) -> ResourceManager(UnloadAsset) -> ResourceLoader(UnloadAsset) ->
    ObjectPool(Unspawn) -> 从ObjectMap中得到Object,如果内部对象不为空,则回收;如果对象池中对象数量大于池的容量且内部对象被获取的次数<=0,则释放。
    -> DefaultSoundAgentHelper:Play/Resume 播放/恢复声音(有一个淡入的时间) Pause/Stop 暂停/停止声音(有一个淡出的时间)
    每一个声音代理辅助器上都有一个AudioSource,且默认:PlayOnAwake = false; rolloffMode = AudioRolloffMode.Custom
    -> DefaultSoundGroupHelper:继承于SoundGroupHelperBase,有一个AudioMixerGroup
    -> SoundComponentInspector:绘制了三个辅助器、SoundGroup的详细信息
    -> SoundComponent:SoundGroup的信息可以在Inspector面板配置,在Start中会调用AddSoundGroup进行声音组添加。
    ps:需要掌握AudioMixer在框架里面使用的技巧。

  • UI 用户界面
    -> 当UIComponent的InstanceRoot没有给定的时候,会自动创建,添加UI组的时候需要把UI组辅助器上Canvas的渲染模式设置为Overlay或者给它绑定WorldCamera。
    ->ProcedureMenu(OnEnter)/GameEntry.UI.OpenUIForm(UIFormId.MenuForm, this) -> UIExtension(OpenUIForm)
    从数据表中得到对应根据UIFromId枚举转换的索引得到的数据行信息,然后得到资产名称,用AssetUtility组装成完整预制路径,
    如果表单数据行(DRUIFrom)不允许多个实例,UI组件正在加载此资产或者已经存在,则不会被打开;否则打开此UI界面,
    通过对象池获取一个UI表单实例对象,如果为空,则使用ResourceManager.LoadAsset;否则使用InternalOpenUIForm,
    LoadAsset会通过ResourceLoader创建一个LoadAssetTask放入任务池去处理,如果有代理的则交给代理处理,最后在XXXSuccessEventArgs中被携带
    InternalOpenUIForm会通过辅助器创建一个实例对象,以辅助器作为父物体绑定,并返回一个UIFrom,再对UIFrom进行逻辑处理。

  • WebRequest 网络请求:主要是Unity WebRequest,通过网络请求得到数据字节流,不会保存到本地
    -> GetWebRequestInfo和GetDownloadInfo一样,返回的都是TaskInfo
    -> WebRequestManager:Add/RemoveWebRequest
    -> 网络响应的数据流在WebRequestSuccessEventArgs中有字节数组存储(m_WebResponseBytes),但是不会写入到本地磁盘
    -> ProcedureCheckVersion:OnWebRequestSuccess(byte[] versionInfoBytes = ne.GetWebResponseBytes();
    -> 有两种网络请求代理辅助器:WWW、WebRequest,Unity2018.3之前的版本可以使用WWW
    -> 增加一个网络请求 -> 订阅/取消订阅网络请求事件
    ps:资源更新模式时,本地文件(BuildInfo.txt)中指向远端更新文件的地址,是通过网络请求方式调用的任务池。

你可能感兴趣的:(Frameworks,unity,游戏引擎)