trying to remove 3 objects in a collision

I have a table that stores all my display objects. Each display object has a property called .touching that records all other display objects touching it.

When a collision occurs I want to check that the number of entries in the table doesn’t exceed 2 and when it does to remove all the display objects.

removing any two objects that touch is easy

e.object1.parent:remove(e.object1);  
e.object2.parent:remove(e.object2);  

but how would you go about removing the third or more? I’ve tried a number of things shown below but none seem to work.

e.object1.touching[1]:removeSelf(); e.object1.touching[1]:remove(e.object1.touching[1]); e.object1.touching[1].parent:removeSelf(); e.object1.touching[1].parent:remove(e.object1.touching[1]); [import]uid: 31694 topic_id: 22484 reply_id: 322484[/import]

anyone? [import]uid: 31694 topic_id: 22484 reply_id: 89848[/import]

I need a little more info before I can help.
Can you provide the code where you assign the ‘touching’ property?

Jeff
[import]uid: 14119 topic_id: 22484 reply_id: 89866[/import]

Below is my spawn function where the .touching property is created and below that is the test and remove function

local function spawn(e)  
 if(ready == true) then  
 i = i + 1;  
 local rand = m.random(1,6);   
 local newBean = display.newImage("images/"..beanColours[rand]..".png");  
 newBean.id = i;  
 newBean.type = "bean";  
 newBean.touching = {};  
 newBean.colour = beanColours[rand];  
 newBean.x = display.contentWidth\*0.5;  
 newBean.y = 40;  
  
 local left = { -7,-4, 12,24, -5,29, -21,30, -33,25, -40,18, -41,7, -34,1 };  
 local right = { -8,-7, 4,-20, 16,-32, 28,-30, 35,-20, 34,-2, 27,11, 11,22 };  
 physics.addBody( newBean,   
 { density=100, friction=1, bounce=0, shape=left},   
 { density=100, friction=1, bounce=0, shape=right}  
 )  
 foreground:insert(newBean);  
  
 beans[i] = newBean;  
  
 end  
end  
local function touchCheck(e)  
  
 if(e.object1.type == "bean" and e.object2.type == "bean") then  
 if(e.phase == "began") then  
 if(e.object1.colour == e.object2.colour) then  
 if(#e.object1.touching \> 0) then  
 inTable = false;  
 for k=1,#e.object1.touching do  
 if (e.object1.touching[k] == e.object2) then  
 inTable = true;  
 --print ("existing");  
 end  
 end  
 if(inTable == false) then  
 e.object1.touching[#e.object1.touching+1] = e.object2;  
 --print ("additional add");  
 end  
 else  
 e.object1.touching[1] = e.object2;  
 --print ("new add");  
 end  
  
 if (#e.object2.touching \> 0) then  
 inTable = false;  
 for k=1,#e.object2.touching do  
 if (e.object2.touching[k] == e.object1) then  
 inTable = true;  
 --print ("existingobj2");  
 end  
 end  
 if(inTable == false) then  
 e.object2.touching[#e.object2.touching+1] = e.object1;  
 --print ("additional addobj2");  
 end  
 else  
 e.object2.touching[1] = e.object1;  
 --print ("new addobj2");  
 end  
 if(#e.object1.touching \>= 2 or #e.object2.touching \>= 2) then  
 print("match"..e.object1.colour);  
 for m=1,#e.object1.touching, -1 do  
 print("obj1");  
 if (e.object1.touching[m] ~= e.object2) then  
 e.object1.touching[m].parent:remove(e.object1.touching[m]);  
 end  
 end  
 for k=1,#e.object2.touching, -1 do  
 print("obj2");  
 if (e.object2.touching[m] ~= e.object1) then  
 e.object2.touching[k].parent:remove(e.object2.touching[k]);  
 end  
 end  
 e.object2:removeSelf();  
 e.object1:removeSelf();  
  
 end  
  
 end  
 end  
 end  
  
 if(e.phase == "ended") then  
 if(e.object1.colour == e.object2.colour) then  
 if (#e.object1.touching \> 0) then  
 for k=1,#e.object1.touching, -1 do  
 if (e.object1.touching[k] == obj2) then  
 e.object1.touching[k] = nil;  
 --print ("removed");  
 end  
 end  
 end  
 if (#e.object2.touching \> 0) then  
 for k=1,#e.object2.touching , -1 do  
 if (e.object2.touching[k] == obj1) then  
 e.object2.touching[k] = nil;  
 --print ("removedobj2");  
 end  
 end  
 end  
 end  
 end  
end  
  

[import]uid: 31694 topic_id: 22484 reply_id: 89869[/import]

I assume that touchCheck(e) is derived from “Runtime:addEventListener( “collision”, touchCheck)”.
If so, you cannot remove or alter any object that’s involved in a collision inside the collision function itself. You need to delay the action by using something like timer.performWithDelay(10,deleteTheObjects).
Here is the reference:
http://developer.anscamobile.com/reference/index/eventphase

Another problem I see is your ‘for’ loops are incorrect:

for m=1,#e.object1.touching, -1 do
should be:

for m=#e.object1.touching,1, -1 do

Jeff

[import]uid: 14119 topic_id: 22484 reply_id: 90370[/import]

Thanks. I’ve changed some code but still having problems. Is it alright to remove things like this this?

local function matchCheck(e)  
 if(e.object1.type == "bean" and e.object2.type == "bean") then  
 if(e.phase == "began") then  
 if(#e.object1.touching \>= 2 or #e.object2.touching \>= 2) then  
 for m=#e.object1.touching, 1, -1 do  
 if (e.object1.touching[m] ~= nil) then  
 if (e.object1.touching[m] ~= e.object2) then  
 e.object1.touching[m]:pop();  
 end  
 end  
 end  
 for k=#e.object2.touching, 1, -1 do  
 if (e.object2.touching[m] ~= nil) then  
 if (e.object2.touching[m] ~= e.object1) then  
 e.object2.touching[k]:pop();  
 end  
 end  
 end  
 e.object1:pop();  
 e.object2:pop();  
 end  
 end  
 end  
end  

[code]
function newBean(colour)

local bean = display.newImage(“images/”…colour…".png");
bean.x = display.contentWidth*0.5; bean.y = 40;

–Setup properties
bean.type = “bean”;
bean.touching = {};
bean.colour = colour;

function bean:pop()

–hide the object
self.isVisible = false;

–Finally remove the object
self:removeSelf();
self = nil;
collectgarbage(“collect”);
end

local left = { -7,-4, 12,24, -5,29, -21,30, -33,25, -40,18, -41,7, -34,1 };
local right = { -8,-7, 4,-20, 16,-32, 28,-30, 35,-20, 34,-2, 27,11, 11,22 };
physics.addBody( bean,
{ density=100, friction=1, bounce=0, shape=left},
{ density=100, friction=1, bounce=0, shape=right}
)

return bean;
end
[/code] [import]uid: 31694 topic_id: 22484 reply_id: 90453[/import]

I should also mention that I am able to remove somethings. The error I am getting is “attempt to call method ‘removeSelf’ a nil value”

Which I assume means that I have some how disturbed the table references or already removed an object that appears in two tables. But I can’t see how I am doing either. [import]uid: 31694 topic_id: 22484 reply_id: 90455[/import]

Give this a try.
Again I’m assuming matchCheck() is being called from “Runtime:addEventListener( “collision”, matchCheck)”.

local function matchCheck(e)  
 local obj1 = e.object1  
 local obj2 = e.object2  
 if (obj1.type == "bean" and obj2.type == "bean") then  
 if (e.phase == "began") then  
 if (#obj1.touching \>= 2 or #obj2.touching \>= 2) then  
 for m = #obj1.touching, 1, -1 do  
 if (obj1.touching[m] ~= nil) then  
 if (obj1.touching[m] ~= obj2) then  
 timer.performWithDelay(10,function() obj1.touching[m]:removeSelf(); obj1.touching[m] = nil; end )  
 end  
 end  
 end  
 for m = #obj2.touching, 1, -1 do  
 if (obj2.touching[m] ~= nil) then  
 if (obj2.touching[m] ~= obj1) then  
 timer.performWithDelay(10,function() obj2.touching[m]:removeSelf(); obj2.touching[m] = nil; end )  
 end  
 end  
 end  
 else  
 obj1.touching[#obj1.touching + 1] = obj2;  
 obj2.touching[#obj2.touching + 1] = obj1;  
 end  
 end  
 end  
end  

Jeff

[import]uid: 14119 topic_id: 22484 reply_id: 90638[/import]

Hey thanks I really appreciate the help. I tried to put a timer on the remove function. It seems better but it is still sometimes only removing two, sometimes three, sometimes none. I’m not getting the nil error as often now, but I am still getting it on occassion. I’ve posted my full source code below. Any help would be appreciated.

module(..., package.seeall);  
function new()  
  
 --Vars  
 beans = {};  
 i = 0;  
 ready = true;  
 beanColours = {}  
  
 --Bean table  
 beanColours[1] = "green";  
 beanColours[2] = "blue";  
 beanColours[3] = "red";  
 beanColours[4] = "yellow";  
 beanColours[5] = "purple";  
 beanColours[6] = "black";  
  
 --Create display groups  
 local Scene = display.newGroup();  
 local foreground = display.newGroup();  
  
 --Insert display groups into scene  
 Scene:insert(foreground);  
  
 --Initialise physics  
 local physics = require("physics");  
 physics.start();  
 --physics.setDrawMode("hybrid");  
  
 --Classes  
 local bean = require("bean");  
  
 --Create boundaries  
 local ceiling = display.newRect(0,0,\_W,5);  
 ceiling.y = 0 - ceiling.height \* 0.5;  
 ceiling.type = "wall";  
  
 local ground = display.newRect(0,0,\_W,30);  
 ground.y = \_H - ground.height \* 0.5;  
 ground.type = "wall";  
  
 local left\_wall = display.newRect(0,0,6,\_H);  
 left\_wall.x = 0 - left\_wall.width \* 0.5;  
 left\_wall.type = "wall";  
  
 local right\_wall = display.newRect(0,0,6,\_H);  
 right\_wall.x = \_W + right\_wall.width \* 0.5;  
 right\_wall.type = "wall";  
  
 --Add physics bodies  
 physics.addBody(ceiling, "static");  
 physics.addBody(ground, "static");  
 physics.addBody(left\_wall, "static");  
 physics.addBody(right\_wall, "static");  
  
 --Insert into groups  
 foreground:insert(ceiling);  
 foreground:insert(ground);  
 foreground:insert(left\_wall);  
 foreground:insert(right\_wall);  
  
  
 local function endGame (e)  
 print ("Game Over");  
 ready = false;  
 end  
  
 local function touchCheck(e)  
 local object1 = e.target  
 local object2 = e.other  
 if(object1.type == "bean" and object2.type == "bean") then  
 if(e.phase == "began") then  
 if(object1.colour == object2.colour) then  
 if(#object1.touching \> 0) then  
 inTable = false;  
 for k=#object1.touching, 1 do  
 if (object1.touching[k] == object2) then  
 inTable = true;  
 --print ("existing");  
 end  
 end  
 if(inTable == false) then  
 object1.touching[#object1.touching+1] = object2;  
 --print ("additional add");  
 end  
 else  
 object1.touching[1] = object2;  
 --print ("new add");  
 end  
  
 if (#object2.touching \> 0) then  
 inTable = false;  
 for k=#object2.touching, 1 do  
 if (object2.touching[k] == object1) then  
 inTable = true;  
 --print ("existingobj2");  
 end  
 end  
 if(inTable == false) then  
 object2.touching[#object2.touching+1] = object1;  
 --print ("additional addobj2");  
 end  
 else  
 object2.touching[1] = object1;  
 --print ("new addobj2");  
 end  
  
 end  
 elseif(e.phase == "ended") then  
 if(object1.colour == object2.colour) then  
 if (#object1.touching \> 0) then  
 for k=#object1.touching, 1, -1 do  
 if (object1.touching[k] == object2) then  
 object1.touching[k] = nil;  
 --print ("removed");  
 end  
 end  
 end  
 if (#object2.touching \> 0) then  
 for k=#object2.touching, 1, -1 do  
 if (object2.touching[k] == object1) then  
 object2.touching[k] = nil;  
 --print ("removedobj2");  
 end  
 end  
 end  
 end  
 end  
 end  
 end  
  
 local function matchCheck(e)  
 local object1 = e.target  
 local object2 = e.other  
 if(object1.type == "bean" and object2.type == "bean") then  
 if(e.phase == "began") then  
 if(#object1.touching \>= 2 or #object2.touching \>= 2) then  
 for m=#object1.touching, 1, -1 do  
 if (object1.touching[m] ~= nil) then  
 if (object1.touching[m] ~= object2) then  
 timer.performWithDelay(10, object1.touching[m]:pop());  
 end  
 end  
 end  
 for k=#object2.touching, 1, -1 do  
 if (object2.touching[m] ~= nil) then  
 if (object2.touching[m] ~= object1) then  
 timer.performWithDelay(10, object2.touching[k]:pop());  
 end  
 end  
 end  
 timer.performWithDelay(10, object1:pop());  
 timer.performWithDelay(10, object2:pop());  
 end  
 end  
 end  
 end  
  
 local function spawn(e)  
 if(ready == true) then  
 i = i + 1;  
 local rand = m.random(1,3);   
 local colour = beanColours[rand];  
  
 local b = bean.newBean(colour);  
 b:addEventListener("collision", touchCheck);  
 b:addEventListener("collision", matchCheck);  
 beans[i] = b;  
  
 foreground:insert(beans[i]);  
  
 end  
 end  
  
 local tmr = timer.performWithDelay(1000, spawn, -1);  
  
 ceiling:addEventListener("collision", endGame);  
 --Runtime:addEventListener("collision", matchCheck);  
  
 return Scene;  
end  

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

function newBean(colour)

local bean = display.newImage(“images/”…colour…".png");
bean.x = display.contentWidth*0.5; bean.y = 40;

–Setup properties
bean.type = “bean”;
bean.touching = {};
bean.colour = colour;

function bean:pop()

–hide the object
self.isVisible = false;

–Finally remove the object
self:removeSelf();
self = nil;
collectgarbage(“collect”);
end

local left = { -7,-4, 12,24, -5,29, -21,30, -33,25, -40,18, -41,7, -34,1 };
local right = { -8,-7, 4,-20, 16,-32, 28,-30, 35,-20, 34,-2, 27,11, 11,22 };
physics.addBody( bean,
{ density=100, friction=1, bounce=0, shape=left},
{ density=100, friction=1, bounce=0, shape=right}
)

return bean;
end
[/code] [import]uid: 31694 topic_id: 22484 reply_id: 90706[/import]

Use display.remove(object) instead of removeSelf. It should get rid of those nil errors [import]uid: 84637 topic_id: 22484 reply_id: 90721[/import]

One problem I see is you used ‘k’ in the for loop and then used ‘m’ instead of ‘k’ later in the code.
Here is the updated code section:
[lua] for k=#object2.touching, 1, -1 do
if (object2.touching[k] ~= nil) then
if (object2.touching[k] ~= object1) then
timer.performWithDelay(10, object2.touching[k]:pop());
end
end
end[/lua]

One thing you could do is consolidate the collision event into one routine. (combine touchCheck(e) and matchCheck(e))
You might want to at least have one collision call like this:

local function beanCollision(e)  
 touchCheck(e)  
 matchCheck(e)  
end  
b:addEventListener("collision", beanCollision);  

This will ensure order of the function calls, in that touchCheck(e) is called first, then matchCheck(e)
Jeff [import]uid: 14119 topic_id: 22484 reply_id: 90722[/import]

Good point Danny, however, using display.remove(object) will get rid of the error but not the problem. I think they might be close to fixing the problem which should get rid of the nil error.

Jeff
[import]uid: 14119 topic_id: 22484 reply_id: 90730[/import]

Thanks for your help guys. That actually seemed to work. For now I’m not getting any errors.

Occassionally it is delayed when removing 3 touching objects and some strange things happen when you have 4 beans touch, but that is because my code isnt designed to handle 4 touches. Ill need to have a think about that.

Thanks again, I really appreciate it. [import]uid: 31694 topic_id: 22484 reply_id: 90735[/import]