五星麻将0客户端登录界面

  • 前言
  • 准备工作
  • 配置报错
  • 热更新模式
    • 热更新程序集HotfixAssembly
    • 热更新启动GotoHotfix
    • 登录Login
      • 登录通道LoginAisle
      • 登录界面LoginPanel
    • 作者的话

前言

HexMap无限地图已经悄无声息的完成了,之所以悄无声息的完成,是因为弃用了ECS框架,弃用的原因在于不够成熟,而我要开发的游戏需要成熟的解决方案。既然不成熟,那么当初为啥要入坑呢?岂不是浪费了太多时间,在Unite 哥本哈根2019的大会上,官方演示了ECS的多人在线游戏的案例,这让ECS或DOTS着实让人期待,这也是明知不成熟,还是要入坑的原因:一项新技术的吸引力对于一个好奇心强的程序猿来说,几乎是不可抗拒的,所以说优化是程序猿的致命毒药,而新技术从某种层面上讲,就是优化。
试问:一个武林高手在拿到绝世武功秘籍的时候,如何能够放手?谁不想炼就绝世神功?
我们程序猿时时刻刻都在面临优化的诱惑,这种歇斯底里的渴望促使我们不断学习,不断进步。
我们在灵魂深处知道:我们离Matrix还有非常非常遥远的距离,程序猿想要成为新世界的神!
所以这是一场造神革命,我们可以看到未来,因此我们才知道差距有多大,因此才肝着努力。
这样写也许太夸张了,不过内心深处就是有这样夸张的渴望,实际上已经饥渴难耐到饮鸩止渴了。
不得已,个人技术水平太Low,不得不沿用原作者的OOP架构,貌似回到了原点。于是耐着性子把原作者的教程拜读了一遍,写得太好了,所以根本没有补充的地方。
站在巨人的肩膀上,无限地图顺利完成,我做的无非是导入了一些Polygon风格的资源,使地图看起来更漂亮一些。这些都不值得大书特书,有兴趣的朋友看看原教程都可以轻易完成。
无限地图完成后,终于又要开新坑了,我的独立游戏是末世生存游戏,我希望末世有着无限的挑战,因而做了无限地图。接下来我需要这款游戏可以像饥荒那样联网,可以使用多人模式,也可以单机模式。
因为我需要一个全面的解决方案,之前研究了太多框架GameFramework、Skynet、YouyouFramework、xluaFramework等等,研究的这些东西都是非常优秀的,但是好的不一定是适合的。每个框架在设计的时候,或多或少都有取舍,毕竟这是一个百家争鸣的时代,非常多杰出的作者开源了自己的杰作,他们都有自己的优势。
我最终选择了ET,它的优势作者熊猫国宝已经表述得非常明了,这些优势使我最终下定决心要使用ET,如果DOTS革新成熟了,也许会融入进来,在那之前我会安安心心地夯实ET开发之路。
在开始学习笔记之前,我已经学习了两天ET了,以下是我的学习路径:

  • ET作者手书
  • ET社区
  • ET学习笔记
  • 肉饼老师主讲ET教程
  • ET新手教程新版-初见主讲
  • ET背包系统源码

两天时间做了以上研究,即便是这样,我觉得离我的独立游戏还有距离。我需要研究一个更加完整的案例,于是我克隆了五星麻将,当然也可以选择斗地主案例,选择五星麻将的原因是我以前开发过一款麻将游戏,所以对麻将比较熟悉。那个时候一下班就被老板叫去机麻,为了熟悉麻将逻辑。后来中途又被调到老虎机项目,委以重任。扯远了,总之选择了五星麻将来作为自己的入门案例。

准备工作

