版权申明:
- 本文原创首发于以下网站:
- 博客园『优梦创客』的空间:https://www.cnblogs.com/raymondking123
- 优梦创客的官方博客:https://91make.top
- 优梦创客的游戏讲堂:https://91make.ke.qq.com
- 『优梦创客』的微信公众号:umaketop
万物起源:Init.cs
- 打开范例场景init.unity,可以发现其场景层级如下:
- 其中唯一重要的就是Global对象上挂在的init.cs脚本,关于其基础代码分析,还是建议大家看初见的教程(ghithub有链接)
- 在这里只想重点分析大家一定会关心的一个问题:init.cs是如何加载初始界面的
init.cs是如何加载初始界面的:
- 上节课分析了,init.cs首先加载UILoading界面,其加载流程大致是这样的,先上序列图,稍后结合序列图贴代码分析:
sequenceDiagramUnity->> +Init: StartAsyncInit ->> BundleHelper: DownloadBundle()BundleHelper->>EventSystem: Run(EventIdType.LoadingBegin)EventSystem->>LoadingBeginEvent_CreateLoadingUI: Run()LoadingBeginEvent_CreateLoadingUI->>UILoadingFactory: Create()note right of UILoadingFactory: 实例化UILoading预制体,并附加UILoadingComponent(更新并显示加载进度)Init->>-Unity: StartAsync
- 加载初始界面的几个步骤如下:
- 调用
EventSystem.Run(EventIdType.LoadingBegin)
引发LoadingBegin事件:
public static class BundleHelper
{
public static async ETTask DownloadBundle()
{
if (Define.IsAsync)
{
try
{
using (BundleDownloaderComponent bundleDownloaderComponent = Game.Scene.AddComponent<BundleDownloaderComponent>())
{
await bundleDownloaderComponent.StartAsync();
Debug.Log("EventIdType.LoadingBegin");
Game.EventSystem.Run(EventIdType.LoadingBegin);
await bundleDownloaderComponent.DownloadAsync();
}
Game.EventSystem.Run(EventIdType.LoadingFinish);
Game.Scene.GetComponent<ResourcesComponent>().LoadOneBundle("StreamingAssets");
ResourcesComponent.AssetBundleManifestObject = (AssetBundleManifest)Game.Scene.GetComponent<ResourcesComponent>().GetAsset("StreamingAssets", "AssetBundleManifest");
}
catch (Exception e)
{
Log.Error(e);
}
}
}
}
- 由于在unity编辑器环境下IsAsync标志被设为false(在VS环境下选中IsAsync成员,右键→速览定义可见),也即异步加载资源才可见loading画面,所以实际上不会看到loading画面!
- 第19行为等待异步加载完毕后引发LoadingFinish事件,其流程与LoadingBegin类似,请同学们自行分析!
实现LoadingBegin事件处理程序:
[Event(EventIdType.LoadingBegin)] public class LoadingBeginEvent_CreateLoadingUI : AEvent { public override void Run() { UI ui = UILoadingFactory.Create(); Game.Scene.GetComponent<UIComponent>().Add(ui); } }
第六行代码
UILoadingFactory.Create()
负责创建UILoading界面,下面代码加了注释:public static class UILoadingFactory { public static UI Create() { try { // KV是Resources文件夹下存储的本地预制体资源,主要存储一些键值对数据 // 从KV加载UIType.UILoading预制体,并实例化UI对象: GameObject bundleGameObject = ((GameObject)ResourcesHelper.Load("KV")).Get<GameObject>(UIType.UILoading); GameObject go = UnityEngine.Object.Instantiate(bundleGameObject); go.layer = LayerMask.NameToLayer(LayerNames.UI); // 创建UI这个Entity,并将上面创建的UI对象作为该Entity的图形表示 UI ui = ComponentFactory.Create<UI, string, GameObject>(UIType.UILoading, go, false); // 添加UILoadingComponent,该组件负责更新loading进度并刷新显示 ui.AddComponent<UILoadingComponent>(); return ui; } catch (Exception e) { Log.Error(e); return null; } } }
实现UILoadingComponent并实现该组件的事件系统:
- UILoading组件
public class UILoadingComponent : Component { public Text text; }
- UILoading事件系统:
[ObjectSystem] public class UiLoadingComponentAwakeSystem : AwakeSystem<UILoadingComponent> { public override void Awake(UILoadingComponent self) { self.text = self.GetParent<UI>().GameObject.Get<GameObject>("Text").GetComponent<Text>(); } } [ObjectSystem] public class UiLoadingComponentStartSystem : StartSystem<UILoadingComponent> { public override void Start(UILoadingComponent self) { StartAsync(self).Coroutine(); } public async ETVoid StartAsync(UILoadingComponent self) { TimerComponent timerComponent = Game.Scene.GetComponent<TimerComponent>(); long instanceId = self.InstanceId; while (true) { await timerComponent.WaitAsync(1000); if (self.InstanceId != instanceId) { return; } BundleDownloaderComponent bundleDownloaderComponent = Game.Scene.GetComponent<BundleDownloaderComponent>(); if (bundleDownloaderComponent == null) { continue; } self.text.text = $"{bundleDownloaderComponent.Progress}%"; } } }
总结:
- 通过对UILoading的学习,我们已经接触了ET的一个完整的ECS对象:
- E:Entity,对应UI类
- C:Component,对应UILoadingComponent类
- S:System,对应UiLoadingComponentAwakeSystem和UiLoadingComponentStartSystem类