Positional differences when spawning display objects in loop

Hello everyone,

so while building a mobile game with Corona SDK i am encountering some problems now and then. One of them I didn’t seem to solve :

When spawning display objects in a loop, there seems to randomly appear a positional difference between two of the objects in a row.

At first, I thought this was due to large chunks of code that were executed between the actual spawning and the start of the transition, but then I managed to reproduce the same problem in few lines :

hen spawning display objects in a loop, there seems to randomly appear a positional difference between two of the objects in a row.

At first, I thought this was due to large chunks of code that were executed between the actual spawning and the start of the transition, but then I managed to reproduce the same problem in few lines :

local rectangleLoopTimer;
local counter = 0;
local rectangleArray = {}

local function rectangleLoop()

counter = counter + 1

local thisRectangle = display.newRect(1, 1, 216, 400)
thisRectangle.anchorX = 0

table.insert(rectangleArray, thisRectangle)

transition.to(

thisRectangle,

{

time = 5000,
x = thisRectangle.x + 1080,

onComplete = function()

display.remove(thisRectangle)
table.remove(rectangleArray, counter)

end

}

)

end

rectangleLoopTimer = timer.performWithDelay(985, rectangleLoop, 0)

If one executes this, then one sees what I mean, so what do you think why this happens? I appreciate every answer!

Greetings, Nils

@19Nils92,

  1. Welcome to the community.

  2. Please help us to help you and always remember to use code blocks when posting code.

formatyourcode.jpg

  1. Here is a repost of your code for others who want to help.

    local rectangleLoopTimer; local counter = 0; local rectangleArray = {} local function rectangleLoop() counter = counter + 1 local thisRectangle = display.newRect(1, 1, 216, 400) thisRectangle.anchorX = 0 table.insert(rectangleArray, thisRectangle) transition.to( thisRectangle, { time = 5000, x = thisRectangle.x + 1080, onComplete = function() display.remove(thisRectangle) table.remove(rectangleArray, counter) end } ) end 

  2. I’ll look at this shortly, but I wanted to respond right away with a clean post for other readers.

First, your code is pretty good.  However it has a few small issues I’d like to change for you:

  • Parentheses are optional.  I removed them, because they are just extra/unnecessary typing.
    • I only use them when concatenating separate lines of code to shorten things up.
  • table.* calls - Not the best way to do this.  See what I have done.
  • New onComplete every time you call transition.  Also not great.
  • display.remove() instead of removeSelf() - You are awesome.  I so hate removeSelf()

I ended up with this:

local rectangleLoopTimer local counter = 0 local rectangleArray = {} function table.count( tbl ) local count = 0 for k,v in pairs(tbl) do count = count + 1 end return count end local function onComplete( self ) rectangleArray[self] = nil display.remove( self ) print("Rectangles left in array: ", table.count( rectangleArray ) ) end local function rectangleLoop() local thisRectangle = display.newRect(1, 1, 216, 400) thisRectangle.anchorX = 0 thisRectangle.onComplete = onComplete rectangleArray[thisRectangle] = thisRectangle transition.to( thisRectangle, { time = 5000, x = thisRectangle.x + 1080, thisRectangle } ) end local rectangleLoopTimer = timer.performWithDelay(985, rectangleLoop, 0)

After running it, I see what (I think) you are talking about.  

You are worried about the occasional gaps that occur?  

If so, it is the solution you are using.  It is wrong, because you are making an assumption about time.  All events actually happen on a frame based demarkation.  So, if your timer doesn’t line up perfectly with a frame you’ll get a generation gap.

So, what is the right solution… Give me a moment and I’ll get back to you.

The trick is to keep everything in the same ‘context’.

Mixing timers with transitions is a bad move.

This is the best ‘hack’ I could come up with on short notice, but I would not do this in a real game.  Sorry.

function table.count( tbl ) local count = 0 for k,v in pairs(tbl) do count = count + 1 end return count end local counter = 0 local rectangleArray = {} local lastBlock local speed = 200 -- Pixels per second local getTimer = system.getTimer local blockMover local blockSpawner blockMover = function ( self ) local curTime = getTimer() local dt = curTime - self.lastTime self.lastTime = curTime if( dt \>= 5000 ) then Runtime:removeEventListener( "enterFrame", thisRectangle ) rectangleArray[self] = nil display.remove(self) return end self.x = self.x + speed \* dt / 1000 -- Spawn a new block if( self.spawn and self.x \> -50 and self.x \< 0 ) then self:spawn() end end blockSpawner = function( self ) local thisRectangle = display.newRect( 1, 1, 216, 400) thisRectangle.anchorX = 0 thisRectangle.lastTime = getTimer() thisRectangle.enterFrame = blockMover thisRectangle.spawn = blockSpawner if( self ) then self.spawn = nil thisRectangle.x = self.x - 216 end Runtime:addEventListener( "enterFrame", thisRectangle ) rectangleArray[thisRectangle] = thisRectangle print( "Rectangles in array: " .. tostring(table.count( rectangleArray )) .. " @ " .. tostring( system.getTimer() ) ) return thisRectangle end local tmp = blockSpawner() tmp:spawn()

