如果是在cocos2d-x里才第一次使用lua的人,里面的extern.lua会带来很大的帮助,因为它帮lua这种勉强算是基于对象的语言实现了继承的功能。

同时,cocos2d-x里集成了tolua++,使自己编写的c++类可以通过配置,轻松地生成lua的绑定代码。

但不一定所有人都会把tolua++研究透,也不一定会所有人都把tolua++的使用方法搞明白。

当项目刚开始的时候,我们就发现了tolua++的释放机制其实是不算完善的。例如以下代码:

tolua_pushusertype(tolua_S,tolua_obj,"CCSize");
    tolua_register_gc(tolua_S,lua_gettop(tolua_S));
虽然表面上看来是注册了回收机制,但实际上,并不会立刻回收,而是到达一定峰值的时候才会回收,这样会导致游戏在某一个时刻出现卡顿的情况。

以后问题先不说,因为解决的手段是根据实际场景的。这段时间我们又发现了一个更严重的问题,由于我们仿照了basic.lua,另外建立了一个baseGameLib.lua,用来将自己写的c++代码绑定到lua,随着项目的推进,我们自己新写的c++代码越来越多,逻辑也越来越复杂,甚至我们还扩展了extern.lua里的class机制,保存了继承树,加入了类似java里isinstance这样的语法。终于隐藏在几种因素的综合下爆发了,游戏在运行中,竟然会出现原来A继承B,但在运行中却突然变成B继承A的问题。查了一个多星期,终于发现了问题所在。

在basic.lua文件的最上面,就有以下的代码:

local CCObjectTypes = {
    "CCObject","CCAction","CCImage","CCFiniteTimeAction",.......
    "
}
-- register CCObject types
for i = 1,#CCObjectTypes do
    _push_functions[CCObjectTypes[i]] = "toluafix_pushusertype_ccobject"
end

这段代码的作用是指定了有那些c++的类是继承CCObject的,然后只要在这里配置了,在tolua++生成的时候就会使用

toluafix_pushusertype_ccobject来返回给lua,否则,如果不在这里配置的所有c++类,一律使用
toluafix_pushusertype返回。

以下是toluafix_pushusertype的代码:

void tolua_pushusertype_internal (lua_State* L,void* value,const char* type,int addToRoot)
{
    if (value == NULL)
        lua_pushnil(L);
    else
    {
        luaL_getMetatable(L,type);                                 /* stack: mt */
        if (lua_isnil(L,-1)) { /* NOT FOUND Metatable */
            lua_pop(L,1);
            return;
        }
        lua_pushstring(L,"tolua_uBox");
        lua_rawget(L,-2);                                           /* stack: mt uBox */
        if (lua_isnil(L,-1)) {
            lua_pop(L,1);
            lua_pushstring(L,"tolua_uBox");
            lua_rawget(L,LUA_REGISTRYINDEX);
        };
        
        lua_pushlightuserdata(L,value);                             /* stack: mt uBox key<value> */
        lua_rawget(L,-2);                                           /* stack: mt uBox uBox[value] */
        
        if (lua_isnil(L,-1))
        {
            lua_pop(L,1);                                           /* stack: mt uBox */
            lua_pushlightuserdata(L,value);
            *(void**)lua_newuserdata(L,sizeof(void *)) = value;     /* stack: mt uBox value newud */
            lua_pushvalue(L,-1);                                    /* stack: mt uBox value newud newud */
            lua_insert(L,-4);                                       /* stack: mt newud uBox value newud */
            lua_rawset(L,-3);                  /* uBox[value] = newud,stack: mt newud uBox */
            lua_pop(L,1);                                           /* stack: mt newud */
            /*luaL_getMetatable(L,type);*/
            lua_pushvalue(L,-2);                                   /* stack: mt newud mt */
            lua_setMetatable(L,-2);                      /* update mt,stack: mt newud */
            
#ifdef LUA_VERSION_NUM
            lua_pushvalue(L,TOLUA_nopEER);             /* stack: mt newud peer */
            lua_setfenv(L,-2);                         /* stack: mt newud */
#endif
        }
        else
        {
            /* check the need of updating the Metatable to a more specialized class */
            lua_insert(L,-2);                                       /* stack: mt uBox[u] uBox */
            lua_pop(L,1);                                           /* stack: mt uBox[u] */
            lua_pushstring(L,"tolua_super");
            lua_rawget(L,LUA_REGISTRYINDEX);                        /* stack: mt uBox[u] super */
            lua_getMetatable(L,-2);                                 /* stack: mt uBox[u] super mt */
            lua_rawget(L,-2);                                       /* stack: mt uBox[u] super super[mt] */
            if (lua_istable(L,-1))
            {
                lua_pushstring(L,type);                             /* stack: mt uBox[u] super super[mt] type */
                lua_rawget(L,-2);                                   /* stack: mt uBox[u] super super[mt] flag */
                if (lua_toboolean(L,-1) == 1)                       /* if true */
                {
                    lua_pop(L,3);                                   /* mt uBox[u]*/
                    lua_remove(L,-2);
                    return;
                }
            }
            /* type represents a more specilized type */
            /*luaL_getMetatable(L,type);             // stack: mt uBox[u] super super[mt] flag mt */
            lua_pushvalue(L,-5);                    /* stack: mt uBox[u] super super[mt] flag mt */
            lua_setMetatable(L,-5);                /* stack: mt uBox[u] super super[mt] flag */
            lua_pop(L,3);                          /* stack: mt uBox[u] */
        }
        lua_remove(L,-2);    /* stack: uBox[u]*/
        
        if (0 != addToRoot)
        {
            lua_pushvalue(L,-1);
            tolua_add_value_to_root(L,value);
        }
    }
}


