返回「计算机、信息技术与工程」

Cocos2dx binding

更多
Markdown 结构化数据
本文目录 5 个章节

Cocos2dx binding

# Cocos2dx binding

JSB

// MyApiJSB.cpp
#include "scripting/js-bindings/manual/ScriptingCore.h"
#include "MyApi.h"

static bool js_myapi_echo(JSContext* cx, uint32_t argc, jsval* vp) {
    if (argc == 1) {
        JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
        std::string s;
        if (args.get(0).isString()) {
            JS::RootedString rs(cx, args.get(0).toString());
            s = JS_EncodeStringToUTF8(cx, rs);
        } else return false;

        auto out = MyApi::echo(s);
        JS::RootedString jsOut(cx, JS_NewStringCopyZ(cx, out.c_str()));
        args.rval().set(STRING_TO_JSVAL(jsOut));
        return true;
    }
    return false;
}

static void bind_myapi(JSContext* cx, JS::HandleObject global) {
    static JSFunctionSpec specs[] = {
        JS_FN("echo", js_myapi_echo, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),
        JS_FS_END
    };
    JS::RootedObject ns(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
    JS::RootedValue  v(cx, OBJECT_TO_JSVAL(ns));
    JS_SetProperty(cx, global, "myapi", v);
    JS_DefineFunctions(cx, ns, specs);
}

// somewhere in startup (e.g., AppDelegate)
auto se = ScriptingCore::getInstance();
if (auto cx = se->getGlobalContext()) {
    JS::RootedObject g(cx, se->getGlobalObject());
    bind_myapi(cx, g);
} else {
    se->addRegisterCallback(bind_myapi);
}

JS 端即可:

myapi.echo("hello"); // -> "hello"

Lua

1) 最小可用 C++ 代码(MyLuaBindings.cpp

// MyLuaBindings.cpp —— 加入到你的原生工程参与编译
#include "cocos2d.h"
#include "scripting/lua-bindings/manual/CCLuaEngine.h"
#include "tolua++.h"   // 若报未定义的 tolua_*,补这个头

using namespace cocos2d;

#define MY_LUA_NS "myapi"   // Lua 侧的命名空间:myapi.xxx

// —— 示例的原生状态(仅演示)——
namespace MyNative {
    static int value = 0;
    static void        setValue(int v) { value = v; }
    static int         getValue()      { return value; }
    static std::string greet(const char* name) {
        return std::string("Hello, ") + (name ? name : "");
    }
}

// 1) 绑定函数:入参校验 + 业务调用 + 压回返回值数量

// myapi.setValue(number)
static int lua_myapi_setValue(lua_State* L) {
    int argc = lua_gettop(L);
    if (argc != 1 || !lua_isnumber(L, 1)) {
        CCLOGERROR("myapi.setValue(number) expects 1 number");
        return 0;
    }
    MyNative::setValue((int)lua_tointeger(L, 1));
    return 0; // 返回 0 个值
}

// local v = myapi.getValue()
static int lua_myapi_getValue(lua_State* L) {
    lua_pushinteger(L, MyNative::getValue());
    return 1; // 返回 1 个值
}

// local s = myapi.greet("Cocos")
static int lua_myapi_greet(lua_State* L) {
    const char* name = luaL_checkstring(L, 1);        // 不符会抛 Lua 错误
    std::string s = MyNative::greet(name);
    lua_pushlstring(L, s.c_str(), s.size());
    return 1;
}

// 2) 把函数注册进 Lua 命名空间:myapi
static void bindMyLuaFunctions(lua_State* L) {
    if (!L) { CCLOGERROR("bindMyLuaFunctions: null lua_State"); return; }

    lua_getglobal(L, "_G");                 // stack: ... _G
    if (lua_istable(L, -1)) {
        tolua_open(L);
        tolua_module(L, MY_LUA_NS, 0);
        tolua_beginmodule(L, MY_LUA_NS);

        tolua_function(L, "setValue", lua_myapi_setValue);
        tolua_function(L, "getValue", lua_myapi_getValue);
        tolua_function(L, "greet",    lua_myapi_greet);

        tolua_endmodule(L);
    }
    lua_pop(L, 1);                          // pop _G
}

// 3) 对外导出一个“注册入口”,在启动时调用一次
void registerMyLuaBindings() {
    auto engine = LuaEngine::getInstance();
    if (!engine) { CCLOGERROR("LuaEngine not found"); return; }
    bindMyLuaFunctions(engine->getLuaStack()->getLuaState());
}

2) 在启动流程里调用一次

// AppDelegate.cpp
bool AppDelegate::applicationDidFinishLaunching() {
    // ... 你的初始化 ...
    registerMyLuaBindings();  // ★ 注册 Lua 绑定
    // ... 继续加载 Lua 脚本等 ...
    return true;
}

3) Lua 侧用法示例

myapi.setValue(42)
print("value =", myapi.getValue())     -- 42
print(myapi.greet("Cocos"))            -- "Hello, Cocos"