Destroying multiple objects simultaneously with each turning into explosion object leaving each time to animate

I have an error in my game which I have spent countless hours trying to resolve with no success. When an enemy is destroyed I spawn an explosion object on it’s position, an animated object, which I leave for 100ms to animate before I remove the explosion object. The problem is the following: If I have 2 enemies being destroyed simultaneously (or close to), which is a possibility in my game, I get an index global explosion < a nil value > error. So basically I can’t have 2 or more explosion objects on screen at once, I have to wait between them until each finishes.

My current way to resolve this issue is that when an enemy explosion object is created, I continously, in an enter frame, check if an explosion object exists, and when it does I set a flag to true else set it to false. I then use this flag to run a while loop in the enemy explosion function so that it does nothing when the flag is true and then when it is false I create the next explosion and so on.

Here is my function activated on enterFrame:

local function movePlayer(event)  
 plane:setLinearVelocity(hspeed,0);   
  
 if(plane.x \> 423) then  
 plane.x = 422;  
 hspeed = 0;  
 end  
 if(plane.x \< 60) then  
 plane.x = 61;  
 hspeed = 0;  
 end  
  
 if(explosion) then  
 inExplode = true;  
 else  
 inExplode = false;  
 end  
  
end  

Here is my collision code, so you can see program execution flow:

function onBulletCollision( self, event )  
 if(event.phase == "began") then  
  
  
 if(event.other.myName == "met") then  
 print( self.myName .. ": collision began with " .. event.other.myName );   
 self:removeSelf();   
 self = nil;   
  
 xCoord = event.other.x; yCoord = event.other.y;   
 event.other:removeSelf();   
 event.other = nil;   
 audio.play(explode\_sound);  
 enemy\_Explode(xCoord,yCoord);  
 elseif(event.other.myName == "ceiling") then  
 print( self.myName .. ": collision began with " .. event.other.myName );   
 self:removeSelf();  
 self = nil;  
 end  
 end  
end  

This function is then called to create the explosion:

enemy\_Explode = function(xCoordinate,yCoordinate)  
  
 while(inExplode == true) do  
 print( "inExplode" );  
 end  
 require "sprite";  
 sheetExplosion = sprite.newSpriteSheet( "Media/Images/explosionSheet.png", 99,119);  
 spriteSetExplosion = sprite.newSpriteSet(sheetExplosion, 1, 3);   
 sprite.add( spriteSetExplosion, "expl", 1, 3, 100,0);   
  
 explosion = sprite.newSprite( spriteSetExplosion );   
 explosion.isVisible = true;  
  
 explosion.x = xCoordinate; explosion.y = yCoordinate;   
  
 explosion:prepare("expl");   
 explosion:play();   
  
 timer.performWithDelay(100, explody, 1);   
end  

Then finally this code is used to remove the explosion:

explody = function()  
 print( "in explody" );  
 explosion:removeSelf();  
 explosion = nil;  
 -- These two lines free texture from memory.  
 sheetExplosion:dispose();  
 sheetExplosion = nil;  
end  

I can’t see why my code doesn’t work, when I run my game, when I hit both enemies simultaneously they both turn into an explosion object, after the 100 ms one of them then vanishes but then the other remains as an animating explosion forever resulting in the explosion nil runtime error.

I also notice that the while loop is never being executed, because the print statement is never being displayed in the simulator.

My code should make it so only one explosion appears, then once it’s done do the next one, I don’t see what I’ve done wrong here.
Any help would be amazing, I am really stumped on this error. [import]uid: 116225 topic_id: 21076 reply_id: 321076[/import]

You may want to give them unique names; create a table -

[lua]explosion = {}[/lua]

then spawn your explosion sprites like so;

[lua]explosion[#explosion] = sprite.newSprite( spriteSetExplosion )[/lua]

Let me know how that goes for you.

On a related note - you only need to set up the sprite sheet, and require “sprite” once - so you can move that out of the function.

Peach :slight_smile: [import]uid: 52491 topic_id: 21076 reply_id: 83279[/import]

Hi Peach,

Thanks for telling me that I am able to move it out of the function, I want to make my games as efficient as possible.

Your table idea is great, I have now implemented it into the game as you suggested. I just used a for loop to iterate through the table in the explody() function to remove each explosion object.

explody = function()  
 print( "in explody" );  
  
 for i in pairs (explosion) do  
 explosion[i]:removeSelf();  
 explosion[i] = nil;  
 end  

I thought for sure that would fix everything, seems very logical, but unfortunately it hasn’t :(. I’m convinced it’s something to do with how the timer works though. When I run my game, I spawn 2 enemies which have the same velocity and fire a large rectangle object covering the width of the screen at them, to simulate a simultaneous event.

Now what happens, is the collision detection print statements are printed basically simultaneously (as expected) but then something interesting happens with the calling of the explody() function.

The timer waits 1000ms (I currently have set higher for testing purposes) and then executes the explody function twice simultaneously. However, the same problem persists, only the first explosion hit dissapears, the other just animates forever. It seems that the second explosion being entered into the table is never removed from the table, what is going on? I tried setting the timer to go off infinite times, but the other explosion still just sits their animating forever. Also there are no errors appearing in the simulator output.

Maybe the error is in the way I’m using tables to spawn meteors, although I did it the way you said, maybe I still made an error somewhere?

enemy\_Explode = function(xCoordinate,yCoordinate)   
  
 explosion[#explosion] = sprite.newSprite( spriteSetExplosion ); -- Creates explosion at most recent index.  
 explosion[#explosion].x = xCoordinate; explosion[#explosion].y = yCoordinate;   
  
 explosion[#explosion]:prepare("expl");   
 explosion[#explosion]:play();   
 timer.performWithDelay(1000, explody, 1);   
end  

Thanks so much for your help so far, I think the problem is almost resolved.

EDIT: It’s fixed!! Yes!!!

The problem was my practice with tables, I used #explosion, I should be using #explosion+1 as index 0 is nil!!!
I changed the code as follows and works brilliantly!!

enemy\_Explode = function(xCoordinate,yCoordinate)   
explodeNumber = #explode+1;  
  
 explosion[explodeNumber] = sprite.newSprite( spriteSetExplosion ); -- Creates explosion at most recent index.  
 explosion[explodeNumber].x = xCoordinate; explosion[explodeNumber].y = yCoordinate;   
  
 explosion[explodeNumber]:prepare("expl");   
 explosion[explodeNumber]:play();   
 timer.performWithDelay(1000, explody, 1);   
end  

Thank you so much for all your help Peach!! [import]uid: 116225 topic_id: 21076 reply_id: 83432[/import]

Yay! Well done :slight_smile:

I’m sorry, I should have considered the +1 situation - nicely done!

Peach :slight_smile: [import]uid: 52491 topic_id: 21076 reply_id: 83491[/import]