Unity常见框架探索-ET框架探索

这篇具有很好参考价值的文章主要介绍了Unity常见框架探索-ET框架探索。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

ET框架是类ECS的一个Unity前后端框架

论坛地址为:https://et-framework.cn

Git地址为:https://github.com/egametang/ET

预备知识

Unity程序集的使用

接入流程

本文将会以7.2版本进行分析。所以直接clone github上的仓库,将工程导入到本地,之后将分支切换到最新的release分支,"release7.2"

菜单栏相关

ENABLE_CODE选项

ET->ChangeDefine->ADD_ENABLE_CODE/REMOVE_ENABLE_CODE

一般在开发阶段使用Editor时需要启用ENABLE_CODE选项。该选项启用时,修改脚本之后,会直接重新编译所有的代码,Editor在运行时会直接使用最新的程序集。如果ENABLE_CODE选项是关闭的,框架启动后会加载之前生成的程序集文件(这个文件需要在ET->BuildTool界面生成),导致每次需要应用修改,都要重新生成程序集文件。

框架解析

框架入口解析

启动流程如下

  • 入口文件为Init,之后调用CodeLoader对代码进行加载
  • 如果是EnableCodes模式则直接加载程序集。否则通过AB加载文件,之后调用LoadHotfix函数
  • LoadHotfix会加载程序集,并且调用EventSystem,根据特性注册对应事件的监听。
  • 之后调用ET.Entry的Start方法。
  • ET.Entry.Start 进行初始化之后,推送对应的EntryEvent事件
  • 推送EntryEvent3,EntryEvent3_InitClient接收后推送AppStartInitFinish
  • AppStartInitFinish_CreateLoginUI接收该事件后,创建UI场景

UI系统

UI界面的生成流程

ET是通过异步方式创建UI,如下方例子,调用UIHelper.Create方法,指定创建UI的场景,UI类型和对应的层级

C#
        protected override async ETTask Run(Scene scene, EventType.AppStartInitFinish args)
        {
            await UIHelper.Create(scene, UIType.UILogin, UILayer.Mid);
        }

调用scene挂载的UIComponent组件,处理Create事件

C#
        public static async ETTask<UI> Create(Scene scene, string uiType, UILayer uiLayer)
        {
            return await scene.GetComponent<UIComponent>().Create(uiType, uiLayer);
        }

之后会标记有对应UIEvent特性的类,处理该事件,开始加载资源并生成对应的GameObject

C#
    [UIEvent(UIType.UILogin)]
    public class UILoginEvent: AUIEvent
    {
        public override async ETTask<UI> OnCreate(UIComponent uiComponent, UILayer uiLayer)
        {
            await uiComponent.DomainScene().GetComponent<ResourcesLoaderComponent>().LoadAsync(UIType.UILogin.StringToAB());
            GameObject bundleGameObject = (GameObject) ResourcesComponent.Instance.GetAsset(UIType.UILogin.StringToAB(), UIType.UILogin);
            GameObject gameObject = UnityEngine.Object.Instantiate(bundleGameObject, UIEventComponent.Instance.GetLayer((int)uiLayer));
            UI ui = uiComponent.AddChild<UI, string, GameObject>(UIType.UILogin, gameObject);
            ui.AddComponent<UILoginComponent>();
            return ui;
        }

        public override void OnRemove(UIComponent uiComponent)
        {
            ResourcesComponent.Instance.UnloadBundle(UIType.UILogin.StringToAB());
        }
    }

UI组件解析

以UILogin为例子,对应的Prefab实际上只挂载了ReferenceCollector,ReferenceCollector负责将结点进行绑定

Unity常见框架探索-ET框架探索

生成该GameObject之后,调用AddComponent

C#
GameObject gameObject = UnityEngine.Object.Instantiate(bundleGameObject, UIEventComponent.Instance.GetLayer((int)uiLayer));
UI ui = uiComponent.AddChild<UI, string, GameObject>(UIType.UILogin, gameObject);
ui.AddComponent<UILoginComponent>();

其中UILoginComponent负责显示对应成员

C#
[ComponentOf(typeof(UI))]
public class UILoginComponent: Entity, IAwake
{
    public GameObject account;
    public GameObject password;
    public GameObject loginBtn;
}

