JSBinding绑定 -- CCTableView

这几天公司要把一款以前用cocos2d(object-c)版本的游戏翻译成可以跨平台的,我个人是想要用C++的,因为我对C++还是有点经验的,但是没理法,才刚毕业,老板不是很相信,很是怀疑我的C++能力,在加上公司只有我一个懂C++,于是,他问了另外一个做服务端的,用PHP写的,基本上他只会PHP的,然后他说用JS来,说JS的开发效率高。本来我是比较担心JS的心能,但是他发了三天时间,终于把-x里面的jsdemo下到安卓上面,然后说js的性能应该没有问题,但是我对其还是比较怀疑的。看了一下-x,后来发现,-x里面的jsbinding里面调用的还是原生的C++,也就是说渲染引擎跟C++其实应该是一样的,性能应该跟原生的效率不会差很多,个人理解。那就只能用JS了,发了点牢骚,进入正题
在手机上面,-x通过jsbingding,将C++的源生库给绑定成JS可以直接调用的方式。但是基本看不到关于将C++绑定成JS的相关资料,而且后来2.0加上去的一些扩展类都没有做相应的绑定。既然上头说要用JS开发,那这些控件肯定是要绑定的。所以这个事情就落到了我的头上了。

既然没有相关的资料,没有理法,只能看源代码,参考着绑定。刚开始做这个的时候,我决定从CCTableView开始入手,因为个人感觉这个东西涉及到的应该会比较全面,有JS调用C++和C++调用JS,如果这个可以绑定成功了,后面的应该都没有什么问题了吧。开始的时候,可以先看一下cocos2d_specifics.cpp 、cocos2dx.cpp这两个文件,只要照着这个上面的方式做,一些简单的方法绑定应该都没有太大的问题,核心是ibjs_static.a这个静态库,有点大,>20M,按照这两个文件的写法,封装好要传递的参数和要要调用的函数,基本上不会有很大的问题,浪费时间,体力活。开始CCTableView的绑定。一开始我自己是这样认为的。首先我们在JS创建一个CCTableView的控件,比如要用到Create方法,也就是JS要调用C++的代码,这个的绑定方法很简单,参考下cocos2d_specifics.cpp 、cocos2dx.cpp的方式写一个,可以发现C++的Create被调用到了,而且JS也到了一个CCTableView的对象了(JS上面用的对象),创建成功之后,CCTableView的三个调用数据源的委托方法要被实现,也就是说我们要在JS上面重写这些委托方法,然后C++去调用JS的方法。这时,我发现这个方式就是跟touch事件的处理有点相似了,接着看CCLayer

bool CCLayer::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
    if (kScriptTypeNone != m_eScriptType)
    {
        return excuteScriptTouchHandler(CCTOUCHBEGAN, pTouch) == 0 ? false : true;
    }

    CC_UNUSED_PARAM(pTouch);
    CC_UNUSED_PARAM(pEvent);
    CCAssert(false, "Layer#ccTouchBegan override me");
    return true;
}

这边我们可以看到,如果是lua或者js脚本的时候,会去执行一个方法,这个方法可以让C++调用到JS,跟踪后我们发现最终在ScriptingCore.cpp这个文件里面发现了调用JS的方法,int ScriptingCore::executeLayerTouchEvent(CCLayer* pLayer, int eventType, CCTouch *pTouch);所以这个在这个tableview里面我们是不是也要弄个分支,让他去执行一个可以让C++调到js的方法呢。但是在CCTableView.cpp里面,我们发现这些委托方法被调用的地方有很多,这样要写分支的地方也就会很多,这样一来代码的维护就会出现问题,没理法,只能把CCTableView在往上面封装一层,这边我把他给封装成了JSTableView的样子
JSTableView.h

//
//  JSTableView.h
//  tableview
//
//  Created by mac on 12-12-25.
//
//

#ifndef __tableview__JSTableView__
#define __tableview__JSTableView__

#include "cocos2d.h"
#include "CCTableView.h"
#include "CCTableViewCell.h"

USING_NS_CC;
USING_NS_CC_EXT;

NS_CC_EXT_BEGIN
class JSTableView;

class JSTableViewDelegate
{
public:
    virtual void executeTableCellTouched(JSTableView* table, CCTableViewCell* cell) = 0;
};

