CocosBuilder是一个用于cocos2d的可视化编辑器,属于cocos2d联合发布的一部分。我曾经考虑过用它来做游戏的界面编辑,但是做了个Demo,评估了下之后,还是放弃了这个想法。一方面是感觉CocosBuilder还不太成熟,很多cocos2d的类与方法都不能在CocosBuilder中直接使用,另一方面用cocos2d-x加载ccbi文件之后,需要手动的对场景(或者是节点)里面的成员进行绑定,而我要做的项目单个界面并不复杂,但是界面很多,如果每个界面都手动绑定的话,实际效率上不会有太大的提高,但是项目的复杂度却会大大的增加,再加上当时项目比较紧,没有太多的时间用来学习和尝试CocosBuilder,所以最后选择了放弃。
前段时间被以前的同学拉去参加黑客马拉松,正好有个机会试试CocosBuilder,发现了不少有趣的东西。
CocosPlayer
在开发ios游戏的时候,由于必须由XCode进行代码编译,所以像Unity这样的跨平台游戏引擎,在进行真机调试之前,都必须先把做好的项目导出成一个XCode项目,然后编译这个XCode项目来进行真机调试。而用过unity的人应该都很清楚,这个导出的过程非常的缓慢。
相比之下,CocosPlayer的出现给了用CocosBuilder开发游戏的人一个方便、快捷的真机测试途径。它的原理是通过wifi,CocosBuilder直接把ccbi、js以及资源文件发布给真机上运行的CocosPlayer,CocosPlayer接受完毕之后,运行js文件来开始游戏。这样省去了导出和编译的步骤,只需要一次wifi传输即可。(当然CocosPlayer本身的编译过程还是要有的,只是这个编译并不频繁,一般只是在你第一次运行或者修改本地代码的时候才需要执行)
一键发布
CocosBuilder支持一键发布多平台(ios、android、html5)应用,并且会自动把resources-auto文件夹里面的图片进行缩放,来适配不同的屏幕大小。(不过似乎没有考虑到iphone5?)
用CocosBuilder来制作图集
对于cocos2d开发者来说,最常用的制作图集的方法莫过于TexturePacker了,只不过TexturePacker是收费的,对于图集要求不高的朋友可以试试用CocosBuilder来制作图集。CocosBuilder的这个功能并不是独立出来的,而是附加在发布功能上面,把要制作成图集的图片放在一个文件夹下面,CocosBuilder中右键该文件夹,选择Make Smart Sprite Sheet,然后发布项目,之后在发布出来的文件夹里面就能找到图集的.plist与.png文件了^_^当然,这种方法有点旁门左道了,而且可供选择的功能远远不如TexturePacker那么多,正式制作游戏的时候还是花点钱用TexturePacker为好。
Javascript binding
剩下的诸如场景制作、动画制作、粒子特效都是CocosBuilder的传统功能了,看官方文档即可,无需多讲,最后来说说Javascript绑定。在CocosBuilder中可以通过javascript来编写游戏,使用mvc方式进行交互,即需要交互的ccb文件指定一个js类来作为其控制器,ccb文件中的成员和方法都可以由这个指定的类进行控制和实现。cocos2d使用SpiderMonkey作为其JS引擎,所以标准的js语法和库都能够支持,同时cocos2d为自己的本地代码提供了jsb接口,所以大多数cocos2d中的类与方法也可以用js直接调用(注意:不是全部),并且还提供了jsb接口的生成工具让我们能够为自己的本地代码做js绑定。于是我就帮我的摇杆添加了js绑定,在添加的过程中遇到了一些问题,我相信这些问题也是现在js绑定存在的一些主要问题,下面来具体说一下。
根据cocos2d-x官方的说法,这个jsb生成工具的有一些限制,比如函数不能有可变参数、参数不能有默认值、delegate需要手动绑定。根据我的使用经验,还发现一个限制就是不能传null值给函数。前两个限制还好解决,改变一下函数写法就好了,后面两个就比较蛋疼了。先说delegate的问题,由于摇杆需要在玩家的操作之后做出一系列的回调处理,但是delegate本身是c++的代码,它回调的对象是js的代码,而生成工具无法判断出delegate,所以回调的一律是c++代码,所以遇到要回调js的delegate,我们就得靠自己来绑定,至于怎么自己绑定官方文档没写,谷歌也不知道。
我查看了cocos2d-x自己做的手动绑定,发现大致的流程是这样的:先把需要手动绑定的代码在jsb生成工具的配置文件中禁掉,接着为delegate编写一个代理类,这个代理类主要把delegate的回调跟js那边的代码关联起来,然后把delegate的对象实例替换成代理类的,最后注册手动绑定的方法。
以我为摇杆做的js绑定为例,在配置文件中把我们需要手动绑定的部分禁掉:
classes=Joystick
#...
skip = Joystick::[setDelegate]
编写delegate的代理类:
class JSB_JoystickDelegate : public JoystickDelegate
{
public:
virtual void onRock(ysDirection director,CCPoint vector)
{
jsval arg[2];
arg[0]=INT_TO_JSVAL(director);
arg[1]=ccpoint_to_jsval(ScriptingCore::getInstance()->getGlobalContext(), vector);
ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(m_pJSDelegate), "onRock",2,arg,NULL);
}
virtual void onRockEnd()
{
ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(m_pJSDelegate),"onRockEnd");
}
void setJSDelegate(JSObject *sender)
{
m_pJSDelegate=sender;
}
private:
JSObject* m_pJSDelegate;
};
替换代理类实例:
JSB_JoystickDelegate* nativeDelegate = new JSB_JoystickDelegate();
nativeDelegate->setJSDelegate(jsDelegate);
cobj->setDelegate(nativeDelegate);
注册函数:
extern JSObject *jsb_Joystick_prototype;
void register_all_joystick_manual(JSContext *cx,JSObject *global)
{
JS_DefineFunction(cx, jsb_Joystick_prototype, "setDelegate", js_joystick_Joystick_setDelegate, 1, JSPROP_READONLY|JSPROP_PERMANENT);
}
这样就OK了。js那边的代码可以接收到摇杆事件的回调了!
关于传null值会报错的问题,有两种处理方法。一种是传一个没用的初始化对象进去,另一种方法是找到报错的地方,把JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object");这一句代码注释掉。如果第一种方法没法解决的话,再用第二种方法比较好。