我们的项目开始立项的时候,最常见的一个情况就是:几个人的小团队,一开始什么也不做,就开始写代码,验证逻辑,游戏就开始写起来了。而公司的一些所谓的领导层面一开始就把游戏定义为我们要做一个大作。这个事情本身就是一个笑话,因为没有任何的规划和设计,我们就妄图写出一个杰出的作品出来是不现实的。Unity 在好用,那么以这个心态去做游戏,一定会写不出来好的游戏来。— 刘钢《Unity 项目架构设计与开发管理》

以上这段话说得很清楚了,就是做一个项目的时候一定要做规划和设计,当然这是从整个项目的角度来看,但作为开发者,对我们来说就要从技术上进行规划和设计,而技术上的规划和设计其实就是要做架构。

架构要做什么?

在项目的初期,我们直接把架构理解为准备即可。我们仔细回忆一下在一个项目的准备阶段,我们都会做什么?

笔者一般是先分析需求,需求分析清楚了,就会对需求进行模块拆分,拆分之后就会去逐个验证技术难点,这时候会选择一些插件等等。等验证完毕就算是准备完毕了。

当然这一系列操作是笔者主动意识下完成的,但是其实还有很多习惯性的操作,比如用 QFramework、用公司的代码规范。

这就是笔者的准备阶段做的事情了。当然项目不是笔者一个人做的,而是有多个人做,而笔者的模块拆分阶段就已经可以把项目的工作量进行拆分了,而团队成员都是按照模块进行分工的。

这就是笔者一般做一个项目的时候做的准备,也就是架构,也就是规划和设计。很普通的事情,可能大家都在做。

但是仔细分析每一个操作,它背后都有很多故事和原因的。

比如一开始分析需求,这个习惯,都是被迫养成的,因为如果一开始不清楚需求就开工,那么就会导致对项目开发的走向判断错误,走向判断错误,那么当项目扩张的时候就会手足无措,体验非常差,而需求不清楚的话,在做项目的时候就会感到有力使不出,很难受的。作为一个开发者,虽然本职工作不是做产品或策划,但是把业务需求理解清楚,会对项目的理解会更加深刻,而如果知道了每个业务需求背后的原因,自己做项目的心态都会变得不一样。但是主动去理解需求是很多开发者不屑于去做的。不过我们可以好好算一笔账,假如在非常清楚需求的前提下,去完成这些需求要花三周的时间,但是在对需求模棱两可的前提下,去完成这些需求可能要花四周的时间。多出一周的原因,是因为需求模糊所造成的多余的工作量。而把需求理解清楚,很简单,一张纸一支笔花两个小时,就清楚了。

当然以上这些情况是适用于开发流程比较成熟的公司,比如策划提前两个月就把需求明确好了,美术提前一个月就把美术资源搞好了,而开发者到手的资源和需求全部都是完整的不需要排查的。

但是市面上大部分公司做不到以上的流程,真实情况下,都是美术开发策划同时开工的,策划都没想清楚就给了需求,给的需求往往都是非常模糊的,美术给的资源都要排查一次,这样就导致开发者会多出很多工作量。

但是在这种情况下,更是要理解清楚需求。策划自己都不清楚的需求,开发者要理解清楚,没错。开发者要想理解清楚需求,就要帮助策划理清思路,也就是策划要和开发多沟通,要理解策划在做游戏设计的时候在考虑什么事情。

当然以上单对很多人来说都很难,因为太在乎面子,太在乎尊严,瞧不起策划等等。一个项目好好做也是做,不好好做也是做,为什么不好好做呢?同样都是花自己的时间,如果不好好做那岂不是浪费了这段时间?

而一个开发者,最好是在最初就要有一颗积极的心态,什么叫积极的心态,就是为了做好项目,可以不在乎尊严,不在乎面子,而是一心想做好它,为了项目可以在争执的时候选择妥协,因为决定一个开发者价值的是项目,而不是尊严和面子。比如,到另一家公司去求职,你不能说这个项目是因为策划 SB 才做成这样的,而要说这个项目是我做的。

