Cocos Creator JSB [Lv.3]

Posted VermillionTear

tags:

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

摘要

本文内容大部分源于官方文档,对其中一些比较重要的内容,以及有自己想法的内容做了适度的展开,意在帮助读者更加全面的了解JSB

资源

正式开始

为什么要使用JSB

为了让脚本层与C++层面进行交互,从而让脚本层可以控制一些高效的或是定制性较强的操作。

  • 虽然游戏的大部分逻辑都放到了脚本层,但是对于一些性能要求较高的操作(例如文件的读写,文件的加解密等)还是需要在C++层面完成。
  • 对于某些功能,各原生平台会有各自的实现方式,需要C++层面定义统一的接口,各原生平台自行实现功能。
  • 实际上cocos2dx引擎主要都是使用C++进行编写,js使用引擎的功能都是通过JSB来调用C++提供的接口。

基于以上几点,脚本层面想要使用这些功能,就需要通过JSB调用C++提供的接口。

cc.Sprite为例,在JSB中如果使用new操作符来调用cc.Sprite的构造函数,实际上在C++层会调用js_cocos2dx_Sprite_constructor函数。在这个C++函数中,会为这个精灵对象分配内存,并把它添加到自动回收池,然后调用JS层的_ctor函数来完成初始化。在_ctor函数中会根据参数类型和数量调用不同的init函数,这些init函数也是C++函数的绑定。
三层的方法对应关系如下:

javascriptJSBCocos2d-x
cc.Sprite.initWithSpriteFrameNamejs_cocos2dx_Sprite_initWithSpriteFrameNamecocos2d::Sprite::initWithSpriteFrameName
cc.Sprite.initWithSpriteFramejs_cocos2dx_Sprite_initWithSpriteFramecocos2d::Sprite::initWithSpriteFrame
cc.Sprite.initWithFilejs_cocos2dx_Sprite_initWithFilecocos2d::Sprite::initWithFile
cc.Sprite.initWithTexturejs_cocos2dx_Sprite_initWithTexturecocos2d::Sprite::initWithTexture

在这里插入图片描述

JSB能做什么

他能让js脚本与C++互相传递参数,互相调用函数。他搭建了js脚本与C++之间通讯的桥梁。

进行JSB绑定需要做什么

JSB绑定简单来讲就是在C++层实现一些类库,然后经过一些特定处理可以在JS端进行对应方法调用的过程。

构建工程

  1. 指定发布路径
  2. 模板选择default
  3. 构建工程。

模板一定要选default,因为这样才会将cocos2dx的源码拷贝到发布路径下。
我们需要修改cocos2dx的部分源码,从而实现JSB绑定。
cocos2dx源码目录为发布路径/jsb-default/frameworks/cocos2d-x/。之后为了叙述方便,提及cocos2dx源码中的文件,如不做特殊说明,均以此目录作为根目录。

创建类

cocos/模块目录下编写类.h类.cpp

绑定(搭建桥梁)

cocos/scripting/js-bindings/auto/模块目录下编写jsb_模块_auto.hppjsb_模块_auto.cpp
jsb_模块_auto.hpp

#pragma once
#include "base/ccConfig.h"

#if (CC_TARGET_PLATFORM == CC_PLATFORM_android || CC_TARGET_PLATFORM == CC_PLATFORM_ios || CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"

extern se::Object* __jsb_cocos2d_模块_proto;
extern se::Class* __jsb_cocos2d_模块_class;

bool js_register_模块_类(se::Object* obj);		// 注册类。
bool register_all_模块_类(se::Object* obj);		// 注册模块下所有的类。
SE_DECLARE_FINALIZE_FUNC(js_cocos2d_模块_类_finalize);		// 声明一个 JS 对象被 GC 回收后的回调函数。
SE_DECLARE_FUNC(js_cocos2d_模块_类_成员函数);	// 声明一个 JS 函数,一般在 .h 头文件中使用。
...

#endif //#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)

jsb_模块_auto.cpp

#include "scripting/js-bindings/auto/jsb_模块_auto.hpp"
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)

#include "scripting/js-bindings/manual/jsb_conversions.hpp"
#include "scripting/js-bindings/manual/jsb_global.h"
#include "模块/类.h"

se::Object* __jsb_cocos2d_模块_proto = nullptr;
se::Class* __jsb_cocos2d_模块_class = nullptr;

static bool js_cocos2d_模块_类_成员函数(se::State &s) {
    ...
}
SE_BIND_FUNC(js_cocos2d_模块_类_成员函数);	// 包装一个 JS 函数,可用于全局函数、类成员函数、类静态函数。

