How to remove items after a set amount of time

I need some help! I have a game that will continuously spawn objects at random places on screen using a timer.
How can I make these objects remove themselves if they have not been tapped within a set time frame?

Here is a sample of my code –

[lua]local function spawnBall ()
rad = mRand (15, 35)
local ball = display.newCircle (mRand(rad, _W - rad), mRand(rad + 40, _H - rad), rad)
ball:setFillColor (255, 255, 255, 99)
ball.strokeWidth = 1
ball:setStrokeColor (0, 255, 120, 99)

function ball:touch(e)
if (p == true) then
return true
end
if (e.phase == “ended”) then
– Play popping sound
audio.play(burst)

– Remove ball
ballHit(self)
end
return true
end

ball:addEventListener (“touch”, ball)
end

local gameTimer = timer.performWithDelay (spawnSpeed, spawnBall, total_balls)[/lua] [import]uid: 151658 topic_id: 29135 reply_id: 329135[/import]

Add something like this after line 22;

[lua] ball:addEventListener (“touch”, ball)
local function removeBall()
ball:removeSelf()
end
timer.performWithDelay(2000, removeBall, 1)[/lua]

(though you should consider using a table for your objects.)

Peach :slight_smile: [import]uid: 52491 topic_id: 29135 reply_id: 117306[/import]

Thank you!!! That worked perfectly :slight_smile: I had that same exact code written already, but I must not have had it in the right spot because I could not for the life of me get them to disappear. I am curious, what benefit would tables give me and how would you suggest using them? [import]uid: 151658 topic_id: 29135 reply_id: 117325[/import]

This is by no means a text book definition on tables. The way I see it is, to put it in short, when you have tables each ball is given an individual number, so you can do more specific actions upon an exact ball that you want.

In some cases your balls might not get removed in the proper order and those that have not been removed when they were supposed too won’t be getting removed from the timer anymore since it’s an ‘old’ ball and you are creating new variables named ball. If they are in a table however every ball has it’s own specific number which allows you to do a lot of things with it.

Here’s some sample code, might not be perfect since I just did a replace all and checked over it quick

ball = {}  
i = 0  
  
local function spawnBall ()  
 rad = mRand (15, 35)  
 i = i + 1  
 local ball[i] = display.newCircle (mRand(rad, \_W - rad), mRand(rad + 40, \_H - rad), rad)  
 ball[i]:setFillColor (255, 255, 255, 99)  
 ball[i].strokeWidth = 1  
 ball[i]:setStrokeColor (0, 255, 120, 99)  
  
 function ball:touch(e)  
 if (p == true) then  
 return true  
 end  
 if (e.phase == "ended") then  
 -- Play popping sound  
 audio.play(burst)  
  
 -- Remove ball  
 ballHit(self)  
 end  
 return true  
 end  
  
 ball[i]:addEventListener ("touch", ball)  
end  
   
local gameTimer = timer.performWithDelay (spawnSpeed, spawnBall, total\_balls)  

You might have to change the remove ball function depending on how you have it. A simple solution for this is to make something like this for your ball remove function

test = event.target  
test:removeSelf()  
test = nil  

[import]uid: 77199 topic_id: 29135 reply_id: 117333[/import]

@hatethinkingofnames - that is a very solid example of how to use a table in this case; +1 [import]uid: 52491 topic_id: 29135 reply_id: 117384[/import]

Ok so I tried using a table and for some reason when I add in the code to remove after a set amount of time, it starts acting crazy. It will skip the first 5 or 6 balls and they will stay on screen, and then the others will start to remove themselves. Here is the code I have without the automatic removal.

[lua]function spawnBall()
i = i + 1;
ball[i] = gameBall.new();
ball[i].life = 1;
function ball:touch(e)
– If the game is paused, don’t allow balls to be clicked
if (p == true) then
return true;
elseif (e.phase == “ended”) then
e.target.life = e.target.life - 1;
– Play burst sound
audio.play(burst);
– Remove ball and increase score
if (e.target.life == 0) then
e.target:removeSelf();
e.target = nil;
increaseScore();
end
end
return true;
end
ball[i]:addEventListener(“touch”, ball);
end
local gameTimer = timer.performWithDelay (spawnSpeed, spawnBall, totalBalls);[/lua]

