Accessing display objects in nested groups

Hi fellow Corona developers,

I would like some input on how to access display objects that exists several levels down in nested groups. I am building an app with several scenes, and I am currently using the “Director” class to handle the different scenes in separate files. Now I need to access individual display objects in a scene. Each object has a “key” attribute set, so they could be easily accessed regardless of its numeric index.

Each scene is “built” into a local display group, which is then returned to director class which adds it as a subgroup to a display group, or to be 100% correct it actually appears as a group three levels down from the main group. So to access my object with key “sun”, I have this code:

local subgrp = mainGroup[1]  
local subgrp2 = subgrp[2]  
local subgrp3 = subgrp2[1]  
subgrp3.sun.isVisible=false  

Is there a quick way to address an object several layers down in the hierarchy? Something like “maingrp.subgrp.sub_subgrp.sun”?

/Leif [import]uid: 10329 topic_id: 3867 reply_id: 303867[/import]

Well, with your code, if you know the object will always be at that location, you can do this:

lua[1].isVisible=false[/lua]

But a better way is simply to name objects as you want them. Remember, display objects only get added to a display group if you either pass a reference to the group to their constructor (eg: display.newCircle( dispGrp, … ) ) or when you call :insert(dispObj) on the group object.
That doesn’t stop you using a normal table reference on them…

[lua]local mygroup = display.newGroup()
mygroup.myimg = display.newImage( mygroup, “someimg” )[/lua]

The second line there creates a name on the display group table which references the img, but also inserts the image into the group for inclusion in its hierarchy. That’s two very different operations.

Matt.
[import]uid: 8271 topic_id: 3867 reply_id: 11987[/import]

Thank you Matt, very helpful information!
Lua is all new to me, I knew there must be a way to reference things in one statement, just didn’t know the notation for it. Your second piece of information is also very interesting, I will see which way works best in my project.

/Leif [import]uid: 10329 topic_id: 3867 reply_id: 12054[/import]

That’s cool, glad I could help. I had a similar problem when I started but it looks like you’re up and running quicker. The thing to remember is that any dot notation value is also an index, so:

mytable[“hello”]

is equivalent to:

mytable.hello

Technically,

mytable[1]

would be the same as:

mytable.1

but that’s crazy talk because variables can’t start with numerals.

Take a really good look at the lua language page on this site but also at: http://www.lua.org/manual/5.1/manual.html
And definately try out: http://www.lua.org/cgi-bin/demo (I write code there when I don’t have access to my mac) and also check: http://developer.anscamobile.com/content/basic-functions#ipairs_t because the pairs() and ipairs() functions are very useful.

If you need to do some hard debugging, use this to dump lots of useful info about an object:

[lua]function dump(t)
for i in pairs(t) do
print(i,t[i],type(i))
end
end[/lua]

That prints the name, value and type of all the entries in a table, whether they are indexed or just arbitrarily assigned. As per my last email, try adding something to a display group then dumped the group’s values out - you’ll see the img added twice in the dump, but only once as an indexed value, of course.

Matt. [import]uid: 8271 topic_id: 3867 reply_id: 12059[/import]

Again very helpful information. I have done a lot of programming in Delphi and many other languages, but this table/index-based thinking is new, at least in this kind of usage. I see a lot of potential here, once I feel comfortable with it.

I have the book “Programming in Lua”, but will definitely check out those links as well, and the debugging dump code will for sure come in handy!

/Leif [import]uid: 10329 topic_id: 3867 reply_id: 12063[/import]

OK, I have made some progress but now I run into a problem that seems totally weird to me. This is my code, the key point here is the event listener for “enterFrame”. Notice that it is commented out in both locations, I will explain below.

require "scriptengine"  
  
local sceneGroup  
  