好了,说得有点远了。总之,笔者只是想说,理解业务,分析需求是架构的第一件要做的事情。而做好项目是架构的最终目的。

OK,其实还有一种情况没有讲完,这种情况是大多数开发者遇到的,就是项目已经开始了,但是需求还是很模糊,这时候,对开发者的要求会比较高,这时候大家只要记住一点就好,要容忍当前项目的不完美,记住这一点,项目的配置就算是最低,在最艰难的环境下都有机会绝处逢生。但是如果容忍不了当前的不完美,比如策划需求不清楚,老子就不干了,这样项目,那最终只会造成项目的 Delay,对自己对公司都不是啥好事。我们要做的就是,策划需求不清楚,OK,找它聊去,总归能聊明白的,聊完策划也明白,自己也明白。如果还是不能完全明白,也没关系,最起码对需求的理解程度有所改善,这样也是好的。

今天说了很多,结论就是,需求分析是最重要的一环,分析清楚了,更容易评估出工作量,更容易掌握对项目的走向,从而设计出面向未来的项目结构,总之,不要天天呆在电脑前写代码,多花点时间去思考产品可以事半功倍。

从 EmptyGO 到 Manager Of Managers

以下为 刘钢老师的《Unity 项目架构设计与开发管理》部分文字稿。

我们今天探讨一个话题。Unity 的架构有很多方法,所谓的流派,如下所示:

  1. EmptyGO:
  2. Simple GameManager
  3. Manager Of Managers

    4. MVCS/MVVM
  4. ECS (Entity Component Based System)

Empty GO



那我们一起来沿着一个思路走下去,看看怎么样的找到一个架构设计的最优方法。当我们谈到 Unity 的项目设计,可能一开始的时候,我们会写一堆 GameObject,比方说场景里有一些主角、怪物或者一些静态物体等等,我们习惯会去写一些脚本来控制这些 GameObject。而剩下的就是和这些 GameObject 没有明显关系的,一些 UI、Manager、内存池这些东西。我们习惯上,会创建一个 Empty 的 GameObject,然后把控制 UI、Manager、内存池这些东西的脚本往这个 GameObject 上一挂,那么我们的项目就算是有架构的东西了,非常值得鼓励,这就算是一个架构的雏形了。那么在接下来我们访问数据的时候,通常需要 GameObject.Find 或 Object.FindObjectOfType 这样的 API,那么这个东西呢,速度慢慢不慢我们先不说。一旦说,他们之间的一些引用关系有一些变化的时候,我们就要一个个 Search Find 地查找代码。那么做着做着很快就会发现,这不是一个很好的方法。一旦你的项目 规模,慢慢地膨胀的时候,你就会发现,我单单的用一个 Empty 的 GameOject 来涵盖所有无关的控制逻辑的时候,它不能满足你的需求,尤其是一些 UI 搅在一起的时候,就会造成更大的混乱。

而假如,我们使用 MonoBehaviourSimplify 就不会产生这个问题了。

不过我们接着文字稿继续。

Simple GameManager



由以上这个问题,我们想到,是不是可以对这个架构进行改变?那么很多人都知道,我们是不是可以把这个 Empty GO 直接改成一个 Singleton,那么恭喜大家,大家已经开始上路了。那么这是一个最简单的架构方法,事实上也是最常用最有意义的一种。思想非常非常地简单,但是,他的确可以起到一个很重要的作用。那么,我们把刚才提到的这个 Empty GO 变成一个 Singleton,这个时候我们说它有一个明显的好处,当你所有其他的 GameObject 想要访问这样一些公共逻辑的时候,我只要拿到 Instance 去调用他的方法,从你的游戏的任何一个位置,都可以访问到这样的一些逻辑,包括一些 UI 的设计,包括一些模块的访问,我们都变得容易了起来。

到这里呢,与笔者当初接触 Unity 时所使用的设计工具模式是一致的,都是先使用单例。

我们在接着往下。

Manager Of Managers



