Cocos jsb 2.0 示例

Cocos Creator 手动绑定不完全手册

官方 JSB 2.0 说明文档
http://docs.cocos.com/creator/manual/zh/advanced-topics/jsb/JSB2.0-learning.html

本文只补齐文档中缺少的实操部分,具体代码是什么意思请参考文档

废话不多说,由于本例子在 iOS 真机上测试的,所以只构建 xcode 工程,Android 同理

Creator v2.0.1

MacOS, XCode

Github: https://github.com/shpz/CocosJSBExample

交流群: 850993054

Step 1

首先构建 xcode 工程,如图所示

记得把调试模式钩上方便测试

Step 2

打开构建好的 xcode,长这样

然后依次点开 cocos2d_libs.xcodeproj/jsbindings/manual

## Step 3

在这里新建一个 jsb_test.hpp 一个 jsb_test.cpp,把以下内容依次复制进去

// jsb step 3
// jsb_test.hpp

#pragma once

namespace se {
    class Object;
}

bool js_register_jsbTest_jsbTest(se::Object* obj);




// jsb step 3
// jsb_test.cpp

#include "jsb_test.hpp"
#include "cocos2d.h"
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"

USING_NS_CC;

static bool jsb_test_log(se::State& s)
{
    CCLOG("jsb_test_log, run this!");
    return true;
}
SE_BIND_FUNC(jsb_test_log)


bool js_register_jsbTest_jsbTest(se::Object* global)
{
    global->defineFunction("jsb_test_log", _SE(jsb_test_log));
    return true;
}


然后再新建一个 jsb_class_test.hpp 一个 jsb_class_test.cpp,把以下内容依次复制进去

// jsb step 3
// jsb_class_test.hpp

namespace se {
    class Object;
    class Class;
}

bool js_register_ns_SomeClass(se::Object* obj);




// jsb step 3
// jsb_class_test.cpp

#include "jsb_class_test.hpp"
#include "cocos2d.h"
#include "SeApi.h"
#include "jsb_classtype.hpp"

USING_NS_CC;

static se::Object* __jsb_ns_SomeClass_proto = nullptr;
static se::Class* __jsb_ns_SomeClass_class = nullptr;

namespace ns {
    class SomeClass
    {
    public:
        SomeClass()
        : xxx(0)
        {}
        
        void foo() {
            printf("SomeClass::foo\n");
        }
        
        static void static_func() {
            printf("SomeClass::static_func\n");
        }
        
        void setCallback(const std::function<void(int)>& cb) {
            _cb = cb;
            if (_cb != nullptr)
            {
                printf("setCallback(cb)\n");
            }
            else
            {
                printf("setCallback(nullptr)\n");
            }
        }
        
        int xxx;
    private:
        std::function<void(int)> _cb;
    };
}

static bool js_SomeClass_finalize(se::State& s)
{
    ns::SomeClass* cobj = (ns::SomeClass*)s.nativeThisObject();
    delete cobj;
    return true;
}
SE_BIND_FINALIZE_FUNC(js_SomeClass_finalize)

static bool js_SomeClass_constructor(se::State& s)
{
    ns::SomeClass* cobj = new ns::SomeClass();
    s.thisObject()->setPrivateData(cobj);
    return true;
}
SE_BIND_CTOR(js_SomeClass_constructor, __jsb_ns_SomeClass_class, js_SomeClass_finalize)

static bool js_SomeClass_foo(se::State& s)
{
    ns::SomeClass* cobj = (ns::SomeClass*)s.nativeThisObject();
    cobj->foo();
    return true;
}
SE_BIND_FUNC(js_SomeClass_foo)

static bool js_SomeClass_get_xxx(se::State& s)
{
    ns::SomeClass* cobj = (ns::SomeClass*)s.nativeThisObject();
    s.rval().setInt32(cobj->xxx);
    return true;
}
SE_BIND_PROP_GET(js_SomeClass_get_xxx)

