Sloppy's Blog

cocos2d-x如果让c++执行js回调

此文章接:点击查看绑定C++给JS调用 这篇文章而来.

Cocos2d-x JS项目中JS调用C++,相对比较简单,在前一篇文章也做了说明。主要是绑定C++给JS调用。相对简单,那昨天看到论坛里好多朋友一直在讨论C++调用JS的问题,好象都有一些奇怪的问题,今天做了一个测试DEMO。下面分几点来看一下。

改造之前的C++类(Eraylayer)

新增一个Delegate类,为ErayLayer添加设置Delegate类,ErayLayer头文件如下:

class ErayDelegate:public cocos2d::Ref {
public:
    virtual void onClick(const std::string& value) {};
    virtual ~ErayDelegate() {};
};

class ErayLayer :public cocos2d::Layer {
public:
    ErayLayer();
    ~ErayLayer();
    virtual bool init();
    CREATE_FUNC(ErayLayer);
    void setDelegate(ErayDelegate* _delegate);
private:
    ErayDelegate* m_pDelegate;
};

CPP文件如下:

ErayLayer::ErayLayer() {
    m_pDelegate = nullptr;
}
ErayLayer::~ErayLayer() {
    CC_SAFE_RELEASE(m_pDelegate);
}
bool ErayLayer::init() {
    if (!Layer::init()) {
        return false;
    }
    ImageView* image = ImageView::create();
    image->loadTexture("res/diamond3.png");
    image->setTouchEnabled(true);
    image->addTouchEventListener([=](Ref *pSender, ui::Widget::TouchEventType type) {
        if (type != ui::Widget::TouchEventType::ENDED)
            return;
        if (m_pDelegate) {
            m_pDelegate->onClick("call from cpp");
        }
        CCLOG("click on Image");
    });
    image->setPosition(Vec2(300.0f, 300.0f));
    addChild(image);
    return true;
}
/**
* @brief 设置代理执行类
*/
void ErayLayer::setDelegate(ErayDelegate* _delegate) {
    if (_delegate) {
        m_pDelegate = _delegate;
        m_pDelegate->retain();
    }
}

新增jsb_coolexp_manual.hpp,jsb_coolexp_manual.cpp,主要代码如下:

〈pre>
class JSB_ErayDelegate :public ErayDelegate {
public:
JSB_ErayDelegate() {

}
virtual void onClick(const std::string& value) override {
    // 执行代理的方法
    JSContext *cx = ScriptingCore::getInstance()->getGlobalContext();
    jsval arg = std_string_to_jsval(cx, value);
    JS::RootedValue delegateVal(cx, _JSDelegate);
    ScriptingCore::getInstance()->executeFunctionWithOwner(delegateVal, "onClick", 1, &arg);

    // 调用一个全部的对象的方法
    JSContext * context = ScriptingCore::getInstance()->getGlobalContext();
    JS::RootedObject object(context, ScriptingCore::getInstance()->getGlobalObject());
    JS::RootedValue owner(context);
    jsval arg1 = INT_TO_JSVAL(1001);

    JS_GetProperty(context, object, "Config", &owner);
    ScriptingCore::getInstance()->executeFunctionWithOwner(owner, "sendNumber", 1, &arg1);
}
void setJSDelegate(JS::HandleValue pJSDelegate)
{
    _JSDelegate = pJSDelegate;
}

private:
JS::Heap _JSDelegate;
};
static bool jsb_ErayLayer_setJSHandler(JSContext cx, uint32_t argc, jsval vp) {
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
JS::RootedObject obj(cx, args.thisv().toObjectOrNull());
js_proxy_t proxy = jsb_get_js_proxy(obj);
ErayLayer
cobj = (ErayLayer )(proxy ? proxy->ptr : NULL);
JSB_PRECONDITION2(cobj, cx, false, “Invalid Native Object”);
if (argc == 1)
{
// save the delegate
JSB_ErayDelegate
nativeDelegate = new (std::nothrow) JSB_ErayDelegate();
nativeDelegate->setJSDelegate(args.get(0));
cobj->setDelegate(nativeDelegate);
args.rval().setUndefined();
nativeDelegate->release();
return true;
}
JS_ReportError(cx, “wrong number of arguments: %d, was expecting %d”, argc, 1);
return false;
}

extern JSObject jsb_ErayLayer_prototype;
void register_all_coolexp_manual(JSContext
cx, JS::HandleObject global)
{
JS::RootedObject proto(cx, jsb_ErayLayer_prototype);
JS_DefineFunction(cx, proto, “setJSDelegate”, jsb_ErayLayer_setJSHandler, 1, JSPROP_ENUMERATE | JSPROP_PERMANENT);
}

JS文件内容:

var erayLayer = ErayLayer.create();
this.addChild(erayLayer);
erayLayer.setJSDelegate({
    "onClick":function(value){
        cc.log("onClick:%s",value);
    }
});

// 写在JS顶层
var Config = Config || {};

Config.sendNumber = function(num)
{
    cc.log("From javascript: " + num);
};

运行点击场景上的图片,看打印输出

参考文件:点击查看