03. WebApp2.0时代启程:Cocos2d-JS让C++代码支持JS脚本(三)

紧接上文,JS在单线程下,性能不会比Java差,注意场景是单线程。Java的优势不仅是高级语言的特性,还具备了丰富的系统内核资源,如多线程、网络等支持,要比JS灵活的多很多,这里暂时不在讨论这些问题。

回到主题,如果我们把一个完整的C++图形引擎注入到SpiderMonkey中,把复杂的预算放到C/C++内核中,而JS只作为业务处理和内存管理,是否可以获得C/C++的运行能力,有获得了良好的逻辑处理呢?

答案是肯定的!我们直入主题,我们使用最新的SpiderMonkeyV1.8.5,一起解析一下cocos2d-js的代码,下一步,我们会将SpiderMonkey集成到iOS工程中,与JSPatch结合,打造一个跨平台的JS引擎:

1. 理解SpiderMonkey

网上有一些文章,只是用了一些皮毛,若要构建一个完整的JS引擎,要经常去看国外的SpiderMonkey论坛,如果想看中文,直接看Cocos2d-x的代码好了。今天,我们从Cocos2d-JS的入口类《ScriptingCore.cpp》开始

a) 启动JS虚拟机:ScriptingCore::start()

_rt = JS_NewRuntime(8L  1024L  1024L); // 开辟8M内存,作为JS运行控件
JS_SetGCParameter(_rt, JSGC_MAX_BYTES, 0xffffffff); // 设置GC的条件
JS_SetTrustedPrincipals(_rt, &shellTrustedPrincipals);  // 权限控制函数
JS_SetSecurityCallbacks(_rt, &securityCallbacks); // 权限回调函数
JS_SetNativeStackQuota(_rt, JSB_MAX_STACK_QUOTA); // 设置堆栈大小
_cx = JS_NewContext(_rt, 8192); // 创建当前上下文,一个Runtime可以支持多个上下文
JS::RuntimeOptionsRef(_rt).setIon(true);
JS::RuntimeOptionsRef(_rt).setBaseline(true);
JS_SetErrorReporter(_cx, ScriptingCore::reportError); // 设置异常回调函数

b) 就这么简单,一个JS的运行环境就启动了,我们写个小脚本测试一下《test.js》

var a = 0, b = 1, c = 2;
a = b + c;

c) 执行

RootedValue rval(_context); // 定义返回值
JSAutoCompartment ac(_context, _global); // 启动隔离区,类似mutex
string filename = pathfile.substr(pathfile.find_last_of("/") + 1); // 查找文件名称
bool success = JS_EvaluateScript(_context, RootedObject(_context, _global), file.bytes, file.size, filename.c_str(), linecount, &rval); // 执行JS文件
free(file.bytes);
string result = JS_EncodeStringToUTF8(_context, RootedString(_context, rval.toString()));
JS_MaybeGC(_context);

d) 打印result的value,可以看到值为3

2. 注入C++函数到SpiderMonkey

a) 先回顾一下cocos2d-JS注入了那些C++对象和类

在启动函数中,我们找到如下函数:AppDelegate::applicationDidFinishLaunching

ScriptingCore* sc = ScriptingCore::getInstance();
sc->addRegisterCallback(register_all_cocos2dx);
sc->addRegisterCallback(register_cocos2dx_js_core);
sc->addRegisterCallback(jsb_register_system);

sc->addRegisterCallback(register_all_cocos2dx_extension);
sc->addRegisterCallback(register_all_cocos2dx_extension_manual);

sc->addRegisterCallback(jsb_register_chipmunk);
sc->addRegisterCallback(JSB_register_opengl);

sc->addRegisterCallback(MinXmlHttpRequest::_js_register);
sc->addRegisterCallback(register_jsb_websocket);
sc->addRegisterCallback(register_jsb_socketio);

sc->addRegisterCallback(register_all_cocos2dx_builder);
sc->addRegisterCallback(register_CCBuilderReader);

sc->addRegisterCallback(register_all_cocos2dx_ui);
sc->addRegisterCallback(register_all_cocos2dx_ui_manual);
sc->addRegisterCallback(register_all_cocos2dx_studio);
sc->addRegisterCallback(register_all_cocos2dx_studio_manual);

sc->addRegisterCallback(register_all_cocos2dx_spine);
sc->addRegisterCallback(register_all_cocos2dx_spine_manual);

sc->addRegisterCallback(register_all_cocos2dx_3d);
sc->addRegisterCallback(register_all_cocos2dx_3d_manual);

sc->addRegisterCallback(register_all_cocos2dx_3d_extension);

b) 定义JS类成员函数和属性(eg. CCNode)

声明 Node的JS类模板JSClass