Is there anything in there that is not necessary to have? Is anyone available for iMessage or anything like that for a more in depth discussion? [import]uid: 151658 topic_id: 29135 reply_id: 119924[/import]

Can you post the automatic removal just to get the whole picture. And also, why is your ball function inside your spawnball function?

[import]uid: 77199 topic_id: 29135 reply_id: 120031[/import]

My ball function is inside my spawnball function because I have the code for ball creation in another .lua file called gameBall.lua. Here is the code for that followed by the code with the auto removal.

[lua]module(…, package.seeall);

function new()
local img;
local imgWidth;
local imgHeight;

local imgType = math.random(1,3)

if(imgType == 1) then
– Get small ball image
img = “images/sm_ball.png”;
imgWidth = 40; imgHeight = 40;
elseif(imgType == 2) then
– Get medium ball image
img = “images/med_ball.png”;
imgWidth = 60; imgHeight = 60;
elseif(imgType == 3) then
– Get large ball image
img = “images/lrg_ball.png”;
imgWidth = 80; imgHeight = 80;
end

local ball = display.newImageRect(img, imgWidth, imgHeight);
ball:setReferencePoint(display.TopLeftReferencePoint);
while ball.x <= 20 or ball.y >= display.contentHeight - 20 do
ball.x = math.random(0, _W - ball.width); ball.y = math.random(40, _H - ball.height);
end

–ball.alpha = 0;
–transition.to( ball, { alpha=1, time= 250 })

return ball;
end[/lua]

[lua] function spawnBall()
i = i + 1;
ball[i] = gameBall.new();
ball[i].life = 1;
function ball:touch(e)
– If the game is paused, don’t allow balls to be clicked
if (p == true) then
return true;
elseif (e.phase == “ended”) then
e.target.life = e.target.life - 1;
– Play burst sound
audio.play(burst);
– Remove ball and increase score
if (e.target.life == 0) then
e.target:removeSelf();
e.target = nil;
increaseScore();
end
end

return true;
end
ball[i]:addEventListener(“touch”, ball);

local function removeBall()
ball[i]:removeSelf();
decreaseScore();
end
ball[i].tmr = timer.performWithDelay(2000, removeBall, 1);
end
local gameTimer = timer.performWithDelay (spawnSpeed, spawnBall, totalBalls);[/lua] [import]uid: 151658 topic_id: 29135 reply_id: 120056[/import]

Yeah it is the automatic removal that’s not correct. Let me try explaining why. So the reason why you switched to using tables is so that each ball gets his own number, so you can do anything you want with that specific ball. Now I’m not sure what your spawnBall rate is but I’m guessing it’s pretty fast at the beginning. Each time a ball spawns it increases the value of i by 1. So you have a timer to remove the ball i every 2 seconds. So if you spawn balls faster that means it will remove every other ball or worse, every other other ball or however many balls spawn in that amount of time. Literally when the removeBall function is being called i is already equal to 5 or something so 1-4 get skipped entirely.

To fix this is quite easy. You create a new variable that does not increase in value every time a ball is created. You can use any name or letter you want. Let me give you an example:

local function removeBall()  
ball[s]:removeSelf();  
-- note you dont have ball[s] = nil here, might want to add it  
decreaseScore();  
s = s + 1  
-- you are going to have to make s = 1 outside the function  
end  
ball[s].tmr = timer.performWithDelay(2000, removeBall, 1);  

This way it will start off by removing ball 1 and when it does s will be s = s + 1, so s will equal 2 and it will go to remove ball 2 and so on.

I’m not sure about this but it might give you an error if the ball doesnt exist, meaning you removed it from touch. If it does give you an error saying it doesnt exist and cant destroy it then the fix is still easy

ball[i].myName = "alive"  
  
--then in the removeBall function you add  
if ball[s].myName == "dead" then  
 return true  
elseif ball[s].myName == "alive" then  
 ball[s]:removeSelf();  
-- note you dont have ball[s] = nil here, might want to add it  
 decreaseScore();  
 s = s + 1  