以下是toluafix_pushusertype_ccobject方法的代码:

TOLUA_API int toluafix_pushusertype_ccobject(lua_State* L,int refid,int* p_refid,void* ptr,const char* type)
{
    if (ptr == NULL || p_refid == NULL)
    {
        lua_pushnil(L);
        return -1;
    }
    
    if (*p_refid == 0)
    {
        *p_refid = refid;
        
        lua_pushstring(L,TOLUA_REFID_PTR_MAPPING);
        lua_rawget(L,LUA_REGISTRYINDEX);                           /* stack: refid_ptr */
        lua_pushinteger(L,refid);                                  /* stack: refid_ptr refid */
        lua_pushlightuserdata(L,ptr);                              /* stack: refid_ptr refid ptr */
        
        lua_rawset(L,-3);                  /* refid_ptr[refid] = ptr,stack: refid_ptr */
        lua_pop(L,1);                                              /* stack: - */
        
        lua_pushstring(L,TOLUA_REFID_TYPE_MAPPING);
        lua_rawget(L,LUA_REGISTRYINDEX);                           /* stack: refid_type */
        lua_pushinteger(L,refid);                                  /* stack: refid_type refid */
        lua_pushstring(L,type);                                    /* stack: refid_type refid type */
        lua_rawset(L,-3);                /* refid_type[refid] = type,stack: refid_type */
        lua_pop(L,1);                                              /* stack: - */
        
        //printf("[LUA] push CCObject OK - refid: %d,ptr: %x,type: %s\n",*p_refid,(int)ptr,type);
    }
    
    tolua_pushusertype_and_addtoroot(L,ptr,type);
    return 0;
}

通俗点的说,

toluafix_pushusertype是有隐患的,就好像我刚刚所说的,在各种复杂条件配合下,例如在某一段代码开了定时器,定时器逻辑里的对象又有复杂的继承树,并又使用了isinstance这种功能,或者还有其它一些我也想不明白的条件,就算明明在c++里创建了一个对象,并绑定到lua的时候,if (lua_isnil(L,-1))这段代码会返回false,直接导致报错。 所以,cocos2d-x的作者们很聪明地发明了toluafix_pushusertype_ccobject,只要我们完全按照basic.lua一样,将自己新建的继承CCObject的类,都配置在basic.lua里,就绝对不会出现我上面所说的问题。

