execute two for loops at the exact same time?

I want to kill a row of gems in a match 3 game. I want to kill the gems Upward in a timed delayed, and the exact same time, kill the gems Downward. The effect would be like the striped gem explodes outward in a shockwave.  I thought I could execute both “for” loops at the exact same time?  Is it possible?

I called a timer delay function for both “for” loops (code below) : I thought in my mind this would be like making a thread in c++… is it?

To me the code seems to execute each “for” loop seperately…(not at the same time. Just wondering is it possible to execute two for loops at the exact same time?

timer.performWithDelay( 1, function()
            for rowToKillDown = row+1 , bubblesMatch3.numRows do
                if( rowToKillDown ~= row ) then
                  timer.performWithDelay( 40*rowToKillDown, function()  DestroyGem( col, rowToKillDown ) end)
                end
            end
        end)
        
timer.performWithDelay( 1, function()
      local time_delay = 1
       for rowToKillUp = row-1, 0, -1 do
        if( rowToKillUp ~= row ) then
           timer.performWithDelay( 40*time_delay, function()  DestroyGem( col, rowToKillUp ) end)
                  time_delay = time_delay + 1
                end
            end
        end)

No it is not possible to execute 2 for loops at the same time. Your code executes lines of code as it gets to them.  

A better solution would be to combine both the “up” and “down” elements of your function into a single loop.

for rowToKillDown = row+1 , bubblesMatch3.numRows do local rowToKillUp = rowToKillDown + whateverNumberMakesThis work if( rowToKillDown ~= row ) then timer.performWithDelay( 40\*rowToKillDown, function() DestroyGem( col, rowToKillDown ) end) elseif ( rowToKillUp ~= row ) then timer.performWithDelay( 40\*time\_delay, function() DestroyGem( col, rowToKillUp ) end) time\_delay = time\_delay + 1 end end end

I’ve just done this quickly and simply, obviously you would need to change it around a bit to make it work in your game.

Wow! Thanks for the solution. It’s perfect. Why didn’t I think of that?

Another option would be to run through the 2 loops, one after the other, but don’t trigger any timers, just set some flag variables to 1.  Then, in another/later loop, look at the flag variable and trigger any timers/events you need.

-- set a bunch of flags to zero/no action flag = {} for r=1,rows do flag[r] = {} for c=1,cols do flag[r][c] = 0 end end for rowToKillDown = row+1 , bubblesMatch3.numRows do if( rowToKillDown ~= row ) then -- don't trigger the timer yet, just set the relevant flags for c=1,cols do flag[rowToKillDown][c] = 1 end end end end) -- repeat above loop for rowToKillUp -- now trigger all the actions at once for r=1,rows do for c=1,cols do if( flag[r][c] == 1 ) then timer.performWithDelay( 40\*time\_delay, function() DestroyGem(r,c) end) end end end

A potential added bonus:  if you later want to destroy all gems in a certain row _and_ all gems in a certain column, or all gems of a certain color, or all gems that … you can just add more loops to test the conditions and set the flags.

Finally got around to putting the “two” for loops into “one” for loop – this is the code incase anyone else needs to do this. One big problem was declaring variables outside the loop then incrementing them inside the loop – this won’t work when you call that variable in a timer that’s inside the loop – the variable will not increment I guess because it loses scope –

–KILL VERTICAL
        for i = 1 , bubblesMatch3.numRows-1 do
            local rowToKillDown =  row +  i
            local rowToKillUp = ( row - 1 ) - ( i - 1 )
                if( rowToKillDown <= bubblesMatch3.numRows) then
                    timer.performWithDelay( bubblesMatch3.KILL_COL_ROW_DELAY*i,function()
                            PreProcessGemToKill( col, rowToKillDown )

                    end)
                end
                  
                if( rowToKillUp > 0 ) then       
                    timer.performWithDelay( bubblesMatch3.KILL_COL_ROW_DELAY*i, function()
                         PreProcessGemToKill( col, rowToKillUp )
                    end)
                end
        
        end

–KILL HORIZONTAL

 for i = 1 , bubblesMatch3.numCols-1 do
            local colToKillRight =  col +  i
            local colToKillLeft = ( col - 1 ) - ( i - 1 )
    
            if( colToKillRight <= bubblesMatch3.numCols) then
                timer.performWithDelay( bubblesMatch3.KILL_COL_ROW_DELAY*i,function()
                    PreProcessGemToKill( colToKillRight, row )
                end)
            end
                  
            if( colToKillLeft > 0 ) then       
                timer.performWithDelay( bubblesMatch3.KILL_COL_ROW_DELAY*i, function()
                        PreProcessGemToKill( colToKillLeft, row )
                end)
            end   
        end

Without seeing your PreProcessGemToKill function, I’d just note that any time you use timers like this, you potentially have a race condition – sometimes the code will process (i-1,j) and then (i,j), but sometimes (for reasons out of your control) it may process (i,j) first and then (i-1,j).

So you might want to make sure that the exact ordering of the PreProcessGemToKill function calls doesn’t matter (i.e. the code to kill (i,j) really doesn’t depend on what happens to (i-1,j), or (i+1,j), or (i,j-1), etc., that each function call really “does its own thing”).

No it is not possible to execute 2 for loops at the same time. Your code executes lines of code as it gets to them.  

A better solution would be to combine both the “up” and “down” elements of your function into a single loop.

for rowToKillDown = row+1 , bubblesMatch3.numRows do local rowToKillUp = rowToKillDown + whateverNumberMakesThis work if( rowToKillDown ~= row ) then timer.performWithDelay( 40\*rowToKillDown, function() DestroyGem( col, rowToKillDown ) end) elseif ( rowToKillUp ~= row ) then timer.performWithDelay( 40\*time\_delay, function() DestroyGem( col, rowToKillUp ) end) time\_delay = time\_delay + 1 end end end

I’ve just done this quickly and simply, obviously you would need to change it around a bit to make it work in your game.

Wow! Thanks for the solution. It’s perfect. Why didn’t I think of that?

Another option would be to run through the 2 loops, one after the other, but don’t trigger any timers, just set some flag variables to 1.  Then, in another/later loop, look at the flag variable and trigger any timers/events you need.

-- set a bunch of flags to zero/no action flag = {} for r=1,rows do flag[r] = {} for c=1,cols do flag[r][c] = 0 end end for rowToKillDown = row+1 , bubblesMatch3.numRows do if( rowToKillDown ~= row ) then -- don't trigger the timer yet, just set the relevant flags for c=1,cols do flag[rowToKillDown][c] = 1 end end end end) -- repeat above loop for rowToKillUp -- now trigger all the actions at once for r=1,rows do for c=1,cols do if( flag[r][c] == 1 ) then timer.performWithDelay( 40\*time\_delay, function() DestroyGem(r,c) end) end end end

A potential added bonus:  if you later want to destroy all gems in a certain row _and_ all gems in a certain column, or all gems of a certain color, or all gems that … you can just add more loops to test the conditions and set the flags.

Finally got around to putting the “two” for loops into “one” for loop – this is the code incase anyone else needs to do this. One big problem was declaring variables outside the loop then incrementing them inside the loop – this won’t work when you call that variable in a timer that’s inside the loop – the variable will not increment I guess because it loses scope –

–KILL VERTICAL
        for i = 1 , bubblesMatch3.numRows-1 do
            local rowToKillDown =  row +  i
            local rowToKillUp = ( row - 1 ) - ( i - 1 )
                if( rowToKillDown <= bubblesMatch3.numRows) then
                    timer.performWithDelay( bubblesMatch3.KILL_COL_ROW_DELAY*i,function()
                            PreProcessGemToKill( col, rowToKillDown )

                    end)
                end
                  
                if( rowToKillUp > 0 ) then       
                    timer.performWithDelay( bubblesMatch3.KILL_COL_ROW_DELAY*i, function()
                         PreProcessGemToKill( col, rowToKillUp )
                    end)
                end
        
        end

–KILL HORIZONTAL

 for i = 1 , bubblesMatch3.numCols-1 do
            local colToKillRight =  col +  i
            local colToKillLeft = ( col - 1 ) - ( i - 1 )
    
            if( colToKillRight <= bubblesMatch3.numCols) then
                timer.performWithDelay( bubblesMatch3.KILL_COL_ROW_DELAY*i,function()
                    PreProcessGemToKill( colToKillRight, row )
                end)
            end
                  
            if( colToKillLeft > 0 ) then       
                timer.performWithDelay( bubblesMatch3.KILL_COL_ROW_DELAY*i, function()
                        PreProcessGemToKill( colToKillLeft, row )
                end)
            end   
        end

Without seeing your PreProcessGemToKill function, I’d just note that any time you use timers like this, you potentially have a race condition – sometimes the code will process (i-1,j) and then (i,j), but sometimes (for reasons out of your control) it may process (i,j) first and then (i-1,j).

So you might want to make sure that the exact ordering of the PreProcessGemToKill function calls doesn’t matter (i.e. the code to kill (i,j) really doesn’t depend on what happens to (i-1,j), or (i+1,j), or (i,j-1), etc., that each function call really “does its own thing”).