学习Cocos2d-x Lua:Lua Binding实现C++里访问Lua的自定义对象

2015年03月24日 11:04 0 点赞 0 评论 更新于 2025-11-21 18:23

在这个系列中,我们主要聚焦于学习Cocos2d-x Lua,总结Lua开发过程中涉及的知识点,以及探讨如何在开发过程中使用Cocos Code IDE。本篇文章将详细讲解如何通过Lua Binding实现C++里访问Lua的自定义对象。

LUABinding概述

LUABinding相较于JSBinding更为简单。无论是使用脚本自动绑定,还是手动编写绑定代码,都能够轻松实现在Lua中访问C++的类和对象。然而,如果想要在C++里访问Lua里的自定义类和对象,则需要对C++代码进行一些修改。

应用场景

假设在Lua里有一个类MyLayer,它继承了CCLayer,并添加了abcd这4个属性。在Lua里创建一个MyLayer的实例对象,并将其添加到当前的Scene中。然后,当通过Scene.getChildByTag方法获取这个MyLayer的实例对象时,会发现自定义属性abcd都消失了。这是因为调用tolua_fix_pushusertype_ccobject(tolua_S, nID, pLuaID, (void*)tolua_ret, "CCNode")返回的是一个CCNode。以下是LuaCocos2d.cpp里的相关代码:

static int tolua_Cocos2d_CCNode_getChildByTag00(lua_State* tolua_S)
{
#ifndef TOLUA_RELEASE
tolua_Error tolua_err;
if (
!tolua_isusertype(tolua_S, 1, "CCNode", 0, &tolua_err) ||
!tolua_isnumber(tolua_S, 2, 0, &tolua_err) ||
!tolua_isnoobj(tolua_S, 3, &tolua_err)
)
goto tolua_lerror;
else
#endif
{
CCNode* self = (CCNode*)tolua_tousertype(tolua_S, 1, 0);
int tag = ((int)tolua_tonumber(tolua_S, 2, 0));
#ifndef TOLUA_RELEASE
if (!self) tolua_error(tolua_S, "invalid 'self' in function 'getChildByTag'", NULL);
#endif
{
CCNode* tolua_ret = (CCNode*)self->getChildByTag(tag);
int nID = (tolua_ret) ? (int)tolua_ret->m_uID : -1;
int* pLuaID = (tolua_ret) ? &tolua_ret->m_nLuaID : NULL;
tolua_fix_pushusertype_ccobject(tolua_S, nID, pLuaID, (void*)tolua_ret, "CCNode");
}
}
return 1;
#ifndef TOLUA_RELEASE
tolua_lerror:
tolua_error(tolua_S, "#ferror in function 'getChildByTag'.", &tolua_err);
return 0;
#endif
}

解决方法

步骤a:注册自定义类

首先,调用tolua_usertype(tolua_S, "MyLayer")来注册自定义类。这句代码可以添加在任何能够调用lua_State*这个指针的地方,但必须在初始化时仅调用一次。

步骤b:扩展getChildByTag方法

将以下代码添加到LuaCocos2d.cpp中,具体位置可根据实际情况安排:

// 扩展了getChildByTag,可以返回lua的对象,by lizc
/* method: getChildByTag of class  CCNode */
#ifndef TOLUA_DISABLE_tolua_Cocos2d_CCNode_getChildByTag01
static int tolua_Cocos2d_CCNode_getChildByTag01(lua_State* tolua_S)
{
#ifndef TOLUA_RELEASE
tolua_Error tolua_err;
if (
!tolua_isusertype(tolua_S, 1, "CCNode", 0, &tolua_err) ||
!tolua_isnumber(tolua_S, 2, 0, &tolua_err) ||
(!tolua_isvaluenil(tolua_S, 3, &tolua_err) && !tolua_isstring(tolua_S, 3, 0, &tolua_err)) ||
!tolua_isnoobj(tolua_S, 4, &tolua_err)
)
goto tolua_lerror;
else
#endif
{
CCNode* self = (CCNode*)tolua_tousertype(tolua_S, 1, 0);
int tag = ((int)tolua_tonumber(tolua_S, 2, 0));
const char* userTypeName = ((const char*)tolua_tostring(tolua_S, 3, 0));
#ifndef TOLUA_RELEASE
if (!self) tolua_error(tolua_S, "invalid 'self' in function 'getChildByTag'", NULL);
#endif
{
CCNode* tolua_ret = (CCNode*)self->getChildByTag(tag);
int nID = (tolua_ret) ? (int)tolua_ret->m_uID : -1;
int* pLuaID = (tolua_ret) ? &tolua_ret->m_nLuaID : NULL;
tolua_fix_pushusertype_ccobject(tolua_S, nID, pLuaID, (void*)tolua_ret, userTypeName);
}
}
return 1;
#ifndef TOLUA_RELEASE
tolua_lerror:
return tolua_Cocos2d_CCNode_getChildByTag00(tolua_S);
#endif
}
#endif // #ifndef TOLUA_DISABLE

步骤c:添加函数绑定

将以下代码添加到tolua_function(tolua_S, "getChildByTag", tolua_Cocos2d_CCNode_getChildByTag00)下面,以便于管理:

tolua_function(tolua_S, "getChildByTag", tolua_Cocos2d_CCNode_getChildByTag01);

使用方法

-- MyLayer必须继承自C++的某个类,这里就是继承CCLayer
local myLayer = MyLayer:create()
myLayer.a = 1
myLayer.b = 2
local scene = CCScene:create()
scene:addChild(myLayer, 0, 0)
myLayer = scene:getChildByTag(0, "MyLayer")
myLayer = tolua.cast(myLayer, "MyLayer")
cclog("myLayer.a" .. myLayer.a)
cclog("myLayer.b" .. myLayer.b)

通过以上步骤,就可以在C++里访问Lua的自定义对象,并保留其自定义属性。

作者信息

boke

boke

共发布了 3994 篇文章