Cocos Creator JSB [Lv.1]

Posted VermillionTear

tags:

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

摘要

本系列文章主要实操JSB的手动绑定,在官方教程的基础上,做了适当的修改,并增加了新的内容。
文中对相关知识点进行适当展开,不做深入研究。
以实际操作做为出发点,帮助读者快速实现并且掌握JSB手动绑定。

系列文章

JSB能做什么

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

环境

  • Cocos Creator 2.4.4
  • Visual Studio Community 2017

资源

准备工作

  1. 一张小姐姐的图片。没错!你没有看错,就是一张小姐姐的图片,我们要通过JSB跟小姐姐互动起来~
  2. 一张心形的图片。
  3. 创建Empty工程。
  4. 构建工程,
    在这里插入图片描述
    模板一定要选default,因为这样才会将cocos2dx的源码拷贝到发布路径下。我们需要修改cocos2dx的部分源码,从而实现JSB绑定。
    窗口大小调整为Cocos CreatorCanvas节点设置的设计分辨率大小。
    构建完成后,在发布路径会看到jsb-default目录。
    cocos2dx源码目录为发布路径/jsb-default/frameworks/cocos2d-x/。之后为了叙述方便,提及cocos2dx源码中的文件,如不做特殊说明,均以此目录作为根目录。

正式开始

对工程做一些修改

资源管理器
在这里插入图片描述
层级管理器
在这里插入图片描述

  1. 对节点的层级稍稍做了规范化,保证UI与代码分开,代码均挂载在Controller下对应的节点上。
  2. 创建JSBController.js脚本,并且挂载在JSBController节点上。

之后节点相关的设置请参考工程中的设置,文中不再赘述。
场景编辑器
在这里插入图片描述

如何互动

这回小姐姐一下子就出现在我们面前了,可是怎么跟她互动呢?
我们模拟小姐姐在C++层面,而我们在js层面。通过JSB搭建的桥梁,实现参数的相互传递,以及函数的相互调用。

小姐姐现身

我们在C++层面创建一个小姐姐的类。
cocos目录下创建myjsb目录,并在其中创建Goddess.hGoddess.cpp
Goddess.h

#ifndef __CC_GODDESS_H__
#define __CC_GODDESS_H__

#include <string>
#include "base/ccMacros.h"

namespace cocos2d { namespace myjsb {		// 命名空间,cocos2d::myjsb

    class CC_DLL Goddess 		// 单例类
    {
    public: 
        static Goddess* getInstance();		// 获取单例
        static void destroyInstance();		// 销毁单例
    protected: 
        static Goddess* _instance;		// 实例
    };

}}  // namespace cocos2d::myjsb

#endif    // __CC_GODDESS_H__

Goddess.cpp

#include "myjsb/Goddess.h"

namespace cocos2d { namespace myjsb {

    Goddess* Goddess::_instance = nullptr;    // 必须写,否则报错“无法解析的外部符号”。

	// 获取单例。
    Goddess* Goddess::getInstance()
    {
        if (_instance == nullptr)
        {
            _instance = new Goddess();
        }

        return _instance;
    }

	// 销毁单例。
    void Goddess::destroyInstance()
    {
        CC_SAFE_DELETE(_instance);
    }
    
}}  //  namespace cocos2d::myjsb

将这两个文件加入libcocos2d中,从而让它们编译进libcocos2d库中,
在这里插入图片描述在这里插入图片描述

与小姐姐互动的桥梁

cocos/scripting/js-bindings/auto目录下创建jsb_cocos2dx_myjsb_auto.hppjsb_cocos2dx_myjsb_auto.cpp
jsb_cocos2dx_myjsb_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_myjsb_Goddess_proto;
extern se::Class* __jsb_cocos2d_myjsb_Goddess_class;

bool js_register_cocos2d_myjsb_Goddess(se::Object* obj);
bool register_all_myjsb(se::Object* obj);
// 声明作为桥梁的函数。
// 桥梁函数的作用:
// 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_getInstance);