end  
  
--you also have to add e.target.myName = "dead" in your touch function  

That is in case you get errors. I also suggest you move the touch and removeBall functions outside your other functions so that they are their own functions. I’m questioning my function knowledge now but it doesn’t seem right to call a function that already exists and hasn’t been removed every time a ball is created, just extra resources overall unless it ignores it if it already exists. Still a waste to even check if it exists though, anyway best of luck!
[/code]

[import]uid: 77199 topic_id: 29135 reply_id: 120069[/import]

Makes perfect sense but how would you go about pausing and resuming all timers at once if you have a pause function that gets called when the pause button is pressed?

– do you use skype or imessage? [import]uid: 151658 topic_id: 29135 reply_id: 120078[/import]

Was easier to just start from scratch, took me a bit longer than I thought. Try this:

display.setStatusBar( display.HiddenStatusBar )  
  
s = 1  
i = 1  
x = 1  
ball = {}  
score = 0  
  
myText = display.newText("", 50, 50, native.systemFont, 16)  
myText:setTextColor(255, 255, 255)  
myText.text = score  
  
pauseBut = display.newRect( 250, 20, 50, 50 )  
function spawnBalls()  
  
 ranX = math.random( 80, 240 )  
 ranY = math.random( 80, 400 )  
 ball[i] = display.newCircle( ranX, ranY, 20 )  
 ball[i]:addEventListener( "touch", destroyOnTouch )  
 ball[i].tmr = timer.performWithDelay( 2000, killBall, 0 )  
 ball[i].myName = "alive"  
 ball[i].name = i  
 i = i + 1  
  
end  
  
function destroyOnTouch( event )  
 if event.phase == "began" then  
 touchedBall = event.target  
 timer.cancel( event.target.tmr )  
  
 event.target.isVisible = false  
 event.target.myName = "dead"  
 score = score + 1  
 myText.text = score  
 return true  
 end  
end  
  
function killBall()  
 ball[x].myName = "dead"  
end  
  
function ballTimeout( event )  
 if ball[s].myName == "alive" then  
 return true  
 elseif ball[s].myName == "dead" then  
 ball[s]:removeSelf()  
 ball[s] = nil  
 x = x + 1  
 s = s + 1  
 end  
end  
  
anotherTimer = timer.performWithDelay( 500, ballTimeout, 0 )  
  
function pauseEverything( event )  
 if event.phase == "ended" then  
 timer.pause( theTimer )  
 timer.pause( anotherTimer )  
 for gg = s, (i - 1) do  
 timer.pause( ball[gg].tmr )  
 end  
 pauseBut:removeSelf()  
 pauseBut = nil  
 pauseBut = display.newRect( 250, 20, 50, 50 )  
 pauseBut:addEventListener( "touch", resumeEverything )  
 end  
end  
pauseBut:addEventListener( "touch", pauseEverything )  
  
function resumeEverything( event )  
 if event.phase == "ended" then  
 timer.resume( theTimer)  
 timer.resume( anotherTimer )  
 for gg = s, (i - 1) do  
 timer.resume( ball[gg].tmr )  
 end  
 pauseBut:removeSelf()  
 pauseBut = nil  
 pauseBut = display.newRect( 250, 20, 50, 50 )  
 pauseBut:addEventListener( "touch", pauseEverything )  
 end  
end  
theTimer = timer.performWithDelay( 500, spawnBalls, 0 )  

I do have skype that I never logon, but if you have some more questions leave your skype I’ll add ya. or feel free to just ask here if you dont understand anything [import]uid: 77199 topic_id: 29135 reply_id: 120102[/import]

Look forward to talking with you. [import]uid: 151658 topic_id: 29135 reply_id: 120110[/import]

Ok so I tried using a table and for some reason when I add in the code to remove after a set amount of time, it starts acting crazy. It will skip the first 5 or 6 balls and they will stay on screen, and then the others will start to remove themselves. Here is the code I have without the automatic removal.