jsb_cocos2d_Node_class = (JSClass *)calloc(1, sizeof(JSClass));
jsb_cocos2d_Node_class->name = "Node"; // JS中ClassName
jsb_cocos2d_Node_class->addProperty = JS_PropertyStub;// 添加属性回调函数(默认就好)
jsb_cocos2d_Node_class->delProperty = JS_DeletePropertyStub;// 删除属性回调函数(默认就好)
jsb_cocos2d_Node_class->getProperty = JS_PropertyStub; // 获取属性回调函数(默认就好)
jsb_cocos2d_Node_class->setProperty = JS_StrictPropertyStub; //设置属性回调函数(默认就好)
jsb_cocos2d_Node_class->enumerate = JS_EnumerateStub; // 遍历属性回调函数(默认就好)
jsb_cocos2d_Node_class->resolve = JS_ResolveStub; // 解析属性回调函数(默认就好)
jsb_cocos2d_Node_class->convert = JS_ConvertStub;// 转换属性回调函数(默认就好)
jsb_cocos2d_Node_class->finalize = js_cocos2d_Node_finalize;// 析构函数的回调函数,最好用自己的
jsb_cocos2d_Node_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2);// 拥有2个临时持有对象的槽位,方便持有回调函数的引用,比如点击事件

b) 声明类成员属性

static JSPropertySpec properties[] = {
    JS_PSG("__nativeObj", js_is_native_obj, JSPROP_PERMANENT | JSPROP_ENUMERATE),
    JS_PS_END
};

JS_PSG(属性名称,属性回调函数,不可删除| 可以遍历); // 用于只声明只读的属性
JS_PSGS(属性名称,get属性回调函数, set属性回调函数,不可删除| 可以遍历);// 用于声明读写的属性

c) 声明类成员函数

static JSFunctionSpec funcs[] = {
    JS_FN("addChild", js_cocos2dx_Node_addChild, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),
    ....
    JS_FN_END
};

JS_FN定义JS函数声明
JS_FN(函数在JS中得名称,函数的Native回调函数,参数个数,不可以删除|可以遍历);

d) 有了函数和属性的声明后,我们把属性和函数注入到a)中声明的JSClass中吧

jsb_cocos2d_Node_prototype = JS_InitClass(
    cx, global, // 上下文,全局对象,上篇文章已经讲过
    JS::NullPtr(), // 没有父类
    jsb_cocos2d_Node_class, // 当前类(Node)模板
    js_cocos2dx_Node_constructor, 0, // native构造函数和参数个数
    properties,// 上面定义的属性字段列表
    funcs,// 上面定义的函数属性列表
    NULL, // 没有静态属性
    st_funcs // 有静态函数
);

好了这样就可以在JS中直接调用这个JS类对象了:

var parent = new Node();
var child   =  new Node();
parent.addChild(child);

然后再C++代码中添加断点,看看是否断点成功进入。

(总结)

a) cocos2d-JS引入了Cocos2d-x图形引擎作为JS的底层运行支持,为JS提供了更高层面的API封装,为H5展示更绚丽的画面提供基础,极大的满足了众多页游开发者多平台化的需求。不仅如此,cocos2d-js还提供了一套html5的canvas的API封装,让开发者直接在浏览器上所见即所得的开发方式,然后用JSB作为运行环境,彻底打破游戏开发的编译-调试的运行模式。

b) cocos2d-JS目前也有一些较为突出的缺陷,虽然H5的性能的得到了极大的提升,相对Native性能,还是明显差很多,究其原因有:
(i)JSBinding代码太多,大约15W行左右,代码较大,频繁的转换JS与C++对象,耗时的同时产生了大量的临时对象,GC时候,卡顿感明显,类似于Android,大家可以脑补一下【性能下降】
(ii)不是严格意义的JS语言规范,JS与Native的两套内存管理机制,相互制约,导致C++需要维护一个很大的Map的双向对象映射关系,来维护不同的内存管理模式【性能下降】
(iii)JS只是工具,失去了JS的灵活性,为了减少binding的复杂度,Cocos2d-JS很多成员变量都是用函数方式去获取,得到的往往是个临时变量,而不能直接操作,需要前端开发者,长时间的理解规范,才能够避免技术上的缺陷

(优化)

有没有一种办法既可以满足JS的灵活性,也可以满足Native的内存管理呢?答案是肯定的,请持续关注下一阶段的AppEngine的实时动态。

(番外)

QQ浏览器的独门暗器是什么?如果某些网站是支持cocos2d-JS的,那么直接启动Cocos2d-JS内核作为加载容器,性能爆表啊,有木有?!莫非以后的浏览器将是游戏市场的必争之地?

(求知己)

Cocos2d-JS的介绍,到此告一段落,有想法的同学,可以私聊我。

时间: 2024-10-30 17:00:30

03. WebApp2.0时代启程:Cocos2d-JS让C++代码支持JS脚本(三)的相关文章

01. WebApp2.0时代启程:Cocos2d-JS详解(一)

