思路

像所有语言一样,绑定回调主要是执行的任务执行到特定情形的时候,调用对用回调方法。 这里也一样。核心思路是,当c代码执行到特定特定情形的时候,调用lua的方法

我这里使用的是用lua_stack直接调用lua的方法,没有使用cocos2dx封装的那个dispatcher,因为熟悉那个格式太墨迹了

主要步骤如下

  • 缓存lua函数在lua环境中的引用
  • 在c代码的地方用c的方式设置好回调
  • 在c代码回调函数执行的时候,调用lua函数

实现

  • c代码绑定回调,调用lua函数

void ArmatureNode::registerMovementEventHandler(int handler)
{
unregisterMovementEventHandler(); //移除之前注册的监听
_movementHandler = handler; //缓存lua函数的引用 这个后边说 auto dispatcher = getCCEventDispatcher(); auto f = [this](cocos2d::EventCustom *event) //注册c代码形式的回调 这里用function做
{
auto eventData = (dragonBones::EventData*)(event->getUserData());
auto type = (int) eventData->getType();
auto movementId = eventData->animationState->name;
auto lastState = eventData->armature->getAnimation()->getLastAnimationState(); auto stack = cocos2d::LuaEngine::getInstance()->getLuaStack();
stack->pushObject(this, "db.ArmatureNode");
stack->pushInt(type);
stack->pushString(movementId.c_str(), movementId.size());
//通过LuaStack调用lua里的函数 最后一个参数设置参数个数
stack->executeFunctionByHandler(_movementHandler, 3);
}; dispatcher->addCustomEventListener(dragonBones::EventData::COMPLETE, f);
}
void ArmatureNode::unregisterMovementEventHandler(void)
{
if (0 != _movementHandler)
{
cocos2d::LuaEngine::getInstance()->removeScriptHandler(_movementHandler); //移除lua函数的绑定
_movementHandler = 0;
}
}
  • 提供lua函数绑定到c的方法

上边的这个函数直接用cocos里的genbinding.py 是无法正确生成lua里可调用的接口的,需要手动编写绑定方法

说这个得用到cocos2dx中提供的一个方法 toluafix_ref_function 会把一个lua栈中的方法转成一个int,以便c++中调用。我会在最后面说这个


int tolua_db_DBCCArmature_registerMovementEventHandler(lua_State* tolua_S)
{
if (NULL == tolua_S)
return 0;
int argc = 0; dragonBones::ArmatureNode* self = nullptr;
self = static_cast<dragonBones::ArmatureNode*>(tolua_tousertype(tolua_S,1,0)); //第一个参数 就是lua里的self argc = lua_gettop(tolua_S) - 1; if (1 == argc)
{
//第二个参数,就是lua里的function 这里要通过toluafix_ref_function这个函数映射成一个Int值
int handler = (toluafix_ref_function(tolua_S,2,0));
self->registerMovementEventHandler(handler); return 0;
}
return 0;
}
  • 将绑定方法绑定到lua环境里

int extends_ArmatureNode(lua_State* tolua_S)
{
lua_pushstring(tolua_S, "db.ArmatureNode");//之前db.ArmatureNode是通过脚本绑定在lua里。这里只做扩展
lua_rawget(tolua_S, LUA_REGISTRYINDEX);
if (lua_istable(tolua_S,-1))
{
lua_pushstring(tolua_S,"registerMovementEventHandler");
lua_pushcfunction(tolua_S,tolua_db_DBCCArmature_registerMovementEventHandler);
lua_rawset(tolua_S,-3);
} lua_pop(tolua_S, 1);
return 0;
}
  • lua里设置回调到c++

local arm = db.ArmatureNode:create("Dragon")
local animation = arm:getAnimation()
animation:gotoAndPlay("walk")
arm:registerMovementEventHandler(
function(...)
print(...)
end
)

-测试

打印回调输出,测试通过 userdata 8 walk


其他

  • toluafix_ref_function 以及 toluafix_get_function_by_refid

这两个方法是相互对应的 toluafix_ref_function这个方法在注册表上将一个lua的function与一个function_id生成映射 toluafix_get_function_by_refid 方法可以通过前一个方法生成的function_id来讲绑定的lua function放到栈顶


//
TOLUA_API int toluafix_ref_function(lua_State* L, int lo, int def)
{
if (!lua_isfunction(L, lo)) return 0;
s_function_ref_id++; //function_id 加1
lua_pushstring(L, TOLUA_REFID_FUNCTION_MAPPING);//在注册表上,存放luafunction 映射table 的key压栈
lua_rawget(L, LUA_REGISTRYINDEX); //获取方法映射表,放在栈顶
lua_pushinteger(L, s_function_ref_id); //function_id压栈
lua_pushvalue(L, lo); //lo有效处索引处是lua方法,lua方法拷贝,压栈 lua_rawset(L, -3); //生成映射
lua_pop(L, 1);
return s_function_ref_id;
}
TOLUA_API void toluafix_get_function_by_refid(lua_State* L, int refid)
{
lua_pushstring(L, TOLUA_REFID_FUNCTION_MAPPING); //存放luafunction 映射table 的key压栈
lua_rawget(L, LUA_REGISTRYINDEX); //获取方法映射表,放在栈顶
lua_pushinteger(L, refid); //function_id压栈
lua_rawget(L, -2); //获取到的luafunction 放到栈顶
lua_remove(L, -2); //
}
  • executeFunctionByHandler

    executeFunctionByHandler 这个方法只是通过toluafix_get_function_by_refid 获取到function 然后通过lua_pcall 方法调用 代码就不写了


