基于 bearcat 的 cocos2d-js 游戏开发

概述

https://github.com/cocos2d/cocos2d-js 是一个开源的可用于web、native环境的游戏引擎,它是HTML5版本的 https://github.com/cocos2d/cocos2d-x。 cocos2d-js 包含两部分,一部分是用于web game的https://github.com/cocos2d/cocos2d-html5,另一部分则是用于native game的 cocos2d-x javaScript binding (JSB)。cocos2d-js 提供了 cocos2d-html5 和 cocos2d-x jsb 兼容的 API,使得用cocos2d-js编写的game可以无缝、不需要任何修改的就可以跑在基于cocos2d-x jsb的native环境里。
基于javaScript技术栈,在开发效率上有不少的优势
众所周知,web开发是相当高效的,开发过程无需编译、打包,直接刷新下浏览器即可,而且现在的浏览器都支持强大的开发工具,比如https://developer.chrome.com/devtools,包含了比如单步调试、网络数据访问、动态修改、内存/CPU性能分析、交互式控制台。
cocos2d-js 正是基于这一点,通过上层提供统一兼容API,快速的迭代,无缝的跨平台部署,进行游戏产出。
不过,在追求开发效率的道路上还不能仅仅这样就可以满足了,由于是基于javaScript栈开发,就需要考虑比如:
怎么进行依赖管理?如何使用第三方库?怎么做单元测试?代码如何进行复用?
接下来会针对这些问题,提出探讨,并给出相应的解决方案,最后会提供一个 cocos2d-js 的 example 以供参考

cocos2d-js 开发存在的问题探讨

依赖管理
javaScript 依赖管理是一个老生长谈的话题,因为javaScript语言本身到目前为止还没推出统一的模块、依赖管理的机制(es6 module还需要好久),cocos2d-js 在这方面使用的是:
依赖管理挂载在 global 对象下面脚本加载用 project.json 里的 jsList进行手动配置
基于全局的依赖管理作为引擎这样子使用问题还不大,因为我们最终使用cocos2d-js的地方都从cc对象获取即可,但是如果是你自己的应用层代码呢?
很明显,自己在做应用(游戏)开发时,要尽量避免使用全局变量,使用全局变量则必须小心,要考虑所有使用到的地方,否则一步留神就改出了问题,同时使用全局变量,对于一个文件依赖全局变量很难一眼看出这个文件原来依赖了某个全局变量,这样子尤其是在项目的后期带来了不少的麻烦,更不利于多人协作的项目
脚本加载需要手动配置,也是存在问题的。如果文件之间相互有加载顺序的依赖关系呢?(比如a.js依赖于b.js那么b.js就需要先加载完才行)这样一来就必须小心的写好jsList里面的顺序,否则就加载不成功了
因此,一个完善的依赖管理机制还是需要的。解决这个问题的关键是要把脚本的加载过程与脚本之间的依赖处理过程分开。
目前也有不少解决方案,AMD、CommonJS、Dependency Injection,关于这三种方式的比较与讨论可以参考另外一篇博文 http://bearcatjs.org/博客/index.html
可以看到基于 Dependency Injection 模式进行管理,可以极大程度的松散耦合,前后端代码进行复用,并且可以直接使用基于CommonJS的模块(npm module)。目前,bearcat 已经对 cocos2d-x jsb 环境进行了支持, 意味着我们可以编写同一套代码逻辑,然后跑在浏览器和jsb环境中,当然也可以在node.js中进行复用。而 AMD(只适用于浏览器)、CommonJS(依赖于文件I/O,浏览器环境受到限制) 都不能很好的适用于所有的环境,也包括cocos2d-js的jsb环境

第三方库的使用
第三方库其实也是一种依赖,目前最大的javaScript module生态圈是npm,我们可以使用 http://browserify.org/ 直接使用 npm 里面现有的 module,而非拷贝代码,然后手动添加,如果要升级第三方库呢?再拷贝,再添加。明显不太优雅。使用 browserify 的时候,配置个 package.json,然后添加依赖,build一下即可,由于依赖并不是频繁更改的,因此这个browerify的build的过程也是可以接受的

单元测试
使用全局global变量的情况下是很难做单元测试的,要做单元测试首先引用的全局变量要是一个拷贝,这样子可以防止由于在这里的单元测试修改了全局变量,而造成在另外的单元测试里面失败。
比如:
varfs =require(‘fs’);module.exports =function(path,cb){fs.readFile(path,‘utf-8’,function(err,content){cb(null,JSON.parse(content));})}这里有几个依赖?怎么做单元测试?
(依赖了 fs 和全局的 JSON)
Dependency Injection则没有这个问题,因为依赖是传入的,并不是自己获取的,传入的这个依赖可以很方便的进行mock进行单元测试。
换成依赖注入则一目了然
module.exports =function(fs,JSON){returnfunction(path,cb){fs.readFile(path,‘utf-8’,function(err,content){cb(null,JSON.parse(content));})}}对于javaScript,我们可以使用 https://github.com/mochajs/mocha 作为测试驱动框架,使用 https://github.com/tj/should.js 作为断言库

代码复用
由于我们基于javaScript技术栈,代码共享肯定能带来不少好处,游戏开发中不少的逻辑是可以直接复用的,比如model定义、数据的校验、寻路逻辑等等,这里的代码复用不是指的代码拷贝,真正的复用是同一个文件直接在客户端和服务端引用

下面部分由于论坛编辑器有问题,请转到原文继续阅读 http://bearcatjs.org/%E5%8D%9A%E5%AE%A2/bearcat-cocos2djs.html

单元测试确实头疼。。