其实上面例举的学习路径也算是准备工作了,毕竟五星麻将还是有一定难度的。
如果上面的案例大家都掌握了,那么就开始着手准备五星麻将案例吧:
0下载Unity编辑器(2018.4.5f1 or 更新的版本),if(已经下载了)continue;
1克隆:git clone https://github.com/wufanjoin/fivestar.git --recurse 或下载Zip压缩包
2如果下载的是压缩包,解压。将$GitProject\fivestar文件夹下的Unity添加到Unity Hub项目中;
3用Unity Hub打开项目:Unity,等待Unity进行编译工作;
4打开项目后,启动场景在Scenes目录下,打开Init场景。

配置报错

按照作者要求进行本地配置时报错了,操作参考运行指南,错误如下图所示:

点击去发现了MongoHelper类冲突了,如下图所示:

解决方法很简单,既然冲突了,改个名字就好了。利用VS的重命名快捷键对MongoHelper重命名为MongoHelpero。于是可以顺利加载配置文件了,如下图所示:

配置好了,顺利启动游戏,如下图所示:

热更新模式

如果阁下走过前言列出的学习路径的话,一些基础知识我就不详细讲解了,毕竟在下也是一知半解的状态。不过,接下来的热更新就是难点了,所以还是稍微解释一下下吧。
ET的热更新方案正如作者所说:

因为ios的限制,之前unity热更新一般使用lua,导致unity3d开发人员要写两种代码,麻烦的要死。之后幸好出了ILRuntime库,利用ILRuntime库,unity3d可以利用C#语言加载热更新dll进行热更新。ILRuntime一个缺陷就是开发时候不支持VS debug,这有点不爽。ET框架使用了一个预编译指令ILRuntime,可以无缝切换。平常开发的时候不使用ILRuntime,而是使用Assembly.Load加载热更新动态库,这样可以方便用VS单步调试。在发布的时候,定义预编译指令ILRuntime就可以无缝切换成使用ILRuntime加载热更新动态库。

是利用ILRuntime库来进行热更的,原理作者解释了,就是把需要热更的代码打成dll(Dynamic Link Library的英文缩写,意思是动态链接库),dll的方便之处在于动态加载,从而使代码得到更新,而不必重新安装整个程序,这就是所谓的热更新了。那么具体如何操作呢?
其实之前的教程已经解释过了,我就再演示一下吧,如下图所示:

开发的时候把需要热更新的代码放到Hotfix解决方案下面,就可以热更新了,当前添加宏之类的操作就不必我啰嗦了。实际上ET支持整个项目都热更新,为了省事,也为了备不时之需,我觉得完全可以把所有开发的代码都放在Hotfix下面,全部热更就好了。当然,如果确定是万年不变的代码,其实也没必要放进来,这样可以减少热更新的开销,热更新必然是有代价的,具体这里就不解释了(其实我也不甚明白Orz)。

热更新程序集HotfixAssembly

五星麻将作者提到过字段isNetworkBundle,使用该字段就可以控制是否使用网络资源了,如果你想使用就勾选true,这样的话需要部署一个文件服务器,这个肉饼老师的视频中演示了,我就不多说了。
我们这里不勾选,按照本地流程走,按照ET的流程,初始化需要添加一大堆需要用的组件,以备不时之需。这些属于基本操作了,因此也不做详细解释了,下面是热更新的入口:

             //加载热更项目Game.Hotfix.LoadHotfixAssembly();