#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_cocos2dx_myjsb_auto.cpp

#include "scripting/js-bindings/auto/jsb_cocos2dx_myjsb_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 "myjsb/Goddess.h"

se::Object* __jsb_cocos2d_myjsb_Goddess_proto = nullptr;
se::Class* __jsb_cocos2d_myjsb_Goddess_class = nullptr;

// 桥梁函数,jsb.Goddess.getInstance()实际会调用到这里。
static bool js_cocos2d_myjsb_Goddess_getInstance(se::State &s) {
    const auto& args = s.args();	// 传递的参数。
    size_t argc = args.size();		// 参数的数量。
    CC_UNUSED bool ok = true;		// 参数转换是否成功的标志。

    if (argc == 0) {	// 需要0个参数。
    	// 不需要参数,也就没有了参数的转换部分。
        cocos2d::myjsb::Goddess* result = cocos2d::myjsb::Goddess::getInstance();	// 获取Goddess类的实例。
        // 将Goddess类的实例转换为se::Value,并赋值到s.rval。s.rval中的值就是返回给js层面的返回值。
        ok &= native_ptr_to_seval<cocos2d::myjsb::Goddess>((cocos2d::myjsb::Goddess*)result, &s.rval());
        SE_PRECONDITION2(ok, false, "js_cocos2d_myjsb_Goddess_getInstance : 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_getInstance);

bool js_register_cocos2d_myjsb_Goddess(se::Object* obj) {
    auto cls = se::Class::create("Goddess", obj, nullptr, nullptr);

	// 这里就是定义,jsb.Goddess 要暴露出一个 getInstance 函数,
	// jsb.Goddess.getInstance() 时,在 JSB 中要调用 js_cocos2d_myjsb_Goddess_getInstance
    cls->defineStaticFunction("getInstance", _SE(js_cocos2d_myjsb_Goddess_getInstance));

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

    __jsb_cocos2d_myjsb_Goddess_proto = cls->getProto();
    __jsb_cocos2d_myjsb_Goddess_class = cls;

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

bool register_all_myjsb(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();

	// 以下函数被调用之后,jsb.Goddess就可以使用了。
    js_register_cocos2d_myjsb_Goddess(ns);

    return true;
}

#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)

将这两个文件加入libcocos2d中,从而让它们编译进libcocos2d库中,
在这里插入图片描述在这里插入图片描述
由于myjsb是新增加的模块,所以需要在发布路径/jsb-default/frameworks/runtime-src/Classes/jsb_module_register.cpp中增加myjsb的注册逻辑,实际上就是调用register_all_myjsb
注意cocos/scripting/js-bindings/manual/目录下也有一个jsb_module_register.cpp,不要使用这个,
而是要使用发布路径/jsb-default/frameworks/runtime-src/Classes/目录下的。
jsb_module_register.cpp

...
#include "cocos/scripting/js-bindings/auto/jsb_cocos2dx_myjsb_auto.hpp"
...
se->addRegisterCallback(register_all_myjsb);
...

找到小姐姐

经过上述工作,我们在js层面就可以获取到小姐姐的实例了,
JSBController.js

let _goddess = null		// 小姐姐的实例。

cc.Class({
    extends: cc.Component,

    properties: {
        // TODO
    }, 

    onLoad () {
        _goddess = jsb.Goddess.getInstance()	// 获取小姐姐的实例。
    }, 
});

划重点

  • 构建工程时,模板要选择default
  • JSB手动绑定的一般流程:cocos/myjsb/下定义类,cocos/scripting/js-bindings/auto/下定义桥梁,发布路径/jsb-default/frameworks/runtime-src/Classes/jsb_module_register.cpp中注册桥梁。
  • 注意jsb_module_register.cpp的目录。
  • 绑定单例类的写法。

以上是关于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]