事实上一款游戏里面,和 GameObject 没有直接关系的逻辑控制是非常非常复杂的,尤其有好多好多的内容,如果说我们把所有这些内容全部塞到这样一个 Singleton GameObject 上去,你很快就会发现,好像是说我们有这样一个集中的地方控制很多东西,但是马上也会发生混乱,也就是说自己也搞不清楚这样一个庞大的文件里面到底有什么东西,那我们说,有着这样一个思想的话,接下去我们是不是可以写多个 Managers,那么这些 Managers 就会有明显的分工。

在上图中,上边可以有一个所谓的 MainManager,那么它下面会有所谓的 EventManager、AudioManager、GUIManager、PoolManager、LevelManager、GameManager、SaveManager、MenuManager。所有的这些东西大家都可以将它做成是一个 Singleton,那么在它们之间互相联系的时候,我们主要拿到每一个 Singleton 的 Instance,那么接下来就能方便地在模块与模块之间进行相互的访问。那么这个基本上成为了我们以后可以做游戏的时候一个最主流最基本的方法。那么对于一些所谓的中型以上的项目的游戏架构设计,这就是一个非常实用的方法。我不敢说它是最好的,但是它应该是一个非常非常实用的方法。

OK,终于写到这里了,我们回顾一下之前我们所学的知识,我们使用过对象池、还有我们的 MsgDispatcher。对应上边的 PoolManager、EventManager,而通过阅读以上的材料我们知道,Manager Of Managers 是一个非常实用的架构。那么我们可以不可以在我们的库基础上,一一实现上图中的每一个 Manager 呢?当然是可以的,而这其实是一个非常不错的目标。可以让我们的库称为一个真正意义上的框架,因为我们的库提供了 Manager Of Managers 的架构。

那么我们从下一篇开始逐个去分析这些模块。并再第二次整理结束之后就一一实现它们。

那么我们的库,接下来就不叫它库了,而是叫它框架。

今天的内容就这些,我们收获了一个不错的目标,库的方向也越来越清晰了。

转载请注明地址:凉鞋的笔记:liangxiegame.com

更多内容

