Cocos Creator JSB [Lv.1]

Posted VermillionTear

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Cocos Creator JSB [Lv.1] 相关的知识,希望对你有一定的参考价值。

摘要

承接上文 Cocos Creator JSB [Lv.1] (1)
在上文中我们已经找到了小姐姐,本文在此基础上终于可以跟小姐姐进行互动啦~

系列文章

正式开始

小姐姐的昵称以及芳龄

创建两个文本框,用来显示小姐姐的昵称以及芳龄。
在这里插入图片描述在这里插入图片描述
JSBController.js中实现功能。

...
cc.Class({
    ...
    properties: {
        nickname: cc.Label, 	// 昵称
        age: cc.Label, 		// 芳龄
    }, 
	...
    start () {
        _goddess.nickname = 'Honey'	// 实际调用 Goddess 的 setName 函数。
        this.nickname.string = _goddess.nickname	// 实际调用 Goddess 的 getName 函数。

        _goddess.age = 20	// 实际调用 Goddess 的 setAge 函数。
        this.age.string = _goddess.age	// 实际调用 Goddess 的 getAge 函数。
    }, 
});

将节点挂载到脚本对应变量上。
在这里插入图片描述
接下来,要在C++层面实现相应的函数。
Goddess.h

...
    class CC_DLL Goddess 
    {
    public: 
        ...
        // 对应成员变量的 set 和 get 方法。
        inline const std::string& getNickName() const { return _nickname; };
        inline void setNickName(std::string& nickname) { _nickname = nickname; };
        inline const unsigned int getAge() const { return _age; };
        inline void setAge(unsigned int age) { _age = age; };
    protected: 
        ...
        std::string _nickname = "goddess";	// 昵称,随便写了个初始值。
        unsigned int _age = 18;		// 芳龄,随便写了个初始值。
    };
...

jsb_cocos2dx_myjsb_auto.hpp

...
// 声明作为桥梁的函数。
// 桥梁函数的作用:
// 1、将js层面传递过来的参数从se::Value类型转换为C++的类型。
// 2、调用对应的(在js_register_xxx中绑定的)C++类的成员函数,并传递转换后的的参数。
// 3、得到返回值,并将其转换为se::Value类型。
// 4、存入s.rval中,s.rval中的值就是返回给js层面的返回值。
SE_DECLARE_FUNC(js_cocos2d_myjsb_Goddess_getNickName);
SE_DECLARE_FUNC(js_cocos2d_myjsb_Goddess_setNickName);
SE_DECLARE_FUNC(js_cocos2d_myjsb_Goddess_getAge);
SE_DECLARE_FUNC(js_cocos2d_myjsb_Goddess_setAge);
...

jsb_cocos2dx_myjsb_auto.cpp

...
// 桥梁函数,let foo = goddess.nickname 时,实际会调用到这里。
static bool js_cocos2d_myjsb_Goddess_get_nickname(se::State& s) {
	// s.nativeThisObject() 可以获取到绑定的 C++ 类的实例。
    cocos2d::myjsb::Goddess* cobj = (cocos2d::myjsb::Goddess*)s.nativeThisObject();
    SE_PRECONDITION2(cobj, false, "js_cocos2d_myjsb_Goddess_get_nickname : Invalid Native Object");

    const auto& args = s.args();	// 传递的参数。
    size_t argc = args.size();		// 参数的数量。
    CC_UNUSED bool ok = true;		// 参数转换是否成功的标志。

    if (argc == 0) {	// 需要0个参数。
	    // 不需要参数,也就没有了参数的转换部分。
        std::string result = cobj->getNickName();	// 调用类的成员函数,并得到返回值。
        // 将返回值转换为 se::Value 类型,并赋值到s.rval,s.rval中的值就是返回给js层面的返回值。
        ok &= std_string_to_seval(result, &s.rval());
        SE_PRECONDITION2(ok, false, "js_cocos2d_myjsb_Goddess_get_nickname : Error processing arguments");
        return true;
    }
    
    // 传递的参数不正确时,打印的提示信息。
    SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 0);
    return false;
}
SE_BIND_PROP_GET(js_cocos2d_myjsb_Goddess_get_nickname);

