[RESOLVED] group:insert() changing an object's index order inconsistant

Currently I’m having a main object randomly “weaving” between parallax background objects when I tap a button.  I figured the easiest way to give the illusion would be to have the main object move up and down the group index list.  

Problem: the main object will move down the index list ( [3] -> [2] -> [1] ) but not up ( [1] -> [2] -> [3], etc)

Any help on my error below would be appreciated:

local btnTouch, enableBtn local group = display.newGroup() local bg1 = display.newGroup() bg1.name = "bg1" local bg2 = display.newGroup() bg1.name = "bg2" local bg3 = display.newGroup() bg1.name = "bg3" local mainObj = display.newCircl( 0, 0, 30 ) mainObj.name = "mainObj" mainObj.x = display.contentWidth / 2 mainObj.y = display.contentHeight / 2 group:insert( bg1 ) group:insert( bg2 ) group:insert( mainObj ) group:insert( bg3 ) local button = widget.newButton{ left = display.contentWidth - 200, top = display.contentHeight - 150, width = 100, height = 100, id = "btn", label = "Strafe", onPress = btnTouch } function enableBtn () button:setEnabled( true ) end function btnTouch( event ) local ran = math.random() local objPosition for i=1, group.numChildren do local name = group[i].name print( "group children "..i ..group[i].name ) if name == "mainObj" then objPosition = i end end -- set limits of mainObj's position within the group if objPosition == 1 then ran = 0.6 elseif objPosition == ( group.numChildren - 1 ) then ran = 0.3 end if ( "began" == event.phase) then button:setEnabled( false ) if ran \> 0.5 then objPosition = objPosition + 1 group:insert( objPosition, mainObj ) elseif ran \<= 0.5 then objPosition = objPosition - 1 group:insert( objPosition, mainObj ) end end return true end

environment info: OSX 10.8.5, build 2013.1135.

thanks for any help.

Just an observation, I’m confused as to why you set ran = math.random(), but then immediately you explicitly set ran to specific numbers (0.6 or 0.3).  

This was actually quite interesting.  I think it’s an undocumented quirk of how group:insert works when accepting an index.

Here’s a simpler test case:

[lua]

local stage = display.newGroup()

– Create some display groups

local groups = {}

for i=1,4 do

    groups[i] = display.newGroup()

    groups[i].name = “Group #” … i

    stage:insert(groups[i])

end

– Make a special reference to the third group so that we can move it around

local myGroup = groups[3]

– Function to print the display group names

local printNames = function()

    for i=1,stage.numChildren do

        print (i, stage[i].name)

    end

    print(" ")

end

printNames()            – Group #3 is in the third position, as expected

stage:insert(2,myGroup)

printNames()            – Group #3 is now in the second position, as expected

stage:insert(1,myGroup)

printNames()            – Group #3 is now in the first  position, as expected

stage:insert(2,myGroup)

printNames()            – Surprise!  Group #3 is still in the first position, not the second!

stage:insert(3,myGroup)

printNames()            – Surprise again!  Group #3 is now in the second position, not the third!

stage:insert(4,myGroup)

printNames()            – Surprise again!  Group #3 is now in the third position, not the fourth!

[/lua]

Effectively, what’s happening is that the group:insert(i, object) method doesn’t actually insert object to index i in group.  Instead, you might say it’s inserting object to the index before i.  Now, if the object’s current index is after i, it works as you’d expect: the object’s index becomes i.  But if the object’s current index is before i, it’s index after :insert will become i-1.

As a simple workaround, you could call object:toBack() before calling group:insert(i, object).  That’ll ensure that it’s new index does become i.

Weird behavior though, I’m surprised it’s never come up before.

  • Andrew

JonPM, the ran = 0.3 or 0.6 is to set limits so the mainObj will only fill the 1,2 or 3 index of the group.  It really isn’t necessary in the bit of code I put up there, but I left it in from my stripted-down version of code.

Andrew.  Thank you for not only figuring out how the group:insert(i, object) method works but for explaining it to me and offering a workaround.  Oddly, the object:toBack() didn’t seem to fix the issue, but the object:toFront() did. 

Again, thank you for insight!

-Tyson

Glad you got it working. Yes, I wrote my suggested workaround quickly without actually trying it myself. But you’re write that it should actually be toFront, not toBack.

environment info: OSX 10.8.5, build 2013.1135.

thanks for any help.

Just an observation, I’m confused as to why you set ran = math.random(), but then immediately you explicitly set ran to specific numbers (0.6 or 0.3).  

This was actually quite interesting.  I think it’s an undocumented quirk of how group:insert works when accepting an index.

Here’s a simpler test case:

[lua]

local stage = display.newGroup()

– Create some display groups

local groups = {}

for i=1,4 do

    groups[i] = display.newGroup()

    groups[i].name = “Group #” … i

    stage:insert(groups[i])

end

– Make a special reference to the third group so that we can move it around

local myGroup = groups[3]

– Function to print the display group names

local printNames = function()

    for i=1,stage.numChildren do

        print (i, stage[i].name)

    end

    print(" ")

end

printNames()            – Group #3 is in the third position, as expected

stage:insert(2,myGroup)

printNames()            – Group #3 is now in the second position, as expected

stage:insert(1,myGroup)

printNames()            – Group #3 is now in the first  position, as expected

stage:insert(2,myGroup)

printNames()            – Surprise!  Group #3 is still in the first position, not the second!

stage:insert(3,myGroup)

printNames()            – Surprise again!  Group #3 is now in the second position, not the third!

stage:insert(4,myGroup)

printNames()            – Surprise again!  Group #3 is now in the third position, not the fourth!

[/lua]

Effectively, what’s happening is that the group:insert(i, object) method doesn’t actually insert object to index i in group.  Instead, you might say it’s inserting object to the index before i.  Now, if the object’s current index is after i, it works as you’d expect: the object’s index becomes i.  But if the object’s current index is before i, it’s index after :insert will become i-1.

As a simple workaround, you could call object:toBack() before calling group:insert(i, object).  That’ll ensure that it’s new index does become i.

Weird behavior though, I’m surprised it’s never come up before.

  • Andrew

JonPM, the ran = 0.3 or 0.6 is to set limits so the mainObj will only fill the 1,2 or 3 index of the group.  It really isn’t necessary in the bit of code I put up there, but I left it in from my stripted-down version of code.

Andrew.  Thank you for not only figuring out how the group:insert(i, object) method works but for explaining it to me and offering a workaround.  Oddly, the object:toBack() didn’t seem to fix the issue, but the object:toFront() did. 

Again, thank you for insight!

-Tyson

Glad you got it working. Yes, I wrote my suggested workaround quickly without actually trying it myself. But you’re write that it should actually be toFront, not toBack.