function startScene(sceneName)  
  
 local function btn\_play\_t ( event )  
 print (event.phase)  
 if event.phase == "ended" then  
 sceneGroup.play\_button.isVisible = false   
 --Runtime:addEventListener( "enterFrame", scriptengine.scriptAction );  
 end  
 end  
  
 director:changeScene(sceneName,"overFromRight");  
 scriptengine.setRestartFlag();  
 scriptengine.setSceneName(sceneName);  
  
 sceneGroup = ((mainGroup[1])[2])[1]  
 local btn\_play = display.newImageRect("images/play\_button.png",100,100)  
 btn\_play:addEventListener("touch",btn\_play\_t)  
 btn\_play.x = 240  
 btn\_play.y = 160  
 btn\_play.alpha = 0.5  
 sceneGroup:insert(btn\_play)  
 sceneGroup["play\_button"] = btn\_play  
 --Runtime:addEventListener( "enterFrame", scriptengine.scriptAction );  
  
end  

And then I have something like this in the scriptengine.scripAction function (simplified, as it’s a big module):

local sceneGroup  
local restartFlag  
  
function scriptAction(event)  
 if restartFlag == true then  
 restartFlag = false  
 tStart = event.time  
 sceneGroup = ((mainGroup[1])[2])[1]  
 print ("No of children: " .. sceneGroup.numChildren)  
 end  
end  

The idea here is to add a “start” button to my already prepared scene. Clicking the button will enable the event listener and the action will start. Problem is that if I enable the event listener when the button is clicked (first commented-out statement), I get this error:

scriptengine.lua:124: attempt to index upvalue ‘sceneGroup’ (a nil value)

But if I enable the event listener when I start the scene (second commented-out statement), everything works just fine. If I change the assignment of sceneGroup in the scriptAction function to this, it works fine again:

sceneGroup = ((mainGroup[1])[1])[1]  

So the whole display group hiearchy have changed just because I enabled an event listener in a different place in my code. Is there a logical explanation to this?

/Leif
[import]uid: 10329 topic_id: 3867 reply_id: 12274[/import]

As I can’t be sure what you’re doing at line 124 of scriptengine, but I’ll assume it’s the function you’ve provided but at a different line in your real file, I can’t really say - but I would assume you are trying to access the scenegroup value before it is given a value and that is happening because the scriptengine.lua has not been seen and initialised yet.

I can’t really be sure - but the best way is to try and dump values out all the way through your code until something pops up which is obviously wrong. My first print statement would be between lines 7 and 8 in your second listing, to print the value you are trying to assign to sceneGroup. That will be nil. So you need to find out why.

Unless I’m being thick, I can’t see any other reference to mainGroup in the code you’ve provided, so there must be a problem when that gets built, which is causing the array-like table indexing to break. Do you really need to use indexing or could you used named references? [import]uid: 8271 topic_id: 3867 reply_id: 12277[/import]

Sorry, yes the error in line 124 would equal line 9 in the example I provided.

The problem is that I am using the director class found in the code exchange, and this is where the mainGroup gets built. But it’s working fine and handles scene transitions very nicely, so I am sticking with it for now. I don’t think there is a problem with the mainGroup as such, it gets created way before this code executes.

And because of my use of the director class, I can’t use named references unless I start messing with the director class code. Ah well, since my workaround gets the job done, I guess there is no need to dig deeper into this right now. Thanks for looking at the code anyway! [import]uid: 10329 topic_id: 3867 reply_id: 12283[/import]

OT:

You can avoid this:

[lua]sceneGroup = ((mainGroup[1])[1])[1][/lua]

which is rather confusing, and write this instead:

[lua]sceneGroup = mainGroup[1][1][1][/lua]

Round brackets are useful when working with boolean evaluation, because they force Lua to evaluate a statement in place:

[lua]local state = ((myVar > 2 and myVar < 10) or (myOtherVar > 0)) – evaluates every brackets pair into a value

if state == true then
– code
end[/lua]
[import]uid: 5750 topic_id: 3867 reply_id: 12292[/import]

I would go with that for now unless you can do some more debugging and get print values out. I’m not familiar with the director code, I’m afraid, so I can’t help you there. [import]uid: 8271 topic_id: 3867 reply_id: 12299[/import]