(一)WebApp时代,追求App开发效率的同时,我们也要求终端的体验和性能,2/8原则可以很好的阐述当前的hybird开发方式:20%的Native代码+80%的H5代码. (二)H5可以发挥的性能极致是什么样子? 了解这个问题,就需要知道H5的技术定位:一套H5代码支持Android.iOS.PC等多平台的前端语言,这就决定了再好的iOS平台性能,也不能忘记Android平台的用户体验:最终开发者选择了降低用户体验情况下,降低了H5的用户体验. (三)H5可以做的更好,不管是Android还

08. WebApp2.0时代启程:倒立者赢,NativePixi,所见即所得的开发方式

紧接上文,在终端设备中,不管是游戏引擎还是UIKit,图形图像都是基于跨平台的OpenGL ES技术,区分不同的场景,图形图像分为两个分支,一个以高性能的图形显示为目标的cocos2d-x引擎,一个是以省电节能适合App的UIKit框架. 一)今天我们继续逆向思维 Game VS App,既然都是基于OpenGL ES,那我们找出共同点,是否可以让二者的界限,变得更模糊?既可以满足高性能的Game引擎,可以保持App开发? 请仔细观看上图,我们的框架多了一个WebKit? 对的,我以为WebKi

05. WebApp2.0时代启程:倒立者赢,从过去到现在的变化,看将来的发展(一)

1. 移动互联网的兴起,我认为2009年是个分水岭. 开始的时候,我也是做Java开发,习惯了Webx架构,可以熟练的使用Spring.iBatis.veloctiy.HSF.Notify.Tair.Session这些阿里具有代表性的Java框架,也会使用IC.UIC.SC.DC等等服务集群做电商核心业务.概括起来,基本也是三层服务端架构: 2. 技术架构也非常稳定 后台MySQL分库分表.服务端HSF业务处理,前端浏览器使用Html做展示,技术人员的重叠率较低,公司内部资源达到了最大化价值体现

02. WebApp2.0时代启程:Cocos2d-JS为什么选择SpiderMonkey(二)

紧接上文,cocos2d-JS为我们提供了图形引擎.物理引擎.JS引擎等基础库,在多终端时代提供了非常nice的游戏引擎,在浏览器普及在各个终端的今天,为什么还要单独搞一套JS引擎呢? 我们先看看使用SpiderMonkey的技术产品有哪些? 没有看错,SpiderMonkey就是FireFox浏览器的JS虚拟机(后续简称jsvm),FireFox的实力也是赢得了众多前端开发者的芳心:cocos2d-x更是不用说了,东亚97%的2D游戏开发者的选择,手游开发者的入门技能,k-3D也是在AEPIX

09. WebApp2.0时代启程:倒立者赢,挑战Android性能极限

紧接上文,在终端硬件资源有限的大背景下,业务脚本+图形内核,将是未来主流的开发方式.AEPixi使用C/C++.JS.JNI.OC等混合语言开发,将pixi.js变成高性能的Native内核,提供上层pixi.js标准的API,无缝的兼容浏览器开发好的代码,实现浏览器开发,无需编译,到处运行的开发方式. 今天我们做一个H5的Demo,使用FireFox开发,开发完成之后,直接使用上一章节我们发布的android app,直接访问查看效果. 一)搭建前端开发环境 Subline Text2 / V

07. WebApp2.0时代启程:倒立者赢,从CPU到GPU,一张图片的旅行

紧接上文,终端开发使用的WindVane.wax.ReactNative等已经是一种跨平台的技术,我们称之为上层跨平台,Cocos2d-x这种直接使用C/C++,我们成为底层跨平台.上层跨平台,提升开发效率:下层跨平台,提升程序性能. 1. 为什么Cocos2d-x性能比Native开发要好? 因为Cocos2d-X是游戏引擎呗,人家是专业做游戏特效的好不好,直接调用GPU的OpenGL绘图的好不好.打开Cocos2d-X代码,感触最深的不是CCNode这些游戏节点,cocos2d-x已经开始为

js判断上传图片代码(支持ie8,firefox,ie6)

  <!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="conten

js网页时间代码-支持一秒秒走动代码

提示:您可以先修改部分代码再运行 In this case the countdown is to December 5, 2007. 提示:您可以先修改部分代码再运行

Seo3.0时代 外链建设不再墨守陈规

SEO1.0是拼关键词堆砌的时代,SEO2.0大体是拼外链的时代,目前SEO已经进入3.0时代,更多的是注重用户的体验建设,外链建设不能再墨守陈规.从百度官方提出的外链算法后,SEO再也不是拼资源发外链做排名的时代,站长们要看开发新的外链形式,让外链建设脱颖而出. 外链也要注重用户体验 搜索算法更新后不再是堆积垃圾外链,外链更多的是要考虑到用户体验,哪些平台的外链既可以吸引蜘蛛爬行,又能提高用户体验,吸引用户点击链接来到站点.分析网站的潜在客户活动平台,客户需要获得哪些服务,企业给客户提供这样的