cocos2d-x LUA 2.x里tolua++的一个隐患的更多相关文章

  1. ios – 如何使用Objective C类中的多个参数调用Swift函数?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  2. ios – Swift 4添加手势:覆盖vs @objc

    我想在我的视图中添加一个手势,如下所示:但是,在Swift4中,我的编译器给出了以下错误:建议添加@objc以将此实例方法公开给Objective-C.实现此目的的另一个选项将覆盖touchesBegan()函数并使用它来处理点击.我试图以“Swift”的方式做到这一点,而不必带入Obj-C.有没有纯粹的Swift方式来添加这个轻击手势而不使用@objc?

  3. ios – 将视频分享到Facebook

    我正在编写一个简单的测试应用程序,用于将视频从iOS上传到Facebook.由于FacebookSDK的所有文档都在Objective-C中,因此我发现很难在线找到有关如何使用Swift执行此操作的示例/教程.到目前为止我有这个在我的UI上放置一个共享按钮,但它看起来已禁用,从我读到的这是因为没有内容设置,但我看不出这是怎么可能的.我的getVideoURL()函数返回一个NSURL,它肯定包含视

  4. ios – 以编程方式在Swift中添加联系人

    我想在Swift中以编程方式添加联系人.我发现了一些Objective-C示例,但我没有让它们工作,甚至在Objective-C中也没有.我不希望这涉及到AddressBookUI,因为我想从我自己的UI中获取值.解决方法这是在Swift中添加联系人的快速方法.我在我的iPhone5iOS7.1上验证了它,因为我发现模拟器并不总是与我的手机对AB的东西相同.您可以添加一个按钮并指向此方法:顺便说一下–它假设你已经分配了一个地址簿var,你可以通过覆盖viewDidAppear来打开视图.它也会执行安全提示

  5. ios – 为目标c中的方法传递未知类型的参数,可能吗?

    是否可以将未知类型的参数传递给objective-C方法?在C#中你可以写实现这一点,但我知道Objective-C没有泛型,所以有没有其他方法可以在Objective-C中实现这一点?我需要这个,因为我想创建一个方法来改变不同对象的文本颜色,如UITextField和UIButton的占位符文本.所以我的计划是创建一个名为textWhite的方法,然后在此方法中检查对象的类型,然后运行匹配的代码以使文本颜色变为白色.解决方法是的,可以传递未知类型的参数.见下面的例子.请参考使用id对象的链接作为参数Us

  6. ios – Swift指针算术和解除引用;将一些类似C的地图代码转换为Swift

    我有一点似乎没有工作的Swift代码……解决方法您正在指定locationPointer指向新位置,但仍在下一行中使用ptr,并且ptr的值尚未更改.将您的最后一行更改为:或者你可以改变指向var的指针并推进它:

  7. ios – “禁用模块时使用’@import’”错误 – 启用模块和链接框架= YES

    我有一个使用CocoaPods并使用’SCLAlertView-Objective-C’窗格的项目.该pod使用@importUIKit;模块样式导入.我在目标和项目设置中将“启用模块(C&Objective-C)”和“自动链接框架”设置为YES.当模块被禁用时,我仍然得到“使用’@import’错误.有没有什么可以阻止Xcode能够启用模块,如使用.pch文件,任何链接器标志,或者我没有提到的任

  8. XCode 6.3立即在抛出的Objective-C异常上引发SIGABRT

    考虑以下目标-C代码在XCode6.2中,它按预期工作(记录“错误消息”).但是,由于我们升级到6.3,抛出行(throwstd::logic_error…)引发SIGABRT(堆栈跟踪仅包含_cxa_throw和_pthread_kill,超出applicationdidFinishLaunchingWithOptions)并导致应用程序崩溃.这只发生在我们的应用程序中–当我将完全相同的代码复制

  9. ios – 在swift框架中使用Bridging Headers时失败

    我正在做一个快速的框架,我想使用旧的目标c类.为此,我使用桥接头方法但是当我尝试构建时出现此错误:我将我的{PROJECT}-Bridging-Header.h添加到Swift编译器中的Objective-C桥接头–代码生成我怎么解决它?

  10. XCode 3.2 Ruby和Python模板

    在xcode3.2下,我的ObjectiveCPython/Ruby项目仍然可以打开更新和编译,但是你无法创建新项目.鉴于xcode3.2中缺少ruby和python的所有痕迹(即创建项目并添加新的ruby/python文件),是否有一种简单的方法可以再次安装模板?我发现了一些关于将它们复制到某个文件夹的信息,但我似乎无法让它工作,我怀疑文件夹的位置已经改变为3.2.解决方法3.2中的应用程序模板