// 桥梁函数,goddess.nickname = "foo" 时,实际会调用到这里。
static bool js_cocos2d_myjsb_Goddess_set_nickname(se::State& s) {
	// s.nativeThisObject() 可以获取到绑定的 C++ 类的实例。
    cocos2d::myjsb::Goddess* cobj = (cocos2d::myjsb::Goddess*)s.nativeThisObject();
    SE_PRECONDITION2(cobj, false, "js_cocos2d_myjsb_Goddess_set_nickname : Invalid Native Object");

    const auto& args = s.args();	// 传递的参数。
    size_t argc = args.size();		// 参数的数量。
    CC_UNUSED bool ok = true;		// 参数转换是否成功的标志。

    if (argc == 1) {	// 需要1个参数。
        std::string nickname;
        // 传递过来的昵称是 se::Value 的形式,将其转换为 std::string 。
        ok &= seval_to_std_string(args[0], &nickname);
        SE_PRECONDITION2(ok, false, "js_cocos2d_myjsb_Goddess_set_nickname : Error processing new value");
        cobj->setNickName(nickname);	// 调用类的成员函数,并传递转换后的参数。
        // 因为此成员函数没有返回值,所以不用对 s.rval 赋值。

        return true;
    }

	// 传递的参数不正确时,打印的提示信息。
    SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
    return true;
}
SE_BIND_PROP_SET(js_cocos2d_myjsb_Goddess_set_nickname);

// 桥梁函数,let foo = goddess.age 时,实际会调用到这里。
static bool js_cocos2d_myjsb_Goddess_get_age(se::State& s) {
	// s.nativeThisObject() 可以获取到绑定的 C++ 类的实例。
    cocos2d::myjsb::Goddess* cobj = (cocos2d::myjsb::Goddess*)s.nativeThisObject();
    SE_PRECONDITION2(cobj, false, "js_cocos2d_myjsb_Goddess_get_age : Invalid Native Object");

    const auto& args = s.args();	// 传递的参数。
    size_t argc = args.size();		// 参数的数量。
    CC_UNUSED bool ok = true;		// 参数转换是否成功的标志。

    if (argc == 0) {	// 需要0个参数。
	    // 不需要参数,也就没有了参数的转换部分。
        unsigned int result = cobj->getAge();	// 调用类的成员函数,并得到返回值。
        // 将返回值转换为 se::Value 类型,并赋值到s.rval,s.rval中的值就是返回给js层面的返回值。
        ok &= uint32_to_seval(result, &s.rval());
        SE_PRECONDITION2(ok, false, "js_cocos2d_myjsb_Goddess_get_age : Error processing arguments");
        return true;
    }
    
    // 传递的参数不正确时,打印的提示信息。
    SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 0);
    return false;
}
SE_BIND_PROP_GET(js_cocos2d_myjsb_Goddess_get_age);

// 桥梁函数,goddess.age = 123 时,实际会调用到这里。
static bool js_cocos2d_myjsb_Goddess_set_age(se::State& s) {
	// s.nativeThisObject() 可以获取到绑定的 C++ 类的实例。
    cocos2d::myjsb::Goddess* cobj = (cocos2d::myjsb::Goddess*)s.nativeThisObject();
    SE_PRECONDITION2(cobj, false, "js_cocos2d_myjsb_Goddess_set_age : Invalid Native Object");

    const auto& args = s.args();	// 传递的参数。
    size_t argc = args.size();		// 参数的数量。
    CC_UNUSED bool ok = true;		// 参数转换是否成功的标志。

    if (argc == 1) {	// 需要1个参数。
        unsigned int age = 0;
        // 传递过来的年龄值是 se::Value 的形式,将其转换为 unsigend int 。
        ok &= seval_to_uint32(args[0], (uint32_t*)&age);
        SE_PRECONDITION2(ok, false, "js_cocos2d_myjsb_Goddess_set_age : Error processing new value");
        cobj->setAge(age);	// 调用类的成员函数,并传递转换后的参数。
        // 因为此成员函数没有返回值,所以不用对 s.rval 赋值。

        return true;
    }

	// 传递的参数不正确时,打印的提示信息。
    SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
    return true;
}
SE_BIND_PROP_SET(js_cocos2d_myjsb_Goddess_set_age);

bool js_register_cocos2d_myjsb_Goddess(se::Object* obj) {
    ...
    // 这里就是定义,jsb.Goddess要暴露出一个nickname属性,
	// let foo = goddess.nickname 时,在JSB中要调用 js_cocos2d_myjsb_Goddess_get_nickname
	// goddess.nickname = "foo" 时,在JSB中要调用 js_cocos2d_myjsb_Goddess_set_nickname
    cls->defineProperty("nickname", _SE(js_cocos2d_myjsb_Goddess_get_nickname), _SE(js_cocos2d_myjsb_Goddess_set_nickname));
    // 这里就是定义,jsb.Goddess要暴露出一个age属性,
	// let foo = goddess.age 时,在JSB中要调用 js_cocos2d_myjsb_Goddess_get_age
	// goddess.age = 123 时,在JSB中要调用 js_cocos2d_myjsb_Goddess_set_age
    cls->defineProperty("age", _SE(js_cocos2d_myjsb_Goddess_get_age), _SE(js_cocos2d_myjsb_Goddess_set_age));
	...
}
...

