Unity游戏架构:模块间通信原理及设计思路

本文参与“Unity游戏架构”征文活动

转载自“ 游戏扶持by腾讯游戏学院”


先谈一谈个人对游戏框架的一点理解,顾名思义,框架是一个项目的骨架,如同大树的主干,搭建框架,在此基础上再加入各个功能模块,构成有一个完整的项目。如同一棵树有一个健壮的主干,再从主干上生长出一个一个的分支,最终长成一颗枝繁叶茂的大树。此外,框架会设定好模块的基本格式,更加有利于功能的模块化;框架还负责各个模块之间的交互,每个模块作为一个独立的个体,内部是独立运行的,如果模块间需要进行一些交互,则需要通过框架来实现,避免模块间直接通信,最终模块关系错综复杂,难以维护。

一、简单实现方式

模块间的数据交互、信息传递是框架中比较重要的一部分,最近根据做过的几个项目和一些资料,编写了一套简单的模块间信息传递机制,在此之前也发过几篇关于模块封装的博文,组装到一起,应该也是可以用了。

关于消息机制(消息/广播/通知···有多个叫法,不过实现的功能都是类似的),大概原理是:

1. 消息:由唯一消息ID、消息体组成(有的写法也会将消息ID分离出消息体,不包含在消息体内,这样方便消息转发都多个不同模块,但不便于管理)。消息ID,用int值表示,根据需求划分一定数量的ID给每个模块,模块内部单独管理;消息体:数据信息的载体,一般是一个子类,这样方便不同模块自定义数据格式。

要注意一点,跨模块消息,A模块需要B模块的数据,就需要注册B模块的消息,这样B在发送消息之后,只要注册过这条消息的模块,都会接收到消息,这也要求模块内定义ID后,不能随意变动ID,建议采用枚举表示,使用时将枚举转为Int。

2. 建立消息中心,保存所有的消息及对应接收回调函数,各模块通过管理者将消息注册到消息中心,有对外的发消息接口,供各模块调用,当然同样要有注销接口。在收到消息之后执行对应的回调函数,将参数传递到注册过消息的多个具体模块,模块内部自行处理。

3. 回调:各个模块管理者,在脚本运行开始,注册所需要的消息,在脚本待销毁的时候注销,提供一个消息接收回调,消息中心会将消息下发到回调,然后内部处理消息。

4. 关于消息中心保存记录消息,我用的字典Dictionary保存对应的ID和回调,利用委托的一个优点就是委托的“+=”和“-=”,比如有多个模块注册了同一个消息,可以将callback+=newCallback,这样来把所有的回调记录下来,在注销时减掉。

但委托减法具有不可预测的结果,虽然改成Event事件可以避免程序报错,但结果与委托一样也会有这种问题,为了避免出现问题,在使用减法时,每次只减掉一个元素(即 a-= b,不要a-=(b+c)  ),就不会发生意外了,可以忽略代码里的警告了。

Demo代码如下,写的比较简单,实际项目需要再完善。



二、再封装设计

以上只是一种比较常见的消息机制,在此基础上还可以进行改进、封装,因为涉及到之前的项目,这里不粘代码了,简单说一下设计思路吧 。

1. 消息分类:这一点与上面Demo一样,按模块对消息进行分类。

2. 消息中心:每个模块的管理者作为一个消息中心,负责本模块消息的 注册、注销、处理。总消息中心,不处理具体消息,只负责不同模块间的消息流转。

要注册一条消息,模块先判断是否是本模块消息,是的话直接注册到本模块,若不是,则转发到上级的消息中心,消息中心再将消息识别下发到对应的模块,对应模块进行注册。

原本所有的消息都是在消息中心进行处理,现在在模块内部处理,消息中心只负责将消息下发到对应的模块即可。

比如说北京有一个快递中心,一天,在朝阳区的A要寄快递给海淀区的B,A找到朝阳区的快递员上门取件,快递员取件后将快递送到快递中心,再由快递中心识别快递物品,委派海淀区的快递员将快递配送给B。但第二天,朝阳区的A想要寄快递给同在朝阳区的C,同样朝阳区的快递员会上门取件,然后将快递送到快递中心,经识别后将快递委派给朝阳区的快递员,再配送给C。这样就显得比较繁琐了,快递中心的负荷也会非常大。