class JSTableViewDataSource
{
public:
    virtual CCSize executeCellSizeForTable(JSTableView *table) = 0;
    virtual CCTableViewCell* executeTableCellAtIndex(JSTableView *table, unsigned int idx) = 0;
    virtual unsigned int executeNumberOfCellsInTableView(JSTableView *table) = 0;
};

class JSTableView:public CCTableView,public CCTableViewDataSource,public CCTableViewDelegate
{
public:
    JSTableView()
    {
        CCTableView::setDataSource(this);
    }
    static JSTableView* create(JSTableViewDataSource* dataSource, CCSize size,CCNode *container = NULL)
    {
        JSTableView *table = new JSTableView();
        table->initWithViewSize(size, container);
        table->autorelease();
        table->setDataSource(dataSource);
        table->_updateContentSize();
        return table;
    }

    virtual void scrollViewDidScroll(cocos2d::extension::CCScrollView* view)
    {
        CCTableView::scrollViewDidScroll(view);
    }
    virtual void scrollViewDidZoom(cocos2d::extension::CCScrollView* view)
    {
        CCTableView::scrollViewDidZoom(view);
    }
    virtual void tableCellTouched(CCTableView* table, CCTableViewCell* cell);
    virtual CCSize cellSizeForTable(CCTableView *table);
    virtual CCTableViewCell* tableCellAtIndex(CCTableView *table, unsigned int idx);
    virtual unsigned int numberOfCellsInTableView(CCTableView *table);
    
    inline void setDelegate(JSTableViewDelegate* p)
    {
        CCTableView::setDelegate(this);
        m_pJSTableViewDelegate = p;
    }
    inline void setDataSource(JSTableViewDataSource* p)
    {
        CCTableView::setDataSource(this);
        m_pJSTableViewDataSource = p;
    }
    
private:
    JSTableViewDataSource *m_pJSTableViewDataSource;
    JSTableViewDelegate *m_pJSTableViewDelegate;
};

NS_CC_EXT_END
#endif /* defined(__tableview__JSTableView__) */

JSTableView.cpp

//
//  JSTableView.cpp
//  tableview
//
//  Created by mac on 12-12-25.
//
//

#include "JSTableView.h"

NS_CC_EXT_BEGIN
void JSTableView::tableCellTouched(CCTableView* table, CCTableViewCell* cell)
{
    if (m_pJSTableViewDelegate)
    {
        CCScriptEngineManager::sharedManager()->getScriptEngine()->executeTableCellTouch((JSTableViewDelegate*)m_pJSTableViewDelegate, this, cell);
    }
}
CCSize JSTableView::cellSizeForTable(CCTableView *table)
{
    if (m_pJSTableViewDataSource)
    {
        return CCScriptEngineManager::sharedManager()->getScriptEngine()->executeCellSizeForTable(m_pJSTableViewDataSource, this);
    }
    return CCSizeZero;
}
CCTableViewCell* JSTableView::tableCellAtIndex(CCTableView *table, unsigned int idx)
{
    if (m_pJSTableViewDataSource)
    {
      return  CCScriptEngineManager::sharedManager()->getScriptEngine()->executeTableCellAtIndex(m_pJSTableViewDataSource, this, idx);
    }
    return NULL;
}
unsigned int JSTableView::numberOfCellsInTableView(CCTableView *table)
{
    if (m_pJSTableViewDataSource)
    {
        return CCScriptEngineManager::sharedManager()->getScriptEngine()->executeNumberOfCellsInTableView(m_pJSTableViewDataSource, this);
    }
    return 0;
}

NS_CC_EXT_END

这样一来省去了要去CCTableView查找每个委托被调用到的地方,然后在添加调用JS的方法

ScriptingCore.cpp 添加方法

unsigned int ScriptingCore::executeNumberOfCellsInTableView(JSTableViewDataSource *dest,JSTableView *table)
{
    std::string funcName = "numberOfCellsInTableView";
    
    js_proxy_t * p;
    JS_GET_PROXY(p, dest);
    if (!p) return NULL;
    
    jsval value1;
    
    js_proxy_t * p1;

    p1 = js_get_or_create_proxy<cocos2d::extension::JSTableView>(this->getGlobalContext(),table);
    value1 = OBJECT_TO_JSVAL(p1->obj);


    jsval *date = new jsval();
    date = value1;
    
    jsval retval;
    
    executeJSFunctionWithName(this->cx_, p->obj, funcName.c_str(), *date, retval,1);
    
    return JSVAL_TO_INT(retval);
}