[lua]function spawnBall()
i = i + 1;
ball[i] = gameBall.new();
ball[i].life = 1;
function ball:touch(e)
– If the game is paused, don’t allow balls to be clicked
if (p == true) then
return true;
elseif (e.phase == “ended”) then
e.target.life = e.target.life - 1;
– Play burst sound
audio.play(burst);
– Remove ball and increase score
if (e.target.life == 0) then
e.target:removeSelf();
e.target = nil;
increaseScore();
end
end
return true;
end
ball[i]:addEventListener(“touch”, ball);
end
local gameTimer = timer.performWithDelay (spawnSpeed, spawnBall, totalBalls);[/lua]

Is there anything in there that is not necessary to have? Is anyone available for iMessage or anything like that for a more in depth discussion? [import]uid: 151658 topic_id: 29135 reply_id: 119924[/import]

Can you post the automatic removal just to get the whole picture. And also, why is your ball function inside your spawnball function?

[import]uid: 77199 topic_id: 29135 reply_id: 120031[/import]

My ball function is inside my spawnball function because I have the code for ball creation in another .lua file called gameBall.lua. Here is the code for that followed by the code with the auto removal.

[lua]module(…, package.seeall);

function new()
local img;
local imgWidth;
local imgHeight;

local imgType = math.random(1,3)

if(imgType == 1) then
– Get small ball image
img = “images/sm_ball.png”;
imgWidth = 40; imgHeight = 40;
elseif(imgType == 2) then
– Get medium ball image
img = “images/med_ball.png”;
imgWidth = 60; imgHeight = 60;
elseif(imgType == 3) then
– Get large ball image
img = “images/lrg_ball.png”;
imgWidth = 80; imgHeight = 80;
end

local ball = display.newImageRect(img, imgWidth, imgHeight);
ball:setReferencePoint(display.TopLeftReferencePoint);
while ball.x <= 20 or ball.y >= display.contentHeight - 20 do
ball.x = math.random(0, _W - ball.width); ball.y = math.random(40, _H - ball.height);
end

–ball.alpha = 0;
–transition.to( ball, { alpha=1, time= 250 })

return ball;
end[/lua]

[lua] function spawnBall()
i = i + 1;
ball[i] = gameBall.new();
ball[i].life = 1;
function ball:touch(e)
– If the game is paused, don’t allow balls to be clicked
if (p == true) then
return true;
elseif (e.phase == “ended”) then
e.target.life = e.target.life - 1;
– Play burst sound
audio.play(burst);
– Remove ball and increase score
if (e.target.life == 0) then
e.target:removeSelf();
e.target = nil;
increaseScore();
end
end

return true;
end
ball[i]:addEventListener(“touch”, ball);

local function removeBall()
ball[i]:removeSelf();
decreaseScore();
end
ball[i].tmr = timer.performWithDelay(2000, removeBall, 1);
end
local gameTimer = timer.performWithDelay (spawnSpeed, spawnBall, totalBalls);[/lua] [import]uid: 151658 topic_id: 29135 reply_id: 120056[/import]

Yeah it is the automatic removal that’s not correct. Let me try explaining why. So the reason why you switched to using tables is so that each ball gets his own number, so you can do anything you want with that specific ball. Now I’m not sure what your spawnBall rate is but I’m guessing it’s pretty fast at the beginning. Each time a ball spawns it increases the value of i by 1. So you have a timer to remove the ball i every 2 seconds. So if you spawn balls faster that means it will remove every other ball or worse, every other other ball or however many balls spawn in that amount of time. Literally when the removeBall function is being called i is already equal to 5 or something so 1-4 get skipped entirely.

To fix this is quite easy. You create a new variable that does not increase in value every time a ball is created. You can use any name or letter you want. Let me give you an example:

local function removeBall()  
ball[s]:removeSelf();  
-- note you dont have ball[s] = nil here, might want to add it  
decreaseScore();  
s = s + 1  
-- you are going to have to make s = 1 outside the function  
end  
ball[s].tmr = timer.performWithDelay(2000, removeBall, 1);  

This way it will start off by removing ball 1 and when it does s will be s = s + 1, so s will equal 2 and it will go to remove ball 2 and so on.

I’m not sure about this but it might give you an error if the ball doesnt exist, meaning you removed it from touch. If it does give you an error saying it doesnt exist and cant destroy it then the fix is still easy

ball[i].myName = "alive"  
  
--then in the removeBall function you add  
if ball[s].myName == "dead" then  
 return true  
elseif ball[s].myName == "alive" then  
 ball[s]:removeSelf();  
-- note you dont have ball[s] = nil here, might want to add it  
 decreaseScore();  
 s = s + 1  
end  
  
--you also have to add e.target.myName = "dead" in your touch function  

That is in case you get errors. I also suggest you move the touch and removeBall functions outside your other functions so that they are their own functions. I’m questioning my function knowledge now but it doesn’t seem right to call a function that already exists and hasn’t been removed every time a ball is created, just extra resources overall unless it ignores it if it already exists. Still a waste to even check if it exists though, anyway best of luck!
[/code]

[import]uid: 77199 topic_id: 29135 reply_id: 120069[/import]

Makes perfect sense but how would you go about pausing and resuming all timers at once if you have a pause function that gets called when the pause button is pressed?

– do you use skype or imessage? [import]uid: 151658 topic_id: 29135 reply_id: 120078[/import]

Was easier to just start from scratch, took me a bit longer than I thought. Try this:

display.setStatusBar( display.HiddenStatusBar )  
  
s = 1  
i = 1  
x = 1  
ball = {}  
score = 0  
  
myText = display.newText("", 50, 50, native.systemFont, 16)  
myText:setTextColor(255, 255, 255)  
myText.text = score  
  
pauseBut = display.newRect( 250, 20, 50, 50 )  
function spawnBalls()  
  
 ranX = math.random( 80, 240 )  
 ranY = math.random( 80, 400 )  
 ball[i] = display.newCircle( ranX, ranY, 20 )  
 ball[i]:addEventListener( "touch", destroyOnTouch )  
 ball[i].tmr = timer.performWithDelay( 2000, killBall, 0 )  
 ball[i].myName = "alive"  
 ball[i].name = i  
 i = i + 1  
  
end  
  
function destroyOnTouch( event )  
 if event.phase == "began" then  
 touchedBall = event.target  
 timer.cancel( event.target.tmr )  
  
 event.target.isVisible = false  
 event.target.myName = "dead"  
 score = score + 1  
 myText.text = score  
 return true  
 end  
end  
  
function killBall()  
 ball[x].myName = "dead"  
end  
  
function ballTimeout( event )  
 if ball[s].myName == "alive" then  
 return true  
 elseif ball[s].myName == "dead" then  
 ball[s]:removeSelf()  
 ball[s] = nil  
 x = x + 1  
 s = s + 1  
 end  
end  
  
anotherTimer = timer.performWithDelay( 500, ballTimeout, 0 )  
  
function pauseEverything( event )  
 if event.phase == "ended" then  
 timer.pause( theTimer )  
 timer.pause( anotherTimer )  
 for gg = s, (i - 1) do  
 timer.pause( ball[gg].tmr )  
 end  
 pauseBut:removeSelf()  
 pauseBut = nil  
 pauseBut = display.newRect( 250, 20, 50, 50 )  
 pauseBut:addEventListener( "touch", resumeEverything )  
 end  
end  
pauseBut:addEventListener( "touch", pauseEverything )  
  
function resumeEverything( event )  
 if event.phase == "ended" then  
 timer.resume( theTimer)  
 timer.resume( anotherTimer )  
 for gg = s, (i - 1) do  
 timer.resume( ball[gg].tmr )  
 end  
 pauseBut:removeSelf()  
 pauseBut = nil  
 pauseBut = display.newRect( 250, 20, 50, 50 )  
 pauseBut:addEventListener( "touch", pauseEverything )  
 end  
end  
theTimer = timer.performWithDelay( 500, spawnBalls, 0 )  

I do have skype that I never logon, but if you have some more questions leave your skype I’ll add ya. or feel free to just ask here if you dont understand anything [import]uid: 77199 topic_id: 29135 reply_id: 120102[/import]

Look forward to talking with you. [import]uid: 151658 topic_id: 29135 reply_id: 120110[/import]