快递中心感觉这样好心累,要进行改革,于是增大了快递员的权利,可以直接处理自己负责地区的快递,无需再经过快递中心。这样A在寄快递给C的时候,朝阳区的快递员从A取件之后,发现这是朝阳地区内的快递,是寄给C的,就可以直接配送给C,省时又省力。如果A再给B寄快递,朝阳区的快递员取件之后,识别快递是其他地区的,就直接将快递送到快递中心,快递中心收到之后,只需识别是海淀区的,无需关注收件人是谁,再将快递流转到海淀区的快递员,由该快递员配送到C手中。这样来,整个快递流程就完美了。

3. 记录消息及其回调:

网上搜到的大都是用委托或事件来记录消息的,前面也提到过,利用“+=”“-=”计算可以记录一条消息和多个回调。

也想过用每个消息用一个List来记录所有的回调,但明显这样是不可取的。

这里介绍另一种记录方式:

记录的不是具体某个回调函数,而是采用链表的方式记录回调函数所在的类。

3.1 写一个父类或接口,定义一个Callback函数,所有的模块管理者,都重写或实现该函数,用作消息的回调。

3.2 定义一个消息节点类(包含两个属性,本节点的回调脚本,下一个节点Next),注册消息的第一个回调类后,其Next指向第二个回调类,依次类推,记录一个消息的所有回调类。

3.3 只需记录消息ID和第一个节点,获取第一个节点后依次获取节点的Next节点,知道Next节点为空,即遍历完所有节点。

3.4 在收到消息之后,遍历所有的节点,执行回调类的回调函数。



关于游戏架构,消息/通知机制只是其中的一部分,还有很多很多需要去学习去实践,希望以上的内容可以帮助到大家。




前端游戏巨制! CSS 居然可以做 3D 游戏了

↓推荐关注↓ …,?,?,?,????,?,?,?,?,?,?,?,?,?,?,?,?,?,?];然后我们去遍历这个数组, 得到地图.写一个方法去创建地图格子, 同时返回格子数组和节点数组.这里的block是在html中创建的一个预制体, 他是一个正方体.…

批评太多会形成“负脑”,养成“胜脑”才能让孩子学习更专注

国际脑神经外科和脑力开发权威林成之教授,著有不少儿童专注力相关书籍,他在其中一本书里提到很多不利于注意力发展的禁词,而上面几句“经典”话语,恰恰就在其中。看到这里可能很多家长还不理解:“孩子事情没做好,我们只是批评几句,为什么会对注意力有影响?”

教育产品的游戏化设计

的行为,玩具是儿童的天使。”如果能把“玩”代入教育是否能缓解教育带来的“复制性”?在高分纪录片《他乡的童年》中,我看到了不同国家的儿童教育差异:印度的教育注重“思辨”,在课堂上看到的大多是对知识/观点辩驳;芬兰的教育注重“真实的生活”,老师带着学生在森林里上课,素材都是大自然的材料,他们主张学习的目的是为了生活而非应试;日本的教育是为了“为他人着想”,以此为

某游戏服务运维架构进化史(上云方案)

网站架构百度百科:网站架构,一般认为是根据客户需求分析的结果,准确定位网站目标群体,设定网站整体架构,规划、设计网站栏目及其内容,制定网站开发流程及顺序,以最大限度地进行高效资源分配与管理的设计。

Unity 内存管理和profiler详解

Unity Memory Management Unity 的 Memory 构造 实际上Unity游戏使用的内存一共有三种:程序代码、托管堆(Managed Heap)以及本机堆(Native Heap)。 程序代码包括了所有的Unity引擎,使用的库,以及你所写的所有的游戏代码。在编译后,得到的运行文件将会被加载到设备中执行,并占用一定内存。 这部分内存实际上是没有办法去“管理”的,它们...