1201 cocos2d-x LUA 框架

1. 概述

1201 cocos2d-x lua 项目源码包含在 client/src 文件夹中。

下面三个文件夹是框架底层支持,它们排除在 git 仓库之外,使用 5. update 子命令 来获取和更新。

  • client/src/cocos
  • client/src/quick
  • client/src/zrong

src 目录的层级结构如下::

src
├── cocos
├── quick
├── zrong
├── conf
├── game
├── login
├── root
├── update
├── test
└── main.lua

2. 术语表

模块
模块是框架中的基本结构单位。它一般表现为一个文件夹。但并非所有的文件夹都是模块。对模块的详细定义参见: 4. 模块以及模块相关
app
框架的顶级单位,整个游戏由若干个 app 组成。继承 cc.mvc.AppBase。详见: 4.2 app
model
4.3 MVC 模式中的 M,负责存储数据的 M 后缀使用 Model,负责与 外界 通信的 M 后缀使用 Service。继承 cc.mvc.ModelBase。
view
4.3 MVC 模式中的 V,一定是一个可视对象。一般为一个 Scene 或者一个 Layer,也可能是一个 Node。这取决于是否需要对某个可视对象使用模式。
ctrl
4.3 MVC 模式中的 C,用于负责管理与协调 M 和 V。每个 V 应该配备一个 C。继承 cc.mvc.CtrlBase。
scene
每个 app 包含一个或多个 Scene。例如 game app 包含 main 和 fight 两个 Scene。
widget
常用或者可能复用的组件定义成 Widget,一般继承 Node,也有可能继承 Layer。一般情况下,每个 widget 就是一个 class
class
每个 class 包含在一个单独的 lua 文件中,使用 require 导入。
object
每个 object 就是一个包含功能的 table,包含在一个单独的 lua 文件中,使用 require 导入。
init.lua
每个 模块 都可以包含一个 init.lua,负责初始化以及 require|import 本模块中的 classobject
event.lua
每个 模块 都可以包含一个 event.lua,包含本模块中可用的事件常量。
root.runApp(name, force=false)
运行并切换到一个指定的 app,root 模块提供了这个方法。
rerun()
重新运行当前的 app,每个 app 都提供这个方法。
enterScene()
进入一个 Scene,每个 app 都提供这个方法。
全局事件
全局事件由 root app 发布,在 app 之间传递的事件叫做全局事件。
app 事件
app 事件由 app 发布,它仅在 app 内部传递。app 内部的模块通信应该使用 app 事件。
模块事件
模块事件由模块发布,它仅在模块内部传递。模块内部通信应该使用模块事件。

3. conf

conf 文件夹的作用是保存生成的配置文件。这些配置文件的来源如下:

  1. config git 仓库生成的配置文件;
  2. 使用 hhlb templ 根据模版生成的配置文件;
  3. 直接手写的配置文件。

4. 模块以及模块相关

4.1 什么是模块

模块 一般表现为一个文件夹。但并非所有的文件夹都是模块。

模块可以嵌套,一个模块可以包含若干子模块,子模块也可以拥有自己的子模块。

必须至少满足下列定义中的一项,才能称为模块:

  1. 包含一个 init.lua 和/或 一个 event.lua
  2. 包含 4.3 MVC 模式;

例如,每个 app 就是一个 模块root 、 :term`game` 都是模块。

game/scene 也是一个模块。它包含一个 MVC 模式的 V 和 C 。

root/utilroot/gf 就不是模块。它们只是方便功能分类的文件夹而已。

4.2 app

app 是顶级模块。每个 app 中的入口文件是与 app 文件夹同名的 lua 文件。

例如, root app 的入口文件是 Root.lua ,位于 root 模块的根目录中。

入口文件必须继承 cc.mvc.AppBase

4.2.1 app 列表

黄鹤楼项目中一共有 5 个 app ,它们分别是:

update
提供升级功能。它是项目载入的第一个 app 。
root
项目成功升级,或者不必升级,则进入 root app 。root app 会决定接下来进入哪个 app。
login
登录 app 。通常是 root app 决定进入的第一个 app。
game
登录成功之后进入的 app。项目的主要逻辑都在这里。
test
由于 框架结构的变化 ,创建一个新的测试项目并不方便。test app 则是专门用来创建测试项目的。每个测试项目在 test app 中采用 模块 的方式独立存在。

4.2.2 app 常用方法

app 提供了一些常用的方法,如下:

root.runApp(name, force=false)

这个方法只有 root app 提供,它不应该被直接调用,而是被下面几个封装过的方法调用:

  • root.runGame(force=false)
  • root.runTest(force=false)
  • root.runLogin(force=false)

这个方法会运行对应的 app,如果为 force 传递 true, 则会销毁现有的 app,并创建新的; 否则,它会调用 app 的 rerun() 方法。

rerun()

每个 app 都应该提供这个方法。它的具体作用取决于程序员如何定义。

enterScene()

使用这个方法进入某个 scene ,scene 的名称必须使用常量的方式定义在 app 中。

这个方法在 cc.mvc.AppBase 中定义。当前的 app 可以重写这个方法以实现自己的逻辑。

4.2.3 app 的事件

每个 app 都有发送事件的功能。app 发送的事件是 app 事件 ,root app 发送的事件是 全局事件 。每个 app 中的全局事件仅仅影响自己 app 本身。app 之间的事件必须通过 root app 来发送。

4.3 MVC

modelview 、 和 ctrl 是 MVC 模式的三要素。M 和 C 分别继承 cc.mvc.ModelBasecc.mvc.CtrlBase ;而 V 则可能继承 Scene 、 Layer 或者 Node 。

每个 V ,都必须有一个 C 配合它。和界面相关的代码写在 V 中,与逻辑相关的代码写在 C 中。V 并不知道有 C 的存在。它与 C 的通信依赖事件机制。V 应该尽量少地使用全局对象。

C 负责整合 M 和 V。从 M 中收到的数据,在 C 中转换成逻辑,然后去改变 V。

所有的 全局事件 或者 模块事件 的注册,都必须在 C 中进行注册。不要在 V 中接受或者注册 全局事件 和 非自己所属模块的 模块事件

MVC 模式并不一定非要是完整的。以下情况都有可能发生:

  • M 和 C 组成一个模块;
  • V 和 C 组成一个模块;
  • 多个 C 和 V 共用一个全局的 M。

例如,root/model 中的多个 M 就是被共享的。许多 V 和 C 都依赖它们.

4.4 init.lua

每个模块都可以有自己的 init.lua

root app 的 init.lua 完成下列工作:

  1. 定义全局函数和变量;
  2. 载入 quick lua 框架;
  3. 扩展框架功能;
  4. 建立 hhl 命名空间;
  5. 将全局 util 方法加入 hhl 命名空间。

game app 的 init.lua 仅仅是将 game app 中需要使用的类导入 hhl 命名空间::

hhl.SocketService                   = import(".socket.SocketService")
hhl.SocketCtrl                      = import(".socket.SocketCtrl")
hhl.MainScene                       = import(".main.scene.MainScene")
hhl.MainSceneCtrl                   = import(".main.scene.MainSceneCtrl")

game/main/scene 模块中也可以包含自己 init.lua ,这个文件中应该仅包含当前模块所用的初始化信息。

4.5 event.lua

init.lua 一样, event.lua 也是按照模块进行分工的。

例如 game app 下的 event.lua 包含 game app 中所有 app 级别的事件定义;而 game/main/scene 模块下的 event.lua 则应该仅仅包含当前模块所使用的事件定义。

对于仅仅是当前模块使用的事件(例如 V 和 C 之间的事件),可以直接作为 V 的常量定义。这样就可以不必提供 event.lua 。