AddComponent之后,会调用对应的System,这里UILoginComponentSystem就是对应的System,在Awake阶段通过ReferenceCollector对UILoginComponent进行了绑定,以及实现了对应的UI逻辑

C#
[ObjectSystem]
public class UILoginComponentAwakeSystem : AwakeSystem<UILoginComponent>
{
    protected override void Awake(UILoginComponent self)
    {
        ReferenceCollector rc = self.GetParent<UI>().GameObject.GetComponent<ReferenceCollector>();
        self.loginBtn = rc.Get<GameObject>("LoginBtn");
        self.loginBtn.GetComponent<Button>().onClick.AddListener(()=> { self.OnLogin(); });
        self.account = rc.Get<GameObject>("Account");
        self.password = rc.Get<GameObject>("Password");
     }
}

场景切换

关于ET的场景切换相关逻辑可以查看

UILobbyComponentSystem处理进入Map的操作,先是调用EnterMap异步函数,等待EnterMapHelper异步返回后删除界面

C#
        //UILobbyComponentSystem
        public static async ETTask EnterMap(this UILobbyComponent self)
        {
            await EnterMapHelper.EnterMapAsync(self.ClientScene());
            await UIHelper.Remove(self.ClientScene(), UIType.UILobby);
        }

之后EnterMapHelper会向服务器发起进入Map的请求

C#
        //EnterMapHelper
        public static async ETTask EnterMapAsync(Scene clientScene)
        {
            try
            {
                G2C_EnterMap g2CEnterMap = await clientScene.GetComponent<SessionComponent>().Session.Call(new C2G_EnterMap()) as G2C_EnterMap;
                clientScene.GetComponent<PlayerComponent>().MyId = g2CEnterMap.MyId;
               
                // 等待场景切换完成
                await clientScene.GetComponent<ObjectWait>().Wait<Wait_SceneChangeFinish>();
               
                EventSystem.Instance.Publish(clientScene, new EventType.EnterMapFinish());
            }
            catch (Exception e)
            {
                Log.Error(e);
            }       
        }

网络模块

获取路由地址示例

下面以获取路由地址为例,分析ET框架完成一次HTTP请求的过程。

主要包含的类有RouterAddressComponentSystem,RouterAddressComponent

其中RouterAddressComponent为数据的载体,负责填写请求参数,以及保存返回的数据

C#
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;

namespace ET.Client
{
    [ComponentOf(typeof(Scene))]
    public class RouterAddressComponent: Entity, IAwake<string, int>
    {
        public IPAddress RouterManagerIPAddress { get; set; }
        public string RouterManagerHost;
        public int RouterManagerPort;
        public HttpGetRouterResponse Info;
        public int RouterIndex;
    }
}

RouterAddressComponentSystem则是处理获取路由的逻辑

C#
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace ET.Client
{
    [FriendOf(typeof(RouterAddressComponent))]
    public static class RouterAddressComponentSystem
    {
        public class RouterAddressComponentAwakeSystem: AwakeSystem<RouterAddressComponent, string, int>
        {
            protected override void Awake(RouterAddressComponent self, string address, int port)
            {
                self.RouterManagerHost = address;
                self.RouterManagerPort = port;
            }
        }
       
        public static async ETTask Init(this RouterAddressComponent self)
        {
            self.RouterManagerIPAddress = NetworkHelper.GetHostAddress(self.RouterManagerHost);
            await self.GetAllRouter();
        }

        private static async ETTask GetAllRouter(this RouterAddressComponent self)
        {
            string url = $"http://{self.RouterManagerHost}:{self.RouterManagerPort}/get_router?v={RandomGenerator.RandUInt32()}";
            Log.Debug($"start get router info: {url}");
            string routerInfo = await HttpClientHelper.Get(url);
            Log.Debug($"recv router info: {routerInfo}");
            HttpGetRouterResponse httpGetRouterResponse = JsonHelper.FromJson<HttpGetRouterResponse>(routerInfo);
            self.Info = httpGetRouterResponse;
            Log.Debug($"start get router info finish: {JsonHelper.ToJson(httpGetRouterResponse)}");
           
            // 打乱顺序
            RandomGenerator.BreakRank(self.Info.Routers);
           
            self.WaitTenMinGetAllRouter().Coroutine();
        }
       
        // 等10分钟再获取一次
        public static async ETTask WaitTenMinGetAllRouter(this RouterAddressComponent self)
        {
            await TimerComponent.Instance.WaitAsync(10 * 60 * 1000);
            if (self.IsDisposed)
            {
                return;
            }
            await self.GetAllRouter();
        }

        public static IPEndPoint GetAddress(this RouterAddressComponent self)
        {
            if (self.Info.Routers.Count == 0)
            {
                return null;
            }

            string address = self.Info.Routers[self.RouterIndex++ % self.Info.Routers.Count];
            string[] ss = address.Split(':');
            IPAddress ipAddress = IPAddress.Parse(ss[0]);
            if (self.RouterManagerIPAddress.AddressFamily == AddressFamily.InterNetworkV6)
            {
                ipAddress = ipAddress.MapToIPv6();
            }
            return new IPEndPoint(ipAddress, int.Parse(ss[1]));
        }
       
        public static IPEndPoint GetRealmAddress(this RouterAddressComponent self, string account)
        {
            int v = account.Mode(self.Info.Realms.Count);
            string address = self.Info.Realms[v];
            string[] ss = address.Split(':');
            IPAddress ipAddress = IPAddress.Parse(ss[0]);
            //if (self.IPAddress.AddressFamily == AddressFamily.InterNetworkV6)
            //{
            //    ipAddress = ipAddress.MapToIPv6();
            //}
            return new IPEndPoint(ipAddress, int.Parse(ss[1]));
        }
    }
}