通过这一个方法,我们就加载了热更新的代码了,流程如下:

     /// <summary>/// 加载热更新程序集/// </summary>public void LoadHotfixAssembly(){//0.加载打包的代码资源包,内含热更新代码程序集dll动态链接库,对应的路径:Assets\Res\CodeGame.Scene.GetComponent<ResourcesComponent>().LoadBundle($"code.unity3d");//1.从加载的AssetBundle资源中获取代码资源并转化成游戏对象GameObject code = (GameObject)Game.Scene.GetComponent<ResourcesComponent>().GetAsset("code.unity3d", "Code");//2.从游戏对象上获取对应的动态链接库和程序数据库资源转化成字节byte[] assBytes = code.Get<TextAsset>("Hotfix.dll").bytes;byte[] pdbBytes = code.Get<TextAsset>("Hotfix.pdb").bytes;#if ILRuntime//因为设置了ILRuntime的宏,所以会进入到这里,这意味着热更新模式运行游戏Log.Debug($"当前使用的是ILRuntime模式");//3.获取热更库的环境域,这个属于ILRuntime的知识了this.appDomain = new ILRuntime.Runtime.Enviorment.AppDomain();//4.把动态链接库库和PDB(Program Database File,程序数据库文件)加入内存this.dllStream = new MemoryStream(assBytes);this.pdbStream = new MemoryStream(pdbBytes);//5.通过内存加载上面的资源this.appDomain.LoadAssembly(this.dllStream, this.pdbStream, new Mono.Cecil.Pdb.PdbReaderProvider());//6.热更代码的启动方法,直接定位到ETHotfix.Init类下的启动方法this.start = new ILStaticMethod(this.appDomain, "ETHotfix.Init", "Start", 0);//7.热更类型通过反射this.hotfixTypes = this.appDomain.LoadedTypes.Values.Select(x => x.ReflectionType).ToList();
#elseLog.Debug($"当前使用的是Mono模式");this.assembly = Assembly.Load(assBytes, pdbBytes);Type hotfixInit = this.assembly.GetType("ETHotfix.Init");this.start = new MonoStaticMethod(hotfixInit, "Start");this.hotfixTypes = this.assembly.GetTypes().ToList();
#endif//8.秉承过河拆桥的原则,呸,优化内存的原则,卸载AssetBundle资源Game.Scene.GetComponent<ResourcesComponent>().UnloadBundle($"code.unity3d");}

这个流程是定死的,也不用去改动,照着用即可。

热更新启动GotoHotfix

上面为热更新的使用铺平了道路,只需一声令下即可开始运行热更新里面的代码,命令如下:

                //执行热更项目Game.Hotfix.GotoHotfix();

这行代码最终执行的是ETHotfix.Init.Start方法,只是过程比较委婉曲折而已,下面正式启动:

                // 注册热更层回调ETModel.Game.Hotfix.Update = () => { Update(); };ETModel.Game.Hotfix.LateUpdate = () => { LateUpdate(); };ETModel.Game.Hotfix.OnApplicationQuit = () => { OnApplicationQuit(); };//添加UI组件Game.Scene.AddComponent<UIComponent>();Game.Scene.AddComponent<OpcodeTypeComponent>();Game.Scene.AddComponent<MessageDispatcherComponent>();// 加载热更配置ETModel.Game.Scene.GetComponent<ResourcesComponent>().LoadBundle("config.unity3d");Game.Scene.AddComponent<ConfigComponent>();ETModel.Game.Scene.GetComponent<ResourcesComponent>().UnloadBundle("config.unity3d");//房间配置AnnouncementConfig cardFiveStarRoom = (AnnouncementConfig)Game.Scene.GetComponent<ConfigComponent>().Get(typeof(AnnouncementConfig), 1);Log.Debug($"config {JsonHelper.ToJson(cardFiveStarRoom)}");//直接添加Session组件Game.Scene.AddComponent<SessionComponent>();//GameGather新加的组件Game.Scene.AddComponent<VersionsShowComponent>();//版本号显示组件Game.Scene.AddComponent<KCPUseManage>();//KCP使用组件Game.Scene.AddComponent<UserComponent>();//用户信息管理组件Game.Scene.AddComponent<ToyGameComponent>();//游戏场景 管理组件Game.Scene.AddComponent<MusicSoundComponent>();//音乐 音效组件Game.Scene.AddComponent<FrienCircleComponet>();//亲友圈组件Game.Scene.GetComponent<ToyGameComponent>().StartGame(ToyGameId.Login);GameObject.Find("Reporter").SetActive(ETModel.Init.IsAdministrator);//打印日志