static bool js_cocos2d_模块_类_get_成员变量(se::State& s) {
    ...
}
SE_BIND_PROP_GET(js_cocos2d_模块_类_get_成员变量);	// 包装一个 JS 对象属性读取的回调函数

static bool js_cocos2d_模块_类_set_成员变量(se::State& s) {
    ...
}
SE_BIND_PROP_SET(js_cocos2d_模块_类_set_成员变量);	// 包装一个 JS 对象属性写入的回调函数

static bool js_cocos2d_模块_类_constructor(se::State& s) {
    ...
}
// 包装一个 JS 构造函数
SE_BIND_CTOR(js_cocos2d_模块_类_constructor, __jsb_cocos2d_模块_类_class, js_cocos2d_模块_类_finalize);

static bool js_cocos2d_模块_类_finalize(se::State& s) {
    ...
}
SE_BIND_FINALIZE_FUNC(js_cocos2d_模块_类_finalize);	// 包装一个 JS 对象被 GC 回收后的回调函数

bool js_register_模块_类(se::Object* obj) {
    auto cls = se::Class::create("类", obj, nullptr, nullptr);

	// 绑定 jsb.对象.函数 到 C++类的静态成员函数。
	// 一般用于 let foo = jsb.对象.getInstance()
    cls->defineStaticFunction("静态成员函数", _SE(js_cocos2d_模块_类_静态成员函数));
    // 绑定 jsb.对象.属性 到 C++类的SET和GET成员函数。
	// 一般用于 let foo = jsb.对象.属性 以及 jsb.对象.属性 = foo
    cls->defineProperty("成员变量", _SE(js_cocos2d_模块_类_get_成员变量), _SE(s_cocos2d_模块_类_set_成员变量));
    // 绑定 jsb.对象.函数 到 C++类的成员函数。
	// 一般用于 jsb.对象.fun()
    cls->defineFunction("成员函数", _SE(js_cocos2d_模块_类_成员函数));
    ...

    cls->install();
    // 将 se::Class::create 的 Goddess 与 C++ 实际的 Goddess 类对应起来。
    JSBClassType::registerClass<cocos2d::模块::>(cls);

    __jsb_cocos2d_模块_proto = cls->getProto();
    __jsb_cocos2d_模块_class = cls;

    se::ScriptEngine::getInstance()->clearException();
    return true;
}

bool register_all_模块(se::Object* obj)
{
    // Get the ns
    se::Value nsVal;
    if (!obj->getProperty("jsb", &nsVal))
    {
        se::HandleObject jsobj(se::Object::createPlainObject());
        nsVal.setObject(jsobj);
        obj->setProperty("jsb", nsVal);
    }
    se::Object* ns = nsVal.toObject();

    js_register_模块_类(ns);	// 调用上边的函数,注册类。
    ...
    
    return true;
}

桥梁做了下面这些工作:

接收js传递C++类型参数
---------------------------------->转换---------------------------------->
se::Value类型参数seval_to_C++类型调用C++类的成员函数
se::Value类型返回值接收C++类的成员函数传递
<----------------------------------转换<----------------------------------
通过s.rval传递C++类型_to_sevalC++类型返回值

实现自定义的类型转换(非必须)

如果在桥梁函数中,需要将自定义类型转换为se::Value,或是将se::Value转换为自定义类型,就需要在
cocos/scripting/js-bindings/manual/jsb_conversions.hppcocos/scripting/js-bindings/manual/jsb_conversions.cpp中编写转换的代码。
jsb_conversions.hpp

#include "模块/类.h"
bool seval_to_类(const se::Value& v, cocos2d::模块::* pt);

jsb_conversions.cpp

bool seval_to_类(const se::Value& v, cocos2d::模块::* pt)
{
    ...
    return true;
}

注册

如果是新建的模块,就需要在发布路径/jsb-default/frameworks/runtime-src/Classes/jsb_module_register.cpp中注册模块。

#include "cocos/scripting/js-bindings/auto/jsb_模块_auto.hpp"
se->addRegisterCallback(register_all_模块);

将新增的文件加入libcocos2d

类.h类.cppjsb_模块_auto.hppjsb_模块_auto.cpp都有可能是自己新建的文件,需要将他们编译进libcocos2d库。

windows

在这里插入图片描述
添加 -> 现有项

Android

需要修改发布路径/jsb-default/frameworks/cocos2d-x/cocos/Android.mk

LOCAL_SRC_FILES := \\
...
模块/类.cpp \\
scripting/js-bindings/auto/jsb_cocos2dx_模块_auto.cpp \\
...

LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) \\
					...
                    $(LOCAL_PATH)/模块 \\
                    ...

划重点

  • 为什么要使用JSB
  • 进行JSB绑定需要做什么。
  • 参考已有的绑定写法。

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

Cocos Creator JSB [Lv.3]

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]