现在,基本上就可以把CCTableView的库给绑定成功了。主要核心是那个20多兆的库,只要参考着-x已有的绑定方法和CCTableView的绑定方式,构建好要传递的参数和方法,后面的绑定应该不会有很大的问题了

不想在写绑定过程遇到的问题了,还要苦逼的上班呢。直接上代码,希望交流,我也是刚开始做的,有错的留言
源代码就:http://download.csdn.net/detail/zjf526655060/4932847

  • 本帖最后由 cgw0827 于 2013-3-26 14:15 编辑 *

— Begin quote from ____

今天6号 发表于 2013-3-25 14:08 url

我也遇到了这个问题,求高人解答

— End quote

看看cocos2d-x是怎么绑定的就ok了!主要是cocos2d-2.1beta3-x-2.1.0/tools/tojs/cocos2dx.ini文件。

— Begin quote from ____

gutaideng 发表于 2013-3-18 22:43 url

如果在test类中include “cocos2d.h”, 绑定就会报错, 这该怎么解决呢?

— End quote

我也遇到了这个问题,求高人解答

— Begin quote from ____

杨猪 发表于 2013-1-9 01:43 url

这个配置好相关的路径执行test.sh就可以生成出绑定的文件了。不过实际上还是需要对生成的文件做调整。

— End quote

如果在test类中include “cocos2d.h”, 绑定就会报错, 这该怎么解决呢?

— Begin quote from ____

cgw0827 发表于 2012-12-29 16:00 url

不知道楼主对cocos2d-x/cocos2d-2.1beta3-x-2.1.0/tools/cxx-generator/test有什么研究吗?

— End quote

这个配置好相关的路径执行test.sh就可以生成出绑定的文件了。不过实际上还是需要对生成的文件做调整。

— Begin quote from ____

今天6号 发表于 2013-3-25 14:08 url

我也遇到了这个问题,求高人解答

— End quote

我现在都是用tojs里面的ini文件,直接复制一份,改改

这个问题可能是需要再header参数里加上coco2d-x的路径吧

我对这个还不太了解,今天看了cocos2d里关于JSB的wiki,JSB是能过spidermonkey(mozilla的一个开源项目,也就是那个20多M的库)来解析js代码,渲染的部分还是cocos2d-x里的opengl,但解析的过程也是有性能的问题的。还有就是现在的JSB还不完善,TestJavascript项目里还有很多的例子是灰色不给运行的,box2d也还没有。所以我觉得要使用到项目中的话还得等一段时间,但先研究的话也是很有益处的。

不知道楼主对cocos2d-x/cocos2d-2.1beta3-x-2.1.0/tools/cxx-generator/test有什么研究吗?

  • 本帖最后由 cgw0827 于 2013-3-26 14:15 编辑 *

— Begin quote from ____

今天6号 发表于 2013-3-25 14:08 url

我也遇到了这个问题,求高人解答

— End quote

看看cocos2d-x是怎么绑定的就ok了!主要是cocos2d-2.1beta3-x-2.1.0/tools/tojs/cocos2dx.ini文件。

— Begin quote from ____

gutaideng 发表于 2013-3-18 22:43 url

如果在test类中include “cocos2d.h”, 绑定就会报错, 这该怎么解决呢?

— End quote

我也遇到了这个问题,求高人解答

我对这个还不太了解,今天看了cocos2d里关于JSB的wiki,JSB是能过spidermonkey(mozilla的一个开源项目,也就是那个20多M的库)来解析js代码,渲染的部分还是cocos2d-x里的opengl,但解析的过程也是有性能的问题的。还有就是现在的JSB还不完善,TestJavascript项目里还有很多的例子是灰色不给运行的,box2d也还没有。所以我觉得要使用到项目中的话还得等一段时间,但先研究的话也是很有益处的。

不知道楼主对cocos2d-x/cocos2d-2.1beta3-x-2.1.0/tools/cxx-generator/test有什么研究吗?