这里打印的配置文件如下图所示:

由此我们就知道了配置文件的使用方式了,类名和配置都是AnnouncementConfig,所以就能在加载的资源中进行刷选。底层的实现大家可以自行阅读源码,这里我只需要知道如何使用即可。
当然,我选择与底层分离的原因主要是水平有限,不想消耗精力去研究底层,而我要开发的游戏仅仅关心如何实现高级的功能,而没有太多富余的时间去研究底层(富余的时间都去打牌了Orz)。
所以,原本要研究代码的时间用来打了三圈牌,输了120大洋(输的是从老爹那里借来的钱,借200,最终还80,想想自己真是坑爹!),于是干脆跳过一些底层实现。

登录Login

Anyway,热更新跑起来了,上面的代码StartGame(ToyGameId.Login);直接跳转到登录界面。
基于ET的事件机制,其实在ComponentFactory.Create<ToyGameComponent>();的时候就触发了下面的事件,当然组件工厂(ComponentFactory)的Create方法是由AddComponent方法间接触发的。

    [ObjectSystem]public class ToyGameComponentAwakeSystem : ETHotfix.AwakeSystem<ToyGameComponent>{public override void Awake(ToyGameComponent self){self.Awake();}}

所以AddComponent是触发上面事件的始作俑者,当然底层做了非常多的工作,详见肉饼老师的解说视频。我们这里只需知道会触发该事件,还是那句老话,水平有限,停留于使用层面。
该事件的使用方式其实作者写得非常清楚了,整个ET的运行都是基于这样的事件机制的,因而事件机制是必修课,基于事件机制我们可以做很多工作,就像这里的Awake方法:

        /// <summary>/// 由事件机制触发的唤醒方法,在每次添加组件的时候执行一次/// </summary>public void Awake(){mGameAisleBaseDic.Clear();List<Type> types = Game.EventSystem.GetTypes();foreach (Type type in types){object[] attrs = type.GetCustomAttributes(typeof(ToyGameAttribute), false);if (attrs.Length == 0){continue;}ToyGameAttribute toyGameAttribute= attrs[0] as ToyGameAttribute;ToyGameAisleBase toyGameAisleBase = Activator.CreateInstance(type) as ToyGameAisleBase;toyGameAisleBase.Awake(toyGameAttribute.Type);mGameAisleBaseDic.Add(toyGameAttribute.Type, toyGameAisleBase);}}

这里的Awake干了啥?其实我也是一知半解,只能靠着程序猿的本能猜测一下,大概是维护一个字典,这个字典的用途大概是根据游戏类型(ToyGameAttribute)来获取不同的通道(ToyGameAisleBase)。
ToyGameAisleBase负责对应游戏类型的进出,进进出出的地方就是通道了Orz,它有很多子类,后面会讲。
有了Awake所做的工作,我们可以过渡到Start方法了,也就是上面调用的StartGame(ToyGameId.Login);

        public void StartGame(long gameType,params object[] objs){if (mGameAisleBaseDic.ContainsKey(gameType)){if (CurrToyGame != ToyGameId.None){mGameAisleBaseDic[CurrToyGame].EndAndStartOtherGame();}mGameAisleBaseDic[gameType].StartGame(objs);}else{Log.Error("想要进入的游戏不存在:"+ gameType);}}

因为有Awake所做的工作,所以mGameAisleBaseDic字典里面才有对应的Key,否则就会报错。
这些Key实际上就是ToyGameId,这些是属于自定义的字段,应该是通过发射机制注册的,如果没有明白我在说什么,这里是入门指南传送门,走你。当然这纯属我的猜测,总之不必在意这些细节,我们只需知道字典里有什么,我们该如何使用,我的格言大概就是:站在巨人的肩膀上致敬巨人!