请求过程,是先添加RouterAddressComponent组件,在添加时填入对应的HTTP请求地址和端口号

之后调用routerAddressComponent的Init方法。

C#
//获取RouterAddressComponent
RouterAddressComponent routerAddressComponent = clientScene.GetComponent<RouterAddressComponent>();
if (routerAddressComponent == null)
{
    //如果RouterAddressComponent不存在,就添加RouterAddressComponent组件,并且填入HTTP请求的地址和端口号
    routerAddressComponent = clientScene.AddComponent<RouterAddressComponent, string, int>(ConstValue.RouterHttpHost, ConstValue.RouterHttpPort);
    await routerAddressComponent.Init();
    clientScene.AddComponent<NetClientComponent, AddressFamily>(routerAddressComponent.RouterManagerIPAddress.AddressFamily);
}

C#
  public static async ETTask Init(this RouterAddressComponent self)
        {
            self.RouterManagerIPAddress = NetworkHelper.GetHostAddress(self.RouterManagerHost);
            await self.GetAllRouter();
        }
       

Protobuf的使用

proto文件

Proto文件放在Unity/Assets/Config/Proto之下

并且文件名有特定的命名规范,以InnerMessage_S_20001.proto为例,以"_"为分割符,第一个字符串"InnerMessage"是文件名,第二个字符串"S"是用于区分Server还是Client,第三个字符串"20001"为协议起始的编号

生成Protoc#文件

点击菜单栏ET->Build Tool->Proto2CS,生成成功之后会在Scripts/Codes/Model/Generate

Unity常见框架探索-ET框架探索

需要注意的是et使用的是protobuf-net

https://github.com/protobuf-net/protobuf-net

区别于google的protocolbuffers的c#版本

https://github.com/protocolbuffers/protobuf

问题解决

1.当前 .NET SDK 不支持将 .NET 6.0 设置为目标。请将 .NET 5.0 或更低版本设置为目标,或使用支持 .NET 6.0 .NET SDK 版本。    C:\Program Files\dotnet\sdk\5.0.414\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.TargetFrameworkInference.targets        141       

解决方案:这个问题是由于visiual studio 2019 不支持.NET 6.0。需要将开发软件升级到visual studio 2022文章来源地址https://www.toymoban.com/news/detail-493127.html

