How can I use getChildren() in lua?

Hi,

I loaded a TMXFile with

cc = CCTMXTiledMap:tiledMapWithTMXFile(“level1.tmx”)

and then tried to obtain it’s children with cc:getChildren()

The problem is that I can’t find a way to access any of the children returned in lua… According to the definition getChildren should return CCArray<CCNode*> which has methods like count() and getObjectAtIndex but I can’t access any of those methods under lua…

What can I do?

Please try to call

cc.CCNode:getChildren()

It’s the rule by tolua++

Hi, thanks

If I do that:

cc = CCTMXTiledMap:tiledMapWithTMXFile(“level1.tmx”)
cc.CCNode:getChildren()

I get the following error:
attempt to index field ‘CCNode’ (a nil value)

on the other hand cc:getChildren() does call the correct function when debugging it, but the returned userdata in lua is not what I expect so if I do:

children = cc.getChildren()
print(children.count)
print(children.getIndexOfObject)

I just get nil…
I only get nil…

Sorry, bug #654 created.
CCTMXTiledMapCCNode isn’t exported automatically by tolua++ tools. I met this problem in CCLayerCCNode
If you’re very hurry to use this feature, please refer to this commit https://github.com/cocos2d/cocos2d-x/commit/737cfeba8229c943fa4816cdcf305a3645970fe1#lua/cocos2dx_support/LuaCocos2d.cpp

Please manually add these to LuaCocos2d.cpp

/* get function: __CCNode__ of class  cocos2d::CCTMXTiledMap */
#ifndef TOLUA_DISABLE_tolua_get_cocos2d__CCTMXTiledMap___CCNode__
static int tolua_get_cocos2d__CCTMXTiledMap___CCNode__(lua_State* tolua_S)
{
    cocos2d::CCTMXTiledMap* self = (cocos2d::CCTMXTiledMap*)  tolua_tousertype(tolua_S,1,0);
#ifndef TOLUA_RELEASE
    if (!self) tolua_error(tolua_S,"invalid 'self' in accessing variable '__CCNode__'",NULL);
#endif
#ifdef __cplusplus
    tolua_pushusertype(tolua_S,(void*)static_cast(self), "cocos2d::CCNode");
#else
    tolua_pushusertype(tolua_S,(void*)((cocos2d::CCNode*)self), "cocos2d::CCNode");
#endif
    return 1;
}
#endif //#ifndef TOLUA_DISABLE


add this line between  tolua_beginmodule(tolua_S,"CCTMXTiledMap")  and the first tolua_endmodule(tolua_S) below

tolua_variable(tolua_S,"__CCNode",tolua_get_cocos2d__CCTMXTiledMap___CCNode__, NULL);

In hello.lua:

animFrames = cocos2d.CCMutableArray_CCSpriteFrame__:new(2)
animFrames:addObject(frame0)
animFrames:addObject(frame1)

It can access method of CCMutableArray<CCSpriteFrame*> in lua.
Why can’t access methods of CCArray<CCNode*>?
Could you paste the error log?

Hi,

Thanks a lot for your help Minggo Zhang and Walzer Wang and sorry for the late answer…

The fix from Walzer does allow me to access CCNode but the array returned by getChildren still doesn’t allow me to access any of the methods…

So here’s my code:

self.cc = CCTMXTiledMap:tiledMapWithTMXFile("level1.tmx")
local mapSize = self.cc:getMapSize()
local tileSize = self.cc:getTileSize()

children = self.cc.__CCNode__:getChildren()
print("children")
print(children)
print(children.count)
print(children.getIndexOfObject)
print(children.CCObjectArray)

The result of the log is this:

children
userdata: 0x9d78274
nil
nil
nil
Cocos2d: executeScriptFile Error nRet = 1
Cocos2d: ...40-4ABE-80FA-C0DD9C9534CC/rpg_proto.app/lua/main.lua:200: attempt to call field 'count' (a nil value)

So none of the methods appear… It’s a pity that lua doesn’t allow more inspection of c userdata object to understand what is going on…

I’ve noticed that in LuaCocos2d.cpp CCMutableArray_CCNode__ is not defined. Could that be the source of the problem?

Ok, so I dug a bit more into the tolua code integration. The issue are the lines:

   cocos2d::CCMutableArray* tolua_ret = (cocos2d::CCMutableArray*)  self->getChildren();
    tolua_pushusertype(tolua_S,(void*)tolua_ret,"cocos2d::CCMutableArray");

in

