Unity进阶之ET网络游戏开发框架 02-ET的客户端启动流程分析

摘要:
第19行为等待异步加载完毕后引发LoadingFinish事件,其流程与LoadingBegin类似,请同学们自行分析!
版权申明:
  • 本文原创首发于以下网站:
  1. 博客园『优梦创客』的空间:https://www.cnblogs.com/raymondking123
  2. 优梦创客的官方博客:https://91make.top
  3. 优梦创客的游戏讲堂:https://91make.ke.qq.com
  4. 『优梦创客』的微信公众号:umaketop
  • 您可以自由转载,但必须加入完整的版权声明!
万物起源:Init.cs
  • 打开范例场景init.unity,可以发现其场景层级如下:
    Unity进阶之ET网络游戏开发框架 02-ET的客户端启动流程分析第1张
    • 其中唯一重要的就是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事件:
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类似,请同学们自行分析!
  1. 实现LoadingBegin事件处理程序:

    [Event(EventIdType.LoadingBegin)]
    public class LoadingBeginEvent_CreateLoadingUI : AEvent
    {
    	public override void Run()
    	{
    		UI ui = UILoadingFactory.Create();
    		Game.Scene.GetComponent<UIComponent>().Add(ui);
    	}
    }
    

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

  2. 第六行代码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;
    		}
    	}
    }
    

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

  3. 实现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}%";
    		}
    	}
    }
    

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

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

免责声明:文章转载自《Unity进阶之ET网络游戏开发框架 02-ET的客户端启动流程分析》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇自定义地图开发(一)各大免费邮箱邮件群发账户SMTP服务器配置及SMTP发送量限制情况下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Unity3d之音效播放和调用手机震动

http://blog.csdn.net/sunshine_1984/article/details/12943979 今天研究了下Unity3d音效播放相关内容,整理下实现细节。 1,添加音效文件到Assets/Resources目录,我这里添加到Assets/Resources/audio目录了。 2,新建C# Script命名为audio 3,编写a...

unity, 设置帧率上限

用unity做了个demo,把所有开销大的特效都去了,在真机上运行仍然卡。显示帧率来看,最高到30。原来unity在ios设备上帧率默认限制为不超过30。 可以通过Application.targetFrameRate = 60;改成最高60。注意这个设置对编辑器无效。 参考: http://answers.unity3d.com/questions/32...

再议Unity优化

0x00 前言 在很长一段时间里,Unity项目的开发者的优化指南上基本都会有一条关于使用GetCompnent方法获取组件的条目(例如14年我的这篇博客《深入浅出聊Unity3D项目优化:从Draw Calls到GC》)。有时候还会发展为连一些Unity内部对象的属性访问器都要小心使用的注意事项,记得曾经有一段时间我们的项目组也会严格要求把例如trans...

Unity打开外部程序exe/Bat文件方案

Unity调用外部程序/Bat文件 本文提供全流程,中文翻译。 Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例) Chinar —— 心分享、心创新!助力完成 Unity 打开外部程序 exe / bat 文件为新手节省宝贵的时间,避免采坑! Chinar 教程效果:...

Unity3D学习笔记(四) 脚本内访问其他对象,组件或脚本成员方法总结

(2012-07-08 13:40:50) 部分函数尽量不可在update使用,否则极其消耗资源1.在一个脚本内访问其他对象:  想得到对象:可以用下述函数得到对象,或者直接定义一个变量让外部手动传入(可以的话尽量如此)。①通过名字访问对象(消耗资源较多),注意对象名字分为带层次和不带层次。以A为例,"A"为可带父级,"/A"为不可含父级,"C/B/A"为...

Unity3d dll 热更新 基础框架

APK包装到用户手机上后,代码如何更新,总不能全用LUA吧?特别是代码非常多的战斗手游 昨晚上有了dll 热更新的想法,今天做了一天的实验,也遇到些坑,这里总结下 工作环境: U3D5.3.2 + vs2010 +mono 下面要模拟的是一个登陆环境,点击按钮,就加载一个iGameObjec的Item,  Item 上得到更新的文本内容。具体如下图 1&g...