到了这里,关于Unity常见框架探索-ET框架探索的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 02-ET框架的ECS编程思想

    TIPS: 本系列贴仅用于博主学习ET框架的记录 今天来学习OOP以外的另一种编程思想—ECS。 ECS:实体(Entity)、组件(Component)、系统(System),同时在框架中(实体即组件、组件即实体)类似电脑是一个实体,键盘是电脑的一个组件,但同时键盘也是一个实体,因为其下面还有按键这种

    2024年02月08日
    浏览(36)
  • ET框架6.0分析二、异步编程

    ET框架很多地方都用到了异步,例如资源加载、AI、Actor模型等等。ET框架对C#的异步操作进行了一定程度的封装和改造,有一些特点: 显式的或者说强调了使用C#异步实现协程机制(其实C#的异步编程天生就能实现这种用法) 强制单线程异步 没有使用C#库的Task,自己实现了E

    2024年02月04日
    浏览(34)
  • ET框架6.0分析三、网络通信

    ET框架的消息机制贯彻始终,包含Entity消息(Awake,Update ...),自定义(Customer)消息,网络消息等。而ET系统的进程包含了客户端、Gate等各种类型的服务器,进程包含各种服务器客户端之间通过网络消息进行通信进行工作。 结构图为了更加明确整体关系,进行了一定程度的简化

    2024年02月08日
    浏览(36)
  • ET框架6.0分析一、ECS架构

    ET框架的ECS架构是从ECS原生设计思想变形而来的(关于ECS架构的分析可以参考跳转链接:《ECS架构分析》),其特点是: Entity:实体可以作为组件挂载到其他实体上,Entity之间可以有父子嵌套关系,和其他ECS架构一样,Entity只允许是纯数据的(除了基本接口) System:和其他

    2024年02月04日
    浏览(35)
  • HTML5游戏引擎(一)-egret引擎简介——一个开源免费的游戏框架

    游戏行业发展迅速, 给程序员提供了大量就业 (斗鱼, 微派, 腾讯, 蓝月, 网易 等等) 游戏开发薪资普遍比较高 (王者荣耀 , 蓝月) 游戏已经普遍被大众所认可,并且发展成一种竞技体育 重点学习Egret Typescrit 语法学习 一笔带过Cocos2d-x Egret跨平台,入手容易,性能较好,更

    2024年02月05日
    浏览(75)
  • ET介绍——更为便捷高效的AI框架-行为机(Behavior Machine)

    顾名思义,类比状态机每个节点是一个状态,行为机每个节点是描述一种行为。行为机每个节点之间是互斥的,并且节点相互之间完全不用关心是怎么切换的。这里就不讲状态机跟行为树是怎么做ai的了,这里只讲用行为机怎么做一个ai。举个例子 mmo中的小怪策划案,大致会

    2024年02月05日
    浏览(39)
  • 一个简单好用的C语言单元测试框架-Unity

    Unity是一个用于C语言的轻量级单元测试框架。它由Throw The Switch团队开发,旨在简化嵌入式系统的单元测试。单元测试中单元的含义,单元就是人为规定的最小的被测功能模块,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。在

    2024年01月21日
    浏览(58)
  • 【Unity小技巧】手戳一个简单易用的游戏UI框架(附源码)

    参考原视频链接: 【视频】:https://www.bilibili.com/video/BV1zT411b7L3/ 注意 :本文为学习笔记记录,推荐支持原作者,去看原视频自己手敲代码理解更加深入 开发一款游戏美术成本是极其高昂的,以我们常见的宣传片CG为例,动辄就要成百上千万的价格,因此这种美术物料一般只

    2024年02月11日
    浏览(52)
  • 简介:在这篇教程中,我们将使用React.js框架创建一个简单的聊天机器人的前端界面,并利用Dialogflo

    作者:禅与计算机程序设计艺术 介绍及动机 聊天机器人(Chatbot)一直是互联网领域中的热门话题。而很多聊天机器人的功能都依赖于人工智能(AI)技术。越来越多的企业希望拥有自己的聊天机器人系统,从而提升自己的竞争力。为此,业界也出现了很多基于开源技术或云

    2024年02月06日
    浏览(59)
  • 记录:ET6 框架,由于 vs2019 不支持 .NET 6,在[生成解决方案]“Client-Server.sln“解决方案时会发生的报错

    ET 自己的论坛 ET社区 中的帖子内容,百度好像不能直接找到结果。记录一下,便于搜索。 ET6 依赖.NET 6 ,IDE应当选择:VS 2022 或 Rider2021.3.x(对应支持.NET 6 的版本,可以从 Rider官方文章得到相关信息) VS 2019、Rider2021.1.x 均不支持.NET 6,因此都无法正常使用。 VS 2019 只会在编译

    2024年02月12日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包