随机推荐

  1. 【cocos2d-x 3.x 学习笔记】对象内存管理

    Cocos2d-x的内存管理cocos2d-x中使用的是上面的引用计数来管理内存,但是又增加了一些自己的特色。cocos2d-x中通过Ref类来实现引用计数,所有需要实现内存自动回收的类都应该继承自Ref类。下面是Ref类的定义:在cocos2d-x中创建对象通常有两种方式:这两中方式的差异可以参见我另一篇博文“对象创建方式讨论”。在cocos2d-x中提倡使用第二种方式,为了避免误用第一种方式,一般将构造函数设为protected或private。参考资料:[1]cocos2d-x高级开发教程2.3节[

  2. 利用cocos2dx 3.2开发消灭星星六如何在cocos2dx中显示中文

    由于编码的不同,在cocos2dx中的Label控件中如果放入中文字,往往会出现乱码。为了方便使用,我把这个从文档中获取中文字的方法放在一个头文件里面Chinese.h这里的tex_vec是cocos2dx提供的一个保存文档内容的一个容器。这里给出ChineseWords,xml的格式再看看ChineseWord的实现Chinese.cpp就这样,以后在需要用到中文字的地方,就先include这个头文件然后调用ChineseWord函数,获取一串中文字符串。

  3. 利用cocos2dx 3.2开发消灭星星七关于星星的算法

    在前面,我们已经在GameLayer中利用随机数初始化了一个StarMatrix,如果还不知道怎么创建星星矩阵请回去看看而且我们也讲了整个游戏的触摸事件的派发了。

  4. cocos2dx3.x 新手打包APK注意事项!

    这个在编译的时候就可以发现了比较好弄这只是我遇到的,其他的以后遇到再补充吧。。。以前被这两个问题坑了好久

  5. 利用cocos2dx 3.2开发消灭星星八游戏的结束判断与数据控制

    如果你看完之前的,那么你基本已经拥有一个消灭星星游戏的雏形。开始把剩下的两两互不相连的星星消去。那么如何判断是GameOver还是进入下一关呢。。其实游戏数据贯穿整个游戏,包括星星消除的时候要加到获得分数上,消去剩下两两不相连的星星的时候的加分政策等,因此如果前面没有做这一块的,最好回去搞一搞。

  6. 利用cocos2dx 3.2开发消灭星星九为游戏添加一些特效

    needClear是一个flag,当游戏判断不能再继续后,这个flag变为true,开始消除剩下的星星clearSumTime是一个累加器ONE_CLEAR_TIME就是每颗星星消除的时间2.连击加分信息一般消除一次星星都会有连击信息和加多少分的信息。其实这些combo标签就是一张图片,也是通过控制其属性或者runAction来实现。源码ComboEffect.hComboEffect.cpp4.消除星星粒子效果消除星星时,为了实现星星爆裂散落的效果,使用了cocos2d提供的粒子特效引擎对于粒子特效不了

  7. 02 Cocos2D-x引擎win7环境搭建及创建项目

    官网有搭建的文章,直接转载记录。环境搭建:本文介绍如何搭建Cocos2d-x3.2版本的开发环境。项目创建:一、通过命令创建项目前面搭建好环境后,怎样创建自己的Cocos2d-x项目呢?先来看看Cocos2d-x3.2的目录吧这就是Cocos2d-x3.2的目录。输入cocosnew项目名–p包名–lcpp–d路径回车就创建成功了例如:成功后,找到这个项目打开proj.win32目录下的Hello.slnF5成功了。

  8. 利用cocos2dx 3.2开发消灭星星十为游戏添加音效项目源码分享

    一个游戏,声音也是非常的重要,其实cocos2dx里面的简单音效引擎的使用是非常简单的。我这里只不过是用一个类对所有的音效进行管理罢了。Audio.hAudio.cpp好了,本系列教程到此结束,第一次写教程如有不对请见谅或指教,谢谢大家。最后附上整个项目的源代码点击打开链接

  9. 03 Helloworld

    程序都有一个入口点,在C++就是main函数了,打开main.cpp,代码如下:123456789101112131415161718#include"main.h"#include"AppDelegate.h"#include"cocos2d.h"USING_NS_CC;intAPIENTRY_tWinMain{UNREFERENCED_ParaMETER;UNREFERENCED_ParaMETER;//createtheapplicationinstanceAppDelegateapp;return

  10. MenuItemImage*图标菜单创建注意事项

    学习cocos2dx,看的是cocos2d-x3.x手游开发实例详解,这本书错误一大把,本着探索求知勇于发现错误改正错误的精神,我跟着书上的例子一起调试,当学习到场景切换这个小节的时候,出了个错误,卡了我好几个小时。

返回
顶部