namespace ETHotfix
{public class ToyGameId{public const long None = 0;public const long Login = 1;public const long Lobby = 2;public const long Common = 1000;public const long JoyLandlords = 1001;public const long CardFiveStar =1002;public const long CardFiveStarVideo = 2002;}
}

字典里面其实就是上面这些Key了,我们可以在这里自定义自己想做的游戏类型,上面已经定义了登录、大厅等字段,我们也完全可以加上public const long CSDN = 3;这样的字段。
Anyway,我们现在已经推测出字典里面有什么了,如果大家怀疑我的推测,完全可以循环遍历打印出来了。我丝毫不怀疑自己的推理,所以就不打印了。
这里的public long CurrToyGame = ToyGameId.None;字段意思是当前的游戏模式,所以最终又调用了mGameAisleBaseDic[gameType].StartGame(objs);正式开始登录。

登录通道LoginAisle

负责登录的是登录通道(LoginAisle),所有的游戏通道都是继承ToyGameAisleBase,这样才能通过上面的字典统一调用。如果阁下不知道这是什么设计模式的话,即使在评论区留言我也不会告诉阁下的。

        public override void StartGame(params object[] objs){base.StartGame();Log.Debug("进入登陆界面");Game.Scene.GetComponent<KCPUseManage>().InitiativeDisconnect();Game.Scene.GetComponent<UIComponent>().Show(UIType.LoginPanel);}

于是,通过登录通道,我们终于进入了登录流程。

登录界面LoginPanel

在展示UI界面前,进行了KCP断开连接的操作,之所以这么做其实是为了干掉Session,我想这是为了应对多账号用户的注销操作。这也纯属个人推理,如果阁下不明白,我也不解释。
KCP是啥?阁下可以把它当作是TCP的兄弟了,都是CP嘛。那么TCP是啥?这里是入门指南传送门,走你!
送走了一波王莽(网盲,源于文盲、法盲、色盲,王莽就是不懂网络的莽夫!)
在开始展示登录界面之前,有必要先看看UIComponent都做了些什么工作:
首先触发的是事件系统:

    [ObjectSystem]public class UiComponentAwakeSystem : AwakeSystem<UIComponent>{public override void Awake(UIComponent self){self.Awake();}}[ObjectSystem]public class UiComponentLoadSystem : LoadSystem<UIComponent>{public override void Load(UIComponent self){self.Load();}}

通过ET的事件机制进而触发Awake:

        public void Awake(){this.Root = GameObject.Find("Global/UI/");this.Load();Ins = this;}

在Awake中设置了UI的根节点,然后进行加载以及单例模式(Unity必修课)。

        public void Load(){uiMvcVessel.Clear();List<Type> types = Game.EventSystem.GetTypes();foreach (Type type in types){object[] attrs = type.GetCustomAttributes(typeof(UIFactoryAttribute), true);if (attrs.Length == 0){attrs = type.GetCustomAttributes(typeof(UIComponentAttribute), true);if (attrs.Length == 0){continue;}}Type attrType = attrs[0].GetType();if (typeof(UIFactoryAttribute) == attrType){UIFactoryAttribute factoryAttribute = attrs[0] as UIFactoryAttribute;uiMvcVessel.AddUIMvcVessel(UIMvcVesselType.Factory, factoryAttribute.Type, type);}else if (typeof(UIComponentAttribute) == attrType){UIComponentAttribute componentAttribute = attrs[0] as UIComponentAttribute;uiMvcVessel.AddUIMvcVessel(UIMvcVesselType.Componet, componentAttribute.Type, type);}}}

这段代码大家眼熟吗?几乎同样的设计模式,啥?没看出来!