构建工程,然后就可以在Visual Studio中编译运行起来了。
可以看到,我们在JSBController.js中为小姐姐设置的昵称以及芳龄都显示出来了。
在这里插入图片描述

打个招呼

创建一个文本框,用来显示小姐姐说的话。
创建一个按钮,用来跟小姐姐打招呼。
在这里插入图片描述在这里插入图片描述
JSBController.js中实现功能。

...
cc.Class({
    ...
    properties: {
        ...
        txt: cc.Label, 
    }, 
	...
    sayHi() {
        this.txt.string = _goddess.sayHi()
    }, 
});

将节点挂载到脚本对应变量上。
在这里插入图片描述
指定按钮点击后的回调函数。
在这里插入图片描述
接下来,要在C++层面实现相应的函数。
Goddess.h

...
    class CC_DLL Goddess 
    {
    public: 
        ...
		std::string sayHi();	// 打招呼的成员方法。
    protected: 
        ...
    };
...

Goddess.cpp

...
namespace cocos2d { namespace myjsb {
    ...
    // 就是简单返回一句话。
    std::string Goddess::sayHi() {
        std::string s = "Hi! Cutie~";

        return s;
    }
    
}}  //  namespace cocos2d::myjsb

jsb_cocos2dx_myjsb_auto.hpp

...
// 声明作为桥梁的函数。
// 桥梁函数的作用:
// 1、将js层面传递过来的参数从se::Value类型转换为C++的类型。
// 2、调用对应的(在js_register_xxx中绑定的)C++类的成员函数,并传递转换后的的参数。
// 3、得到返回值,并将其转换为se::Value类型。
// 4、存入s.rval中,s.rval中的值就是返回给js层面的返回值。
SE_DECLARE_FUNC(js_cocos2d_myjsb_Goddess_sayHi);
...

jsb_cocos2dx_myjsb_auto.cpp

...
// 桥梁函数,jsb.Goddess.sayHi() 时,实际会调用到这里。
static bool js_cocos2d_myjsb_Goddess_sayHi(se::State& s) {
	// s.nativeThisObject() 可以获取到绑定的 C++ 类的实例。
    cocos2d::myjsb::Goddess* cobj = (cocos2d::myjsb::Goddess*)s.nativeThisObject();
    SE_PRECONDITION2(cobj, false, "js_cocos2d_myjsb_Goddess_sayHi : Invalid Native Object");

    const auto& args = s.args();	// 传递的参数。
    size_t argc = args.size();		// 参数的数量。
    CC_UNUSED bool ok = true;		// 参数转换是否成功的标志。

    if (argc == 0) {	// 需要0个参数。
    	// 不需要参数,也就没有了参数的转换部分。
        std::string result = cobj->sayHi();	// 调用类的成员函数,并得到返回值。
        // 将返回值转换为 se::Value 类型,并赋值到s.rval,s.rval中的值就是返回给js层面的返回值。
        ok &= std_string_to_seval(result, &s.rval());
        SE_PRECONDITION2(ok, false, "js_cocos2d_myjsb_Goddess_sayHi : Error processing arguments");
        return true;
    }
    
    // 传递的参数不正确时,打印的提示信息。
    SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 0);
    return false;
}
SE_BIND_FUNC(js_cocos2d_myjsb_Goddess_sayHi);

bool js_register_cocos2d_myjsb_Goddess(se::Object* obj) {
    ...
    // 这里就是定义,jsb.Goddess要暴露出一个sayHi函数,
	// jsb.Goddess.sayHi() 时,在JSB中要调用 js_cocos2d_myjsb_Goddess_sayHi
    cls->defineFunction("sayHi", _SE(js_cocos2d_myjsb_Goddess_sayHi));
	...
}
...

构建工程,然后就可以在Visual Studio中编译运行起来了。
点击打招呼按钮,小姐姐真的回应我们了~
在这里插入图片描述

划重点

  • 桥梁函数的作用(4个步骤)。
  • 绑定成员变量作为JS对象的属性的写法(SETGET)。
  • 绑定成员函数(无参数,有返回值)的写法。

以上是关于Cocos Creator JSB [Lv.1] 的主要内容,如果未能解决你的问题,请参考以下文章

Cocos Creator JSB [Lv.1]

Cocos Creator JSB [Lv.1]

Cocos Creator JSB [Lv.1]

Cocos Creator JSB [Lv.1]

Cocos Creator JSB [Lv.1]

Cocos Creator JSB [Lv.1]