经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » 游戏设计 » 查看文章
Unity进阶之ET网络游戏开发框架 02-ET的客户端启动流程分析
来源:cnblogs  作者:优梦创客  时间:2019/8/19 8:35:33  对本文有异议

版权申明:

  • 本文原创首发于以下网站:
  1. 博客园『优梦创客』的空间:https://www.cnblogs.com/raymondking123
  2. 优梦创客的官方博客:https://91make.top
  3. 优梦创客的游戏讲堂:https://91make.ke.qq.com
  4. 『优梦创客』的微信公众号:umaketop
  • 您可以自由转载,但必须加入完整的版权声明!

万物起源:Init.cs

  • 打开范例场景init.unity,可以发现其场景层级如下:
    • 其中唯一重要的就是Global对象上挂在的init.cs脚本,关于其基础代码分析,还是建议大家看初见的教程(ghithub有链接)
    • 在这里只想重点分析大家一定会关心的一个问题:init.cs是如何加载初始界面的

init.cs是如何加载初始界面的:

  • 上节课分析了,init.cs首先加载UILoading界面,其加载流程大致是这样的,先上序列图,稍后结合序列图贴代码分析:
sequenceDiagram Unity->> +Init: StartAsync Init ->> BundleHelper: DownloadBundle() BundleHelper->>EventSystem: Run(EventIdType.LoadingBegin) EventSystem->>LoadingBeginEvent_CreateLoadingUI: Run() LoadingBeginEvent_CreateLoadingUI->>UILoadingFactory: Create() note right of UILoadingFactory: 实例化UILoading预制体,并附加UILoadingComponent(更新并显示加载进度) Init->>-Unity: StartAsync
  • 加载初始界面的几个步骤如下:
  1. 调用EventSystem.Run(EventIdType.LoadingBegin)引发LoadingBegin事件:
  1. public static class BundleHelper
  2. {
  3. public static async ETTask DownloadBundle()
  4. {
  5. if (Define.IsAsync)
  6. {
  7. try
  8. {
  9. using (BundleDownloaderComponent bundleDownloaderComponent = Game.Scene.AddComponent<BundleDownloaderComponent>())
  10. {
  11. await bundleDownloaderComponent.StartAsync();
  12. Debug.Log("EventIdType.LoadingBegin");
  13. Game.EventSystem.Run(EventIdType.LoadingBegin);
  14. await bundleDownloaderComponent.DownloadAsync();
  15. }
  16. Game.EventSystem.Run(EventIdType.LoadingFinish);
  17. Game.Scene.GetComponent<ResourcesComponent>().LoadOneBundle("StreamingAssets");
  18. ResourcesComponent.AssetBundleManifestObject = (AssetBundleManifest)Game.Scene.GetComponent<ResourcesComponent>().GetAsset("StreamingAssets", "AssetBundleManifest");
  19. }
  20. catch (Exception e)
  21. {
  22. Log.Error(e);
  23. }
  24. }
  25. }
  26. }
  • 由于在unity编辑器环境下IsAsync标志被设为false(在VS环境下选中IsAsync成员,右键→速览定义可见),也即异步加载资源才可见loading画面,所以实际上不会看到loading画面!
  • 第19行为等待异步加载完毕后引发LoadingFinish事件,其流程与LoadingBegin类似,请同学们自行分析!
  1. 实现LoadingBegin事件处理程序:

    1. [Event(EventIdType.LoadingBegin)]
    2. public class LoadingBeginEvent_CreateLoadingUI : AEvent
    3. {
    4. public override void Run()
    5. {
    6. UI ui = UILoadingFactory.Create();
    7. Game.Scene.GetComponent<UIComponent>().Add(ui);
    8. }
    9. }

    在这里有需要注意学习定义事件类的方法: 1. 为一个类添加Event标志(参数填具体事件类型) 2. 从AEvent继承 3. 此时,ET就会自动将该类识别为一个事件处理类(通过反射机制),并在EventSystem.Run被调用时执行LoadingBeginEvent_CreateLoadingUI事件类的Run方法!

  2. 第六行代码UILoadingFactory.Create()负责创建UILoading界面,下面代码加了注释:

    1. public static class UILoadingFactory
    2. {
    3. public static UI Create()
    4. {
    5. try
    6. {
    7. // KV是Resources文件夹下存储的本地预制体资源,主要存储一些键值对数据
    8. // 从KV加载UIType.UILoading预制体,并实例化UI对象:
    9. GameObject bundleGameObject = ((GameObject)ResourcesHelper.Load("KV")).Get<GameObject>(UIType.UILoading);
    10. GameObject go = UnityEngine.Object.Instantiate(bundleGameObject);
    11. go.layer = LayerMask.NameToLayer(LayerNames.UI);
    12. // 创建UI这个Entity,并将上面创建的UI对象作为该Entity的图形表示
    13. UI ui = ComponentFactory.Create<UI, string, GameObject>(UIType.UILoading, go, false);
    14. // 添加UILoadingComponent,该组件负责更新loading进度并刷新显示
    15. ui.AddComponent<UILoadingComponent>();
    16. return ui;
    17. }
    18. catch (Exception e)
    19. {
    20. Log.Error(e);
    21. return null;
    22. }
    23. }
    24. }

    说明: - UI类是一个Entity类,Entity间接从Component类继承,但只有Entity类可以附加组件,Component类不行 - Entity和Component的关系实际就是设计模式中的Composite模式 - UI类可以复用,当你要创建一个UI时,在ET框架下只要: - 添加一个static的UI工厂类,并在其中定义一个static的Create方法,具体实现参照UILoadingFactory - 为该工厂添加一个新的UI组件(从Component类继承),并实现该组件的事件系统(见下文)

  3. 实现UILoadingComponent并实现该组件的事件系统:

    • UILoading组件
    1. public class UILoadingComponent : Component
    2. {
    3. public Text text;
    4. }
    • UILoading事件系统:
    1. [ObjectSystem]
    2. public class UiLoadingComponentAwakeSystem : AwakeSystem<UILoadingComponent>
    3. {
    4. public override void Awake(UILoadingComponent self)
    5. {
    6. self.text = self.GetParent<UI>().GameObject.Get<GameObject>("Text").GetComponent<Text>();
    7. }
    8. }
    9. [ObjectSystem]
    10. public class UiLoadingComponentStartSystem : StartSystem<UILoadingComponent>
    11. {
    12. public override void Start(UILoadingComponent self)
    13. {
    14. StartAsync(self).Coroutine();
    15. }
    16. public async ETVoid StartAsync(UILoadingComponent self)
    17. {
    18. TimerComponent timerComponent = Game.Scene.GetComponent<TimerComponent>();
    19. long instanceId = self.InstanceId;
    20. while (true)
    21. {
    22. await timerComponent.WaitAsync(1000);
    23. if (self.InstanceId != instanceId)
    24. {
    25. return;
    26. }
    27. BundleDownloaderComponent bundleDownloaderComponent = Game.Scene.GetComponent<BundleDownloaderComponent>();
    28. if (bundleDownloaderComponent == null)
    29. {
    30. continue;
    31. }
    32. self.text.text = $"{bundleDownloaderComponent.Progress}%";
    33. }
    34. }
    35. }

    事件类的定义: 1. 添加[ObjectSystem]标志 2. 继承自对应的XxxSystem类,并实现基类的虚方法 - 事件类与Unity中含义类似,请自行参阅源码学习

总结:

  • 通过对UILoading的学习,我们已经接触了ET的一个完整的ECS对象:
    • E:Entity,对应UI类
    • C:Component,对应UILoadingComponent类
    • S:System, 对应UiLoadingComponentAwakeSystem和 UiLoadingComponentStartSystem类

原文链接:http://www.cnblogs.com/raymondking123/p/11369623.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号