疑惑

包括cocos2dx里的所有lua扩展(不是通过脚本直接生成lua接口的)都是通过注册表里扩展的 lua_rawget(tolua_S, LUA_REGISTRYINDEX); 我没完全看完lua里的userdata绑定过程,封装的太深了。

疑惑是绑定了以后也是userdata,但是扩展的时候拿到都是table。按我已看到的代码是userdata绑定到global表里的。这里的实现机制怎么回事,知道的,望不吝指点

转载请注明出处(http://www.cnblogs.com/boliu/p/4091274.html)

[cocos2dx] lua注册回调到c++的更多相关文章

  1. cocos2dx+lua注册事件函数详解 事件

    coocs2dx 版本 3.1.1 registerScriptTouchHandler             注册触屏事件 registerScriptTapHandler             ...

  2. cocos2dx+lua注册事件函数详解

    coocs2dx 版本 3.1.1 registerScriptTouchHandler 注册触屏事件 registerScriptTapHandler 注册点击事件 registerScriptHa ...

  3. 如何在cocos2dx lua的回调函数里面用self

    回调里的self是另一个不同的东西了,通常是触发回调的对象,或_G或nil ,视情况而定 我的 print(self) 输出 userdata function MyClass:sayFromCall ...

  4. 【转】关于cocos2dx+lua注册事件函数详解

    转载:http://www.taikr.com/article/1605 registerScriptTouchHandler 注册触屏事件registerScriptTapHandler注册点击事件 ...

  5. c++调用lua注册的带参数的回调

    main.cpp int lua_cb = LUA_REFNIL; int lua_cb_arg = LUA_REFNIL; int setcb(lua_State *L) { lua_pushval ...

  6. C中调用LUA回调(LUA注册表)

    实现原理: 通过将LUA中得回调函数存入LUA注册表中来保存LUA函数,然后在需要回调时从LUA注册表中取出LUA函数进行调用 下面是一些预备知识:(学习两个重要的函数) 原汁原味的英文解释的最透彻, ...

  7. cocos2d-x lua与c++简单交互

    cocos2d-x lua与c++简单交互 version: cocos2d-x 3.6 本文讲述lua与c++的一些简单交互: lua通过消息方式调用c++无参接口 c++调用lua带参接口 1.通 ...

  8. Cocos2d-x Lua Node与Node层级架构

    Cocos2d-x Lua采用层级(树形)结构管理场景.层.精灵.菜单.文本.地图和粒子系统等节点(Node)对象.一个场景包含了多个层,一个层又包含多个精灵.菜单.文本.地图和粒子系统等对象.层级结 ...

  9. cocos2d-x lua绑定解析

    花了几天时间看了下cocos2d-x lua绑定那块,总算是基本搞明白了,下面分三部分解析lua绑定: 一.lua绑定主要用到的底层函数 lua绑定其本质就是有一个公用的lua_Stack来进行C和L ...

随机推荐

  1. RHCE认证过程

    RHCE认证,即红帽认证工程师(Red Hat Certified Engineer)的简称,认证内容包括DNS.NFS.Samba.Sendmail.Postfix.Apache和关键安全功能的详细 ...

  2. java web面试技巧,数据库面试,java web轻量级开发面试教程

    我最近看到一本比较好的讲java web方面面试的书,java web轻量级开发面试教程. 其中不仅用案例和视频讲述了Spring MVC,Hibernate, ORM等方面的技巧,而且还实际讲到了面 ...

  3. 深入理解JVM(七)——性能监控工具

    前言 工欲善其事必先利其器,性能优化和故障排查在我们大都数人眼里是件比较棘手的事情,一是需要具备一定的原理知识作为基础,二是需要掌握排查问题和解决问题的流程.方法.本文就将介绍利用性能监控工具,帮助开 ...

  4. 报表 jasper + ireport5.6

    下载 iReport-5.6.0,jdk7,以及众多lib , 这里我提供下资源(我的百度云) 安装好iReport-5.6.0和jdk7,  在安装目录的\etc\ireport.conf,修改其中 ...

  5. C/C++资料网站

    1.C语言基础知识讲解 http://c-faq-chn.sourceforge.net/ccfaq/node1.html 2.C++参考手册中文版 http://zh.cppreference.co ...

  6. 纯css实现table表格固定列和表头,中间横向滚动的思路-附案例

    最近做的后台管理系统要处理大量的表格 原项目是采用的for循环加拼接字符串的方式实现;导致js代码一大堆;各种单引号和双引号的嵌套;让人头疼;遂引入vue.js;用v-for做模板渲染;工作量顿时减轻 ...

  7. java常量池中基本数据类型包装类的小陷阱

    想必大部分学过java的人都应该做过这种题目: public class Test { public static void main(String[] args) { //第一个字符串 String ...

  8. OCUpload的简单介绍与使用

     OCUpload (One Click Upload)译成中文就是一键上传的意思.它是JQuery的一个插件.   对于传统的文件上传,只能通过form表单,将enctype设置为multipart ...

  9. 【ACM小白成长撸】--计算单词个数

    我判断单词个数的方法,根据空格‘ ’的个数 分情况 当没有单词的时候 判断第一个符号,即a[0] == ‘\0’时,赋值给存储个数的数组 当遇到空格时,只有前面一个字符不是空格字符,后面一个字符不是空 ...

  10. 从网络获取json数据,使用imageloader获取网络图片资源并显示在ListView上

    http://www.93.gov.cn/93app/data.do?channelId=0&startNum=0 这是一个接口,通过这个接口来获取数据并解析 大体上就是把解析的数据还有图片u ...