Note: I am working on a solution for this exact kind of mechanic, but:

  1. It isn’t quite ready for release (one or two days left).
  2. It is paid.
  3. It requires SSK2.

However, if this looks cool, keep your eyes open for my upcoming announcement.

https://www.youtube.com/watch?v=4b9CFxTTpaY&feature=youtu.be

@19Nils92,

  1. Welcome to the community.

  2. Please help us to help you and always remember to use code blocks when posting code.

formatyourcode.jpg

  1. Here is a repost of your code for others who want to help.

    local rectangleLoopTimer; local counter = 0; local rectangleArray = {} local function rectangleLoop() counter = counter + 1 local thisRectangle = display.newRect(1, 1, 216, 400) thisRectangle.anchorX = 0 table.insert(rectangleArray, thisRectangle) transition.to( thisRectangle, { time = 5000, x = thisRectangle.x + 1080, onComplete = function() display.remove(thisRectangle) table.remove(rectangleArray, counter) end } ) end 

  2. I’ll look at this shortly, but I wanted to respond right away with a clean post for other readers.

First, your code is pretty good.  However it has a few small issues I’d like to change for you:

  • Parentheses are optional.  I removed them, because they are just extra/unnecessary typing.
    • I only use them when concatenating separate lines of code to shorten things up.
  • table.* calls - Not the best way to do this.  See what I have done.
  • New onComplete every time you call transition.  Also not great.
  • display.remove() instead of removeSelf() - You are awesome.  I so hate removeSelf()

I ended up with this:

local rectangleLoopTimer local counter = 0 local rectangleArray = {} function table.count( tbl ) local count = 0 for k,v in pairs(tbl) do count = count + 1 end return count end local function onComplete( self ) rectangleArray[self] = nil display.remove( self ) print("Rectangles left in array: ", table.count( rectangleArray ) ) end local function rectangleLoop() local thisRectangle = display.newRect(1, 1, 216, 400) thisRectangle.anchorX = 0 thisRectangle.onComplete = onComplete rectangleArray[thisRectangle] = thisRectangle transition.to( thisRectangle, { time = 5000, x = thisRectangle.x + 1080, thisRectangle } ) end local rectangleLoopTimer = timer.performWithDelay(985, rectangleLoop, 0)

After running it, I see what (I think) you are talking about.  

You are worried about the occasional gaps that occur?  

If so, it is the solution you are using.  It is wrong, because you are making an assumption about time.  All events actually happen on a frame based demarkation.  So, if your timer doesn’t line up perfectly with a frame you’ll get a generation gap.

So, what is the right solution… Give me a moment and I’ll get back to you.

The trick is to keep everything in the same ‘context’.

Mixing timers with transitions is a bad move.

This is the best ‘hack’ I could come up with on short notice, but I would not do this in a real game.  Sorry.

function table.count( tbl ) local count = 0 for k,v in pairs(tbl) do count = count + 1 end return count end local counter = 0 local rectangleArray = {} local lastBlock local speed = 200 -- Pixels per second local getTimer = system.getTimer local blockMover local blockSpawner blockMover = function ( self ) local curTime = getTimer() local dt = curTime - self.lastTime self.lastTime = curTime if( dt \>= 5000 ) then Runtime:removeEventListener( "enterFrame", thisRectangle ) rectangleArray[self] = nil display.remove(self) return end self.x = self.x + speed \* dt / 1000 -- Spawn a new block if( self.spawn and self.x \> -50 and self.x \< 0 ) then self:spawn() end end blockSpawner = function( self ) local thisRectangle = display.newRect( 1, 1, 216, 400) thisRectangle.anchorX = 0 thisRectangle.lastTime = getTimer() thisRectangle.enterFrame = blockMover thisRectangle.spawn = blockSpawner if( self ) then self.spawn = nil thisRectangle.x = self.x - 216 end Runtime:addEventListener( "enterFrame", thisRectangle ) rectangleArray[thisRectangle] = thisRectangle print( "Rectangles in array: " .. tostring(table.count( rectangleArray )) .. " @ " .. tostring( system.getTimer() ) ) return thisRectangle end local tmp = blockSpawner() tmp:spawn()

Note: I am working on a solution for this exact kind of mechanic, but:

  1. It isn’t quite ready for release (one or two days left).
  2. It is paid.
  3. It requires SSK2.

However, if this looks cool, keep your eyes open for my upcoming announcement.

https://www.youtube.com/watch?v=4b9CFxTTpaY&feature=youtu.be