写在开头
在上一篇文章中,简单介绍了框架的基本概念和展望了一下我所要实现的框架,并且对这周提出了目标,接下来,这篇文章将介绍我这周搭建框架的成果,可能写的不是特别好,但是总算迈出了第一步,还有很大的改进空间。
框架的基本结构
框架的结构是一个框架搭建的基本,好的结构能够大层度的降低模块的间的耦合和模块的扩展难度。我搭建框架所用的结构是从网上借鉴而来,通过manager of managers 建立各个模块,再使用消息收发机制进行模块间的通信,下面我将详细介绍框架的基本结构。
Manager of Managers
Manager of Managers就是将各个模块单独做一个Manager管理器,让所有关于这个模块的事件都让这个Manager去执行操作。比如将所有UI相关操作都由UIManager去执行,所有关于音频播放的操作都由AudioManager去执行。
模块通信
在不使用框架的时候,大多数人对各个Manager的调用可能就是简单的Manager.方法名()进行方法的调用,这样在短时间内可能看不出什么问题,但是到了后期,你想对程序进行修改的时候,他的弊病就会显现出来,比如你想要改变某一方法的名字的时候,你得找到它所有的引用,并且进行逐一修改,这种调用方式使得各个模块间的耦合特别高,让后期的修改变得异常繁琐,所以我将框架内各模块的通信封装,使其通过消息的收发进行通信。
这也是我从别的大牛那里学习来的方法,消息通信模拟的是网络运营商的消息收发机制。比如一台手机发送信息的过程,手机发送信息会先将消息发送到最近的基站,然后通过基站查询要发送的对象是否也在该基站范围内,如果在则将消息通过该基站发送给要发送的对象,如果不在则通过一些技术找到发送对象所在基站,然后将消息发送到那个基站,再由基站发送给要发送的对象。我们框架的模块通信就是要模仿这一过程。
我们把各个Manager当做基站,每个Manager管理的脚本当做手机,通过一个总控制器寻找脚本所在的Manager,这样就构成了一个完整的通信模块。
消息机制
上面我们已经了解了模块间如何通信,接下来就说一说通信时消息发送的具体机制。一般一个模块下都会有大量的脚本,那我们如何知道我们要把消息发送给谁,而消息的接收者又如何知道有人给自己发送了消息呢?
为了解决上述问题,我们给每个消息定义一个ID,发送者在发送消息时会携带ID,接收者会收录自己感兴趣的ID,这样当有自己感兴趣的ID的消息的时候,接收者就会做出响应。这里可能和上述的手机通信有所不同,在这里的发送者并不在乎所发送的信息有没有人接收,他只是向上传递这样一个信息,而Manager负责向所有感兴趣的接受者发送这个信息,并且接收者可以同时对多个ID感兴趣。接收者会将自己感兴趣的ID注册进Manager,这样Manager就能判断自己该把相应得到消息发送给谁。
完整模块
在完成了上述讲解之后,我们来进行具体实现的讨论。
首先Manager里会对外提供注册,解除注册,发送消息等的方法,在这里我将这些方法单独拿出来做了一个类EventController,所有与消息有关的操作,我都把他们放在这个类里,而Manager会持有这样一个类的对象,帮其进行相关操作。
对于消息的注册,可能会有多个脚本对同一id感兴趣,Manager里可能会有多个id注册,所以在这里采用了字典加链表的存储方式,id为字典的键,链表为值,一个id有多个脚本注册时,对链表进行append。
对于事件的接收者,必须实现一个IEventHandle接口,实现接口的ProcessEvent方法,完成对事件的处理操作。
代码实现
Manager的实现(单例模板)
一个游戏必然由很多Manager组成,每个Manager都由一个单例组成,而单例的脚本大多代码都是重复的,如果每个Manager都去重复的写这些代码,不仅会影响美观,还会有时间上的浪费,所以就有了接下来的方法实现一个单例的模板。
这里不对代码进行详细的解释,有兴趣的可以参考这篇文章《单例的模板与最佳实践》
EventController
EventNode
IEventHandle
结尾
这一周其实还写了很多代码,因为精力有限,后面的一些代码没有去说,可能现在有一些代码和后面关联,没有解释的很清楚,这一周暂时只写这么多了,代码已上传GitHub。项目地址