zoukankan      html  css  js  c++  java
  • cocos2dx之lua绑定简析

    一、总原则:c++对象的生命期不依赖lua gc管理,手动创建的对象要手动销毁

    二、引擎层在设计上就是支持脚本概念的(也就是说脚本的使用是“侵入式”的),与lua打交道的代码都封在CCLuaEngine,引擎各处模块都通过它来调用脚本,如CNode::update会调用CCLuaEngine->executeSchedule来调用脚本的update handler,再如CNode::onEnter/onExit/onCleanup等都会调用CCLuaEngine->executeNodeEvent来调用脚本的event handler。

    三、lua脚本封装模块:

      scripting/lua/tolua:

        这是tolua++自己的运行层代码,各种基础函数,用来操作c++数据与lua数据

      scripting/lua/lua|luajit:

        这是lua和luajit的源码

      scripting/lua/cocos2dx_support/tolua_fix.h|c:

        这是cocos2d为实现自定义数据类型操作而添加的tolua扩展代码,具体见下

      scripting/lua/cocos2dx_support/LuaCocos2d.h|cpp:

        由tolua++解析pkg文件生成的粘合代码,几万行,包括了大量要导出的cocos2d逻辑类

      scripting/lua/cocos2dx_support/CLuaEngine/Value/Stack/Bridge.h|cpp:

        这些都是cocos2d自己处理与lua虚拟机交互的类了

      scripting/lua/cocos2dx_support/Lua_web_socket/Lua_extensions_CCB/CCBProxy.h|cpp:

        这些看起来像是各种扩展库的粘合代码,与LuaCocos2d.h性质一样,但是是手写的,至于为什么用这种形式,有什么特殊的地方,我还没搞清楚。

    四、每个c++对象在lua里以一个userdata表示,这个userdata上绑定了很多重要信息,如对象的类型,所有方法都是挂在类型上的。当多次将同一个c++ obj返回给lua时,为了避免创建多个不同的userdata,用了一个弱表来记录所有已进入过脚本的obj,即 objmap[ptr]=obj-userdata,第二次返回同一对象时查表可得。但由于这是一个弱表,里面的表项不是永久存在的,这极易引发一个经典bug:

    local spt = CCSprite:create("ui/green_btn.png")

    spt:setPosition(320,100);

    base_layer:addChild(spt)

    base_layer:registerScriptTouchHandler(function(et,x,y)

      --gc()

      --gc()

      local children = base_layer:getChildren()

      local cnt = children:count()

      for i=0,cnt-1 do

        local c = children:objectAtIndex(i)

        print("child ",i,tostring(c))

        local s = c:getContentSize()

        。。。

      end

    end)

      spt做为局部对象,在外层函数返回后就失去引用了,虽然它代表的c++ obj通过addChild的方式被其parent(也就是base_layer)引用住了,但是在脚本里这个类型为CCSprite的userdata一旦被gc后,在上述事件响应函数里通过children:objectAtIndex(i)再次获取该c++ obj时,因为在弱表里找不到记录,就会重新生成userdata,而这一次userdata的类型为CCObject!在它上面调getContentSize显然是找不到的。通常这种错误会因为gc的非即时性而掩盖一时,等到报错的时候反让人摸不着头脑了。测试的方法很简单,在获取对象之前强制gc一次,那么下面的代码当场就会报错了。

      解决的办法,要么把spt记在其它对象身上关联起来不被gc,要么在每次获取时,执行强制类型转换(但跟c++层的dynamic_cast一样易出弊端):

      c = tolua.cast(c,"CCNode")

    ……

    待续

    注:以上结论是错的,纯属未认真读代码就想当然了(主要是以前我自己做封装的时候是这么搞)。关于cocos2dx-lua里对象的生命期,请见我后面更新的文章(那个是认真读过代码后写的了。。。)

  • 相关阅读:
    考研打卡_Day049
    考研打卡_Day048
    【生活】2017 开始!
    朝花夕拾-android 自定义toast
    朝花夕拾-android 获取当前手机的内存卡状态和网络连接状态
    android media server 解析1-media player service 结构部分
    android binder 进程间通信机制6-Binder进程间通信机制的JAVA接口
    android binder 进程间通信机制5-Service注册和代理对象的获取
    android binder 进程间通信机制4-Service Manager
    android binder 进程间通信机制3-Binder 对象生死
  • 原文地址:https://www.cnblogs.com/wellbye/p/3288896.html
Copyright © 2011-2022 走看看