Ok,只能帮到这里了,因此我们同样可以通过UIType来自定义自己需要的UI字段。
原理是一样的,这里使用uiMvcVessel来统一管理UI,如果阁下不知道MVC,这里是入门指南传送门,走你!
恐怕新手都送走了,所以ET的门槛其实很高,所以才叫外星人嘛。
咱其实也吃不消,不然为啥要写学习笔记呢?一起学习,共同进步嘛。
Whatever,已经撑到这里了,我们还是继续吧。UIType中定义了所有用到的UI面板,这里就不复制代码了。
这里使用MVC模式来管理UI,把对应的UI类型加入UIMvcVessel中,便于后面的方法调用。

        public void Show(string type){UI ui;if (uis.TryGetValue(type, out ui)){UIView uiView = ui.GetComponent<UIView>();uiView.Show();}else{Create(type);}}

It’s Showtime!终于轮到展示UI界面了,那么LoginPanel一开始进入Show方法时,是没有创建的。如果已经创建了,就直接展示。我们还是从创建开始:

        public UI Create(string type){try{UI ui;IUIFactory uiFactory = uiMvcVessel.GetUIMvcVessel(UIMvcVesselType.Factory, type) as IUIFactory;if (uiFactory != null){ui = uiFactory.Create(this.GetParent<Scene>(), type, Root);}else{UIView uiCommpoentView = uiMvcVessel.GetUIMvcVessel(UIMvcVesselType.Componet, type) as UIView;ui = DefaultUIFactory.Create(this.GetParent<Scene>(), type, Root, uiCommpoentView);}UIView uiView = ui.GetComponent<UIView>();uiView.pViewState = ViewState.CreateIn;//状态改为正在创建中Type t = uiView.GetType();ui.GameObject.transform.SetParent(this.Root.Get<GameObject>(uiView.pCavasName).transform, false);uiView.OnCrete(ui.GameObject);uis.Add(type, ui);uiViews.Add(uiView);return ui;}catch (Exception e){throw new Exception($"{type} UI 错误: {e}");}}

这里使用的是工厂模式,而不是组件模式,两者有啥优劣呢?阁下已经知道在哪里寻找答案。
当然,我们也可以不知道工厂模式和组件模式的区别,这里走了一个创建流程,下面正式Showtime。

至此,这一篇流水账总算记完了,下一篇将完成登录流程,从客户端登录,进入游戏大厅!

作者的话

如果喜欢可以点赞支持一下,谢谢鼓励!如果有什么疑问可以给我留言,有错漏的地方请批评指证!
技术难题?加入开发者联盟:566189328(QQ付费群)提供有限技术探讨,以及,心灵鸡汤Orz!
当然,不需要技术探讨也欢迎加入进来,在这里劈柴、遛狗、聊天、撸猫!( ̄┰ ̄*)

ET学习笔记之五星麻将0相关推荐

  1. 数据库学习笔记第一弹——MySQL8.0和MySQL5.7的下载、安装与配置(图文详解步骤2022)

    数据库学习笔记第一弹--MySQL8.0和MySQL5.7的下载.安装与配置(图文详解步骤2022) 文章目录 数据库学习笔记第一弹--MySQL8.0和MySQL5.7的下载.安装与配置(图文详解步 ...

  2. C4D R26 渲染学习笔记 建模篇(0):建模常识

    往期文章 C4D R26 渲染学习笔记(1):C4D版本选择和初始UI框介绍 C4D R26 渲染学习笔记(2):渲染流程介绍 C4D R26 渲染学习笔记(3):物体基本操作+快捷键 C4D如何建模 ...

  3. android8 通知呼吸灯_android学习笔记----解决兼容8.0以上和8.0之前版本通知栏显示、振动、LED呼吸灯闪烁问题(真机验证)...

    Android 8.0系统的通知栏适配文章讲解(郭霖大神的): 然后开始试验了: 模拟器: 真机(华为荣耀V9,8.0系统),下拉横幅需要手动打开,除非是厂家白名单,比如QQ.微信 我在oppo手机6 ...

  4. STM32学习笔记整理之(0)——新建工程

    转载:原创文章:http://emouse.cnblogs.com 1.1.1 开发工具与开发环境 1. 软件版本 本节所使用Keil MDK 为目前的最新版V4.21,具体版本信息如图 5‑6所示. ...

  5. [读书笔记]C#学习笔记七: C#4.0中微小改动-可选参数,泛型的可变性

    前言 下面就开始总结C#4.0的一些变化了, 也是这本书中最后的一点内容了, 这一部分终于要更新完了. 同时感觉再来读第二遍也有不一样的收获. 今天很嗨的是武汉下雪了,明天周六,一切都是这么美好.哈哈 ...

  6. cocos2d python文档_【Cocos2D-X 学习笔记】Cocos2D-x 3.0+VS开发环境搭建[使用Python]

    上一节讲了如何用VS自带的项目管理器创建项目,该方法只适用于cocos2d-x 2.0版本,而cocos2d-x 3.0较之前版本在命名等方面有了较大更新,而cocos2d-x3.0不再支持用VS项目 ...

  7. C#学习笔记四: C#3.0自动属性匿名属性及扩展方法

    前言 这一章算是看这本书最大的收获了, Lambda表达式让人用着屡试不爽, C#3.0可谓颠覆了我们的代码编写风格. 因为Lambda所需篇幅挺大, 所以先总结C#3.0智能编译器给我们带来的诸多好 ...

  8. 学习笔记(1):activiti6.0从入门到精通-设置流程变量(概述)

    立即学习:https://edu.csdn.net/course/play/24213/272703?utm_source=blogtoedu lk

  9. Qt例子学习笔记 - Examples/Qt-6.2.0/charts/callout

    //QChart 类提供了两种在场景坐标和系列域(由轴范围定义)之间映射的方法. //QPointF QChart::mapToPosition(const QPointF &value, Q ...

最新文章

  1. git ,报403错误,完美解决方案
  2. modelandview为null的原因_如何在Java代码中去掉烦人的“!=null”
  3. 如何用C代码生成二维码
  4. [.NET开发] C#连接MySQL的两个简单代码示例
  5. (~解题报告~)L1-017 到底有多二 (15分)(16行代码AC)
  6. php 分页 url重写 分页问题,解决千古难题,wordpress分页URL问题,wordpress给分页加链接...
  7. 一个穷人是从什么时候开始有钱的?
  8. ASP.NET MVC: 构建不带 Web 窗体的 Web 应用程序(转载)
  9. 如何开启开源之旅(一)
  10. linux 配置远程日志服务器配置,配置远程日志服务器—实现日志的集中管理
  11. Caffe 议事(一):从零开始搭建 ResNet 之 残差网络结构介绍和数据准备
  12. 自己定义控件-DownSlidingDrawer
  13. linux夸分区建立软链接,Linux硬链接和软链接
  14. Go语言 channel 管道 阻塞 死锁 经典问题
  15. 史上最强三千六百道脑筋急转弯(5)
  16. OpenFOAM大涡模拟湍流模型之Smagorinsky模型代码详解
  17. sqlite3_英英词典
  18. win7计算机怎么重置,win7系统的电脑如何重置 win7重置电脑的方法
  19. linux下的open file是什么,linux修改open files数
  20. sprd9820 来电归属地

热门文章

  1. Ubuntu中创建应用快捷方式并固定到快速启动栏
  2. sap学习手册III
  3. 【ESP32调试-快速入门】
  4. Mac 版本 word 如何设置 '段落' 格式
  5. 巧用excel公式提取网址中的域名---超级好用
  6. 机器学习算法实践-树回归-转
  7. android版本怎么升级9.0,为什么安卓系统都升级到9.0了,而国内大部分都是Android7呢?...
  8. 服务器未响应 重新投递中,邮件无法收到
  9. 离散Fréchet(弗雷歇) 距离评价曲线相似度
  10. 浅谈传热学中温度分布曲线的凹凸分析