/* method: getChildren of class  cocos2d::CCNode */
#ifndef TOLUA_DISABLE_tolua_Cocos2d_cocos2d_CCNode_getChildren00
static int tolua_Cocos2d_cocos2d_CCNode_getChildren00(lua_State* tolua_S)
{
#ifndef TOLUA_RELEASE
 tolua_Error tolua_err;
 if (
     !tolua_isusertype(tolua_S,1,"cocos2d::CCNode",0,&tolua_err) ||
     !tolua_isnoobj(tolua_S,2,&tolua_err)
 )
  goto tolua_lerror;
 else
#endif
 {
  cocos2d::CCNode* self = (cocos2d::CCNode*)  tolua_tousertype(tolua_S,1,0);
#ifndef TOLUA_RELEASE
  if (!self) tolua_error(tolua_S,"invalid 'self' in function 'getChildren'", NULL);
#endif
  {
   cocos2d::CCMutableArray* tolua_ret = (cocos2d::CCMutableArray*)  self->getChildren();
    tolua_pushusertype(tolua_S,(void*)tolua_ret,"cocos2d::CCMutableArray");
  }
 }
 return 1;
#ifndef TOLUA_RELEASE
 tolua_lerror:
 tolua_error(tolua_S,"#ferror in function 'getChildren'.",&tolua_err);
 return 0;
#endif
}

It declares the result of getChildren as “cocos2d::CCMutableArray<CCNode*>” but that type isn’t registered with tolua
Only CCMutableArray_CCObject*_ and CCMutableArray_CCSpriteFrame*_ are registered

So we need to add the CCMutableArray’s classes for other object types…

I also tried changing the getChildren() line to this

   cocos2d::CCMutableArray* tolua_ret = (cocos2d::CCMutableArray*)  self->getChildren();
    tolua_pushusertype(tolua_S,(void*)tolua_ret,"cocos2d::CCMutableArray");

and then doing something like this in the code

  children = self.cc.__CCNode__:getChildren()
  print("children")

  print(children:count())
  for i=0,children:count()-1,1  do
    local object = children:getObjectAtIndex(i)
    print(tolua.type(object))
    obj2  = tolua.cast(object, 'cocos2d::CCNode')
    print(tolua.type(obj2))
    print(obj2:getPosition().x)

  end

but then I get a EXC_BAD_ACCESS error when running getPosition() so I think tolua.cast is probably causing some problems…

Ok, I finally got it working… There were two issues:

First issue, CCNode~~>getChildren actually returns a CCArray* not a CCMutableArray<CCNode*>
So I changed this in LuaCocos2d.cpp
<pre>
cocos2d::CCArray* tolua_ret = self~~>getChildren();
tolua_pushusertype(tolua_S,(void**)tolua_ret,“cocos2d::CCArray”);
</pre>
The second problem I had was when doing the following code:
<pre>
n1 = cocos2d.CCNode:node
print.x)
n2 = cocos2d.CCNode:node
print.x)
a = n1:getChildren
n3 = a:objectAtIndex
n4 = tolua.cast
print)
print)
</pre>
It would fail with a EXC_BAD_ACCESS
Upon further debugging the problem was that n2 and n3 referenced a pointer with the address 0x5bcd6a0
but after the cast n4 referenced a pointer with the address 0x5bcd6a4
Another problem with using the Array like this with objectAtIndex returning a CCObject is that there’s no way to know in lua the subclass of the object we’re getting…
For this, one solution we could for CCArray is to use typeid to detect the correct class and return it correctly to lua…
For this we could use typeid… A quick test that I did that work in a very inelegant hackish way is this:
<pre>
cocos2d::CCObject** tolua_ret = self->objectAtIndex(index);
const char * ret_name = typeid(*tolua_ret).name();
printf(“%s”, ret_name);

if (strcmp(ret_name, “N7cocos2d6CCNodeE”) == 0 )
tolua_pushusertype(tolua_S,(void*)(CCNode*) tolua_ret,“cocos2d::CCNode”);
else
tolua_pushusertype(tolua_S,(void*)tolua_ret,“cocos2d::CCObject”);

}

But I think we could use redefine the Mtolua\_typeid macro to be able to automatically associate the correct lua class according to the subclass of the returned object…

Does :

cocos2d.CCTMXTiledMap:tiledMapWithTMXFile( “some.tmx” )

Still work ? Whatever I try I get : “child already added. It can’t be added again” being thrown as an assertion failure from within

CCNode::addChild(…)

For the record, this breakage is caused by commit:e73032b25d9e13be51fab06436d63a64baa31d2d But I don’t know what the correct resolution would be ?