用JavaScript开发HTML5与C++游戏

这是个对cocos JS的简单经验谈,让大家明白引擎原理,以及使用JS开发过程中要注意的事项,但不会涉及太多基本编程知识以及基础安装等,在阅读本文前请先对Javascript与Cocos有基本了解。

Cocos JS项目组成

首先,你可能会问:为什么cocos JS能同时开发HTML5与C++游戏?
我们先看看cocos JS 3.x(3.3)项目目录构成:
先建立一个项目:
cocos new HelloCococJS -p com.163.cocosjs -l js --ios-bundleid com.163.cocosjs

用JavaScript开发HTML5与C++游戏_第1张图片
文件结构

大家看图上的标注:

  1. cocos2d-html5引擎:纯html5引擎,在浏览器上的图形处理全靠它了;
  2. js-bindings:为什么JS可以写原生游戏,关键就在这里;
  3. runtime-src:原生的runtime工程,基础的Class文件,Android到iOS甚至Win32的工程;
  4. tools:JSBinding工具

最让人好奇的是js-bindings,进入里面,里面有3个目录:

  1. bindings:绑定脚本,一个脱水层,用于把cocos JS耦合到到原生引擎,稍候会讲到绑定原理;
  2. cocos2d-x:cocos2d-x的C++引擎,就是那个原生引擎了;
  3. external:里面就只有SpiderMonkey JS引擎,Firefox就是用它了,相比V8引擎,在kraken time与sunspider time测试中略胜V8。
用JavaScript开发HTML5与C++游戏_第2张图片
上图:鲜红色为Firefox,分数越低越好

上图:鲜红色为Firefox,分数越低越好

看到这里,相信不少同学已经发出“哦~”一声,原来如此!
没错,cocos JS组件内包含了3个引擎1个工具:

  • 在HTML5时,运行的是cocos2d-html5引擎,采用canvas或WebGL渲染;
  • 在打包成原生时,SpiderMonkey做JS脚本运行解释器打包进去,同时编译cocos2d-x C++,前者通过JSB让JS调用后者的C++处理图形,原生除了JS外,已经与html5完全无关了,JS就是脚本语言,类似Lua。
用JavaScript开发HTML5与C++游戏_第3张图片

JSBinding原理

JSBinding项目最初由zynga实现,用于胶合JS与Objective C的cocos2d-iphone,项目Github: jsbindings

JavaScript Bindings for C / Objective-C (JSB) is the "glue" code (or wrapper code) that sits between native code (C or Objective-C) and JavaScript (JS) code. JSB allows calling native code from JS and vice-versa.

现在已经移植到这里来,用于把cocos2d-x生成对应的JS接口,方法大致为:

编写配置文件.ini,通过tools下的bindings-generator,把C++类生成对应的辅助C++脚本以及Javascript接口脚本。

配置文件.ini作用

JSB本身就是一个工具,在项目中不负责运行代码,只生成C++对应的JS,而配置文件就是生成的规则,例如JSBinding 上的描述:

// CCAnimation (from cocos2d-iphone v2.0)
+(id) animationWithAnimationFrames:(NSArray*)arrayOfAnimationFrames delayPerUnit:(float)delayPerUnit loops:(NSUInteger)loops;

默认生成以下JS:

// ugly
cc.CCAnimation.animationWithAnimationFrames_delayPerUnit_loops_( frames, delay, loops );

通过规则配置,

method_properties = CCAnimation # animationWithAnimationFrames:delayPerUnit:loops: = name:"create",

可以生成:

// more JS friendly
cc.Animation.create( frames, delay, loops );

JS调用C++细节

JS:

gnode = cc.Node.create();

JSB C++:

JSBool js_cocos2dx_CCNode_create(JSContext *cx, uint32_t argc, jsval *vp)
{
    if (argc == 0) {
        cocos2d::CCNode* ret = cocos2d::CCNode::create();
        jsval jsret;
        do {
        if (ret) {
            js_proxy_t *proxy = js_get_or_create_proxy(cx, ret);
            jsret = OBJECT_TO_JSVAL(proxy->obj);
        } else {
            jsret = JSVAL_NULL;
        }
    } while (0);
        JS_SET_RVAL(cx, vp, jsret);
        return JS_TRUE;
    }
    JS_ReportError(cx, "wrong number of arguments");
    return JS_FALSE;
}

到这里,相信大家明白其中原理了,更深入的可以看文件夹:tools/bindings-generator/test 里的例子。

好了,JSBinding原理就简单说到这里。

实践心得

明白了上面的原理,假如要用JS作用脚本写原生游戏,应该怎么做呢?

在实践过程中,JS中大部分在 cc 命名空间下的接口都有对应的C++ API,小部分html5引擎特有的,有可能是历史遗留,幸好在开发过程中H5是可以实时预览的,也可以容易的放到iOS原生模拟器中看,如果出现类似JSB class not found的错误基本就是这个原因了,换一个写法就可以,这也是一个坑,需要慢慢踩。这里主要说一下JS怎么编码,因为JS自由度太大,所以最好结合JSB原理遵守一些规范。

(如有错误请不吝指正)

  • 规范命名空间,例如 var tt = {} || tt;
  • JS类:统一用cc.Class.extend来实现,例如:
tt.Monster = cc.Class.extend({
    id:         ""
    level:      1,
    texture:    null
});

这个好处是让JS类做到类似C++那样的继承,构造函数中通过this._super()可以调用父类构造函数;

  • 除了cc,ccui这些引擎指定的命名空间可能会调用C++外,所有JS的编写与浏览器中编写没有任何区别;
  • 效率问题:一般来说,不可交互的动画动作,都直接转化成C++接口,之后再也与JS无关不用担心效率问题;
  • 可交互动作,例如touch事件拖动精灵,减少JS里的复杂运算增加效率,但经过测试拖动精灵原生中没有让人感觉有区别;
  • 资源:虽然加载方式不一样,但原生使用上区别不大,两个点:一是touch事件接口有区别有坑要避雷,二是cocos studio只支持1.6及以前的json文件,以及最新cocos 2.1的json文件。
this.stage = guiReader.widgetFromJsonFile(res.StageUI_json);
this.addChild(this.stage, 200);
this.player = ccui.helper.seekWidgetByName(this.stage, "Player");
  • 其它:虽然很多JS写法比较便利,例如 sripte.x = 20 ,但建议写成 sprite.setPositionX(20),只为避雷;

包大小问题

采用JSB写游戏的好处是可以真正的多端运行,但从原理可知这是怎么一个回事,如果要做原生,唯一问题就是包大小了,SpiderMonkey本身就近10m的.so文件,最后打出的iOS近10M,apk包7M,纯C++的iOS才2M多,元芳怎么看?

扩展思考

看了上面的原理,应该不难知道Egret也是类似这么干了吧,但Egret优点是JS的编写用了TypeScript,微软的进阶版JS,更OO和利于组件模块化。

时间有限,先介绍到这里,下一篇会写关于网络请求相关。

参考文献

  • Javascript Binding(简称JSB)自动绑定教程
  • Cocos2d-x从C++到JS的进阶之路
  • Cocos2dx: Javascript Binding
  • Github:zynga/jsbindings
  • http://arewefastyet.com/
  • 关于V8 JavaScript Engine的使用方法研究
  • http://www.zhihu.com/question/21130385

你可能感兴趣的:(用JavaScript开发HTML5与C++游戏)