Unity 游戏框架搭建 2019 (五十六/五十七) 需求分析-架构中最重要的一环&从 EmptyGO 到 Manager Of Managers的更多相关文章

  1. Unity 游戏框架搭建 2019 (二十六) 第一轮整理完结

    昨天呢我们把第八个示例整理完了.整理之后学习了类的第一作用:方法的集合,还有 Obselete 这个 API.并且在进行整理的时候贯彻了我们新的约定和规则:先确保功能有效,再去做变更和删除. 今天我们 ...

  2. Unity 游戏框架搭建 2019 (三十六~三十八) partial与public

    在上一篇,我们把菜单的顺序从头到尾整理了一遍.在整理菜单顺序的过程中,记录了一个要做的事情. 要做的事情: (完成) 备份:导出文件,并取一个合理的名字. 整理完菜单顺序后,学习新的知识,解决随着示例 ...

  3. Unity 游戏框架搭建 2019 (四十六) 简易消息机制 & 集成到 MonoBehaviourSimplify 里

    在上一篇,我们接触了单例,使用单例解决了我们脚本之间访问的问题. 脚本之间访问其实有更好的方式. 我们先分下脚本访问脚本的几种形式. 第一种,A GameObject 是 B GameObject 的 ...

  4. # Unity 游戏框架搭建 2019 (三十四、三十五) 9 ~ 10 示例整理

    第九个示例 目前代码如下: using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif namespace QFramework { p ...

  5. Unity 游戏框架搭建 2019 (二十五) 类的第一个作用 与 Obselete 属性

    在上一篇我们整理到了第七个示例,我们今天再接着往下整理.我们来看第八个示例: #if UNITY_EDITOR using UnityEditor; #endif using UnityEngine; ...

  6. Unity 游戏框架搭建 2019 (十三~十五) 接下来要学什么?& 第九个示例

    在之前的两篇中,我们使用 public 静态方法对之前的内容进行了一个抽取,有了 public 静态方法这个工具,我们的学习行为也发生了一点变化. 在没使用 public 关键字之前呢,每一个示例仅仅 ...

  7. Unity 游戏框架搭建 2019 (四十四、四十五) 关于知识库的小结&独立的方法和独立的类

    在上一篇,我们完成了一个定时功能,并且接触了 Action 和委托.lambda 表达式这些概念. 到目前为止,我们的库作为知识收录这个功能来说,已经非常好用了,由于使用了 partial 关键字,所 ...

  8. Unity 游戏框架搭建 2019 (九~十二) 第一章小结&第二章简介&第八个示例

    第一章小结 为了强化教程的重点,会在合适的时候进行总结与快速复习. 第二章 简介 在第一章我们做了知识库的准备,从而让我们更高效地收集示例. 在第二章,我们就用准备好的导出工具试着收集几个示例,这些示 ...

  9. Unity 游戏框架搭建 2019 (三十二、三十三) 类的命名 & 代码文件命名

    昨天我们完成了第八个示例的第二个 MenuItem 菜单顺序的调整. 我们今天再往下接着调整. 我们来看下接下来的 MenuItem 代码如下: [MenuItem("QFramework/ ...

随机推荐

  1. 一篇文章彻底理解Redis持久化:RDB和AOF

    为什么需要持久化? Redis对数据的操作都是基于内存的,当遇到了进程退出.服务器宕机等意外情况,如果没有持久化机制,那么Redis中的数据将会丢失无法恢复.有了持久化机制,Redis在下次重启时可以 ...

  2. java ->会话技术Cookie&Session

    会话技术Cookie&Session 会话技术简介 存储客户端的状态 由一个问题引出今天的内容,例如网站的购物系统,用户将购买的商品信息存储到哪里?因为Http协议是无状态的,也就是说每个客户 ...

  3. TreeSet的两种实现方法:Comparable和Comparator(Java比较器)

    Comparable与Comparator实际上是TreeSet集合的两种实现方式,用来实现对象的排序.下边介绍一下两种比较器的使用方法和区别. Comparable称为元素的自然顺序,或者叫做默认顺 ...

  4. spark机器学习从0到1机器学习工作流 (十一)

        一.概念 一个典型的机器学习过程从数据收集开始,要经历多个步骤,才能得到需要的输出.这非常类似于流水线式工作,即通常会包含源数据ETL(抽取.转化.加载),数据预处理,指标提取,模型训练与交叉 ...

  5. Enjoy the pain about Moloch

    这echo出来的啥子嘛?意思是小姐姐有自虐倾向?可若是moloch有汉化包或翻译文件,小姐姐至于这么“享受”install的过程吗? 过程都走过了,那就记录一下吧:1.找个Ubuntu镜像,阿里云镜像 ...

  6. mybatis随记

    JDBC问题:1.数据库配置信息硬编码 2.频繁创建,释放数据库连接 3.sql,设置参数,获取结果集硬编码,不通用   解决方案:1.配置文件 2.采用连接池 3.使用反射和内省   自定义持久层框 ...

  7. 3.4 Go字符型

    1. Go字符型 Golang 中没有专门的字符类型,如果要存储单个字符(字母),一般使用 byte 来保存. 普通字符串就是一串固定长度的字符连接起来的字符序列. Go 的字符串是由单个字节连接起来 ...

  8. dockerfile文档的相关参数

    以上是用dockerfile来构建的nginx镜像示例. 一.构建stress压力测试软件镜像 ##(1) 以下是Dockerfile内容(ENTRYPOINT是运行的环境): FROM centos ...

  9. day07:集合的使用0220

    list_1=set([4,5,6,7])list_2=set([4,8,9])list_3=set([4,5])list_4=set([6,7])a = (2,3)b = (2) #list_3是l ...

  10. postman发送请求携带Cookie

    相关步骤: 1.下载 Postman-Interceptor_v0.2.24.zip插件 2.解压下载好的插件,将其拖到应用配置中 3.复制Postman-Interceptor_v中的id地址 4. ...