static bool js_SomeClass_set_xxx(se::State& s)
{
    const auto& args = s.args();
    int argc = (int)args.size();
    if (argc > 0)
    {
        ns::SomeClass* cobj = (ns::SomeClass*)s.nativeThisObject();
        cobj->xxx = args[0].toInt32();
        return true;
    }
    
    SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", argc, 1);
    return false;
}
SE_BIND_PROP_SET(js_SomeClass_set_xxx)

static bool js_SomeClass_static_func(se::State& s)
{
    ns::SomeClass::static_func();
    return true;
}
SE_BIND_FUNC(js_SomeClass_static_func)

bool js_register_ns_SomeClass(se::Object* global)
{
    // 保证 namespace 对象存在
    se::Value nsVal;
    if (!global->getProperty("ns", &nsVal))
    {
        // 不存在则创建一个 JS 对象,相当于 var ns = {};
        se::HandleObject jsobj(se::Object::createPlainObject());
        nsVal.setObject(jsobj);
        
        // 将 ns 对象挂载到 global 对象中,名称为 ns
        global->setProperty("ns", nsVal);
    }
    se::Object* ns = nsVal.toObject();
    
    // 创建一个 Class 对象,开发者无需考虑 Class 对象的释放,其交由 ScriptEngine 内部自动处理
    auto cls = se::Class::create("SomeClass", ns, nullptr, _SE(js_SomeClass_constructor)); // 如果无构造函数,最后一个参数可传入 nullptr,则这个类在 JS 中无法被 new SomeClass()出来
    
    // 为这个 Class 对象定义成员函数、属性、静态函数、析构函数
    cls->defineFunction("foo", _SE(js_SomeClass_foo));
    cls->defineProperty("xxx", _SE(js_SomeClass_get_xxx), _SE(js_SomeClass_set_xxx));
    
    cls->defineFinalizeFunction(_SE(js_SomeClass_finalize));
    
    // 注册类型到 JS VirtualMachine 的操作
    cls->install();
    
    // JSBClassType 为 Cocos 引擎绑定层封装的类型注册的辅助函数,此函数不属于 ScriptEngine 这层
    JSBClassType::registerClass<ns::SomeClass>(cls);
    
    // 保存注册的结果,便于其他地方使用,比如类继承
    __jsb_ns_SomeClass_proto = cls->getProto();
    __jsb_ns_SomeClass_class = cls;
    
    // 为每个此 Class 实例化出来的对象附加一个属性
    __jsb_ns_SomeClass_proto->setProperty("yyy", se::Value("helloyyy"));
    
    // 注册静态成员变量和静态成员函数
    se::Value ctorVal;
    if (ns->getProperty("SomeClass", &ctorVal) && ctorVal.isObject())
    {
        ctorVal.toObject()->setProperty("static_val", se::Value(200));
        ctorVal.toObject()->defineFunction("static_func", _SE(js_SomeClass_static_func));
    }
    
    // 清空异常
    se::ScriptEngine::getInstance()->clearException();
    return true;
}

Step 4

然后点开 Classes 找到 jsb_module_register.cpp

在图中所示位置加两个头文件,其实就是刚才新建的那两个头文件

// jsb_module_register.cpp
// jsb step 4
#include "cocos/scripting/js-bindings/manual/jsb_test.hpp"
#include "cocos/scripting/js-bindings/manual/jsb_class_test.hpp"

Step 5

然后找到 jsb_register_all_modules 方法

在图中所示位置添加两句注册代码

// jsb_module_register.cpp
// jsb step 5
se->addRegisterCallback(js_register_jsbTest_jsbTest);
se->addRegisterCallback(js_register_ns_SomeClass);

Step 6

如图所示,点 cocos2d_libs.xcodeproj 看到 build phases

点开 Compile Sources 在里边添加 jsb_test.cpp 和 jsb_class_test.cpp

点开 Headers 在里边添加 jsb_test.hpp 和 jsb_class_test.hpp

Step 7

用 xcode 运行就能看到编写的 C++ 代码顺利被 js 调用

END.

还有一句,复制一下支付宝领个红包支持我一下会死么??????? :frowning:

mark

:+1:赞赞赞