collision detection problem with physics.removeBody

hi everybody,

in this game when a player lands on the border dies. Each time, it triggers a next level if the number of players killed the equal level.

The problem is that when i have fast collisions i have this bug :

physcis.removeBody() given a display object that is not a physic object 

…why? Can you help me ?

-------------------------------------------------------------------------------- -- require -------------------------------------------------------------------------------- local physics = require("physics") physics.start() physics.setScale(15) physics.setGravity(0,3) -------------------------------------------------------------------------------- --variables -------------------------------------------------------------------------------- local border local player={} local level = 1 local cnt=0 local flagStart=true -------------------------------------------------------------------------------- -- load Elements -------------------------------------------------------------------------------- local function gameInit()     border=display.newRect(100,400,100000,10)     physics.addBody(border,"static")     for i=1, 9 do         player[i]=display.newCircle(200+i\*5,100,5)         player[i].name="player"         player[i].isDead=false         player[i].isVisible=false         player[i].kill = function()             function kill()                 if not ( physics.removeBody( player[i] ) ) then                     print( "Could not remove physics body" )             else                 print("ok")                 player[i].isDead=true                 player[i].isVisible=false                 end             end             timer.performWithDelay(5,kill)         end     end end -------------------------------------------------------------------------------- -- appears Elements -------------------------------------------------------------------------------- local function startLevel(w) --put the player at the top to fall again on the border     for i=1, w do         print("startLevel")         player[i].y=i-100         player[i].isDead=false         player[i].isVisible=true         physics.addBody(player[i]) flagStart=true     end end ---------------------------------------------------------------------- gameInit() startLevel(1) local function onCollision(event)     if event.phase == "began" then         if event.other.name == "player" then             print("collision began with player")             event.other.kill()         end     elseif event.phase =="ended" then         if event.other.name == "player" then             print("collision ended with player")                 cnt = cnt +1 --count the number of player dead                 if cnt == level and flagStart then                     flagStart=false --to prevent multiple startlevel()                     cnt=0 --to reset the count because we start a new level                     level=level+1                     if level \> #player then                         level =1 --to loop                     end                     timer.performWithDelay(10,function() startLevel(level) end)                 end             end     end end border:addEventListener( "collision",onCollision )

pfiuuu it was very difficult …if someone have a simpliest solution…thanks a lot

-------------------------------------------------------------------------------- -- require -------------------------------------------------------------------------------- local physics = require("physics") physics.start() physics.setScale(15) physics.setGravity(0,3) -------------------------------------------------------------------------------- --variables -------------------------------------------------------------------------------- local border local player={} local level = 1 local cnt=0 local flagStart=true -------------------------------------------------------------------------------- -- load Elements -------------------------------------------------------------------------------- local function gameInit() border=display.newRect(100,400,100000,10) physics.addBody(border,"static") for i=1, 9 do player[i]=display.newCircle(200+i\*5,100,5) player[i].name="player" player[i].isDead=false player[i].isVisible=false player[i].kill = function() function kill() if not ( physics.removeBody( player[i] ) ) then print( "Could not remove physics body" ) else print("ok") player[i].isDead=true player[i].isVisible=false cnt = cnt +1 --count the number of player dead if cnt == level then flagStart=true cnt=0 --to reset the count because we start a new level level=level+1 if level \> #player then level =1 --to loop end else flagStart=false end end end timer.performWithDelay(5,kill) end end end -------------------------------------------------------------------------------- -- appears Elements -------------------------------------------------------------------------------- local function startLevel(w) --put the player at the top to fall again on the border if flagStart then for i=1, w do print("startLevel") player[i].y=-i\*20 player[i].isDead=false player[i].isVisible=true physics.addBody(player[i]) flagStart=true end end end ---------------------------------------------------------------------- gameInit() startLevel(1) local function onCollision(event) if event.phase == "began" then if event.other.name == "player" then print("collision began with player") event.other.kill() end elseif event.phase =="ended" then if event.other.name == "player" then print("collision ended with player") timer.performWithDelay(10,function() startLevel(level) end) end end end border:addEventListener( "collision",onCollision )

i ave still a problem after a certain delay my code say

Warning: z:\main.lua:33: physics.removeBody() given a display object that is not a physics object

and then my levels stop

…could you help me to remove my bodys properly please ?

Hi @laurent.cth,

On collision, do you simply want to destroy “player” objects? If so, must these player objects continue to exist, or can you remove them entirely from the simulation?

Brent

Hi,

i want only to physics.removeBody my player when a collision occurs to prevent memory due to physics.

My player still exist but the physics is stop for him.

There is no way to make what i want  ?

i make an another approach with a transition and onComplete and it’s the same. It’s crazy i don’t see my mystake…my snippet is logic. everything is possible in programming and there i can not .

i put a video link to show what i do :

https://youtu.be/WmrwcBDOJRA

-------------------------------------------------------------------------------- -- require -------------------------------------------------------------------------------- local physics = require("physics") physics.start() physics.setScale(95) physics.setGravity(0,3) -------------------------------------------------------------------------------- --variables -------------------------------------------------------------------------------- local border local player={} local level = 1 local cnt=0 local flagStart=true -------------------------------------------------------------------------------- -- load Elements -------------------------------------------------------------------------------- local function gameInit() border=display.newRect(100,400,100000,10) physics.addBody(border,"static") for i=1, 9 do player[i]=display.newCircle(200+i\*5,100,5) player[i].name="player" player[i].isDead=true player[i].isVisible=false end end -------------------------------------------------------------------------------- -- appears Elements -------------------------------------------------------------------------------- local function startLevel(w) --put the player at the top to fall again on the border if flagStart then flagStart=false for i=1, w do print("startLevel") player[i].y=-i\*20 player[i].x=100 player[i].isDead=false player[i].isVisible=true physics.addBody(player[i]) end end end ---------------------------------------------------------------------- gameInit() startLevel(1) local function onCollision(event) if event.phase == "began" then if event.other.name == "player" then print("collision began with player") end elseif event.phase =="ended" then if event.other.name == "player" then event.other.isDead=true event.other.isVisible=false local function removeBody() physics.removeBody(event.other)--that s what i want to do cnt = cnt +1 --count the number of player dead if cnt == level then flagStart=true cnt=0 --to reset the count because we start a new level level=level+1 if level \> #player then level =1 --to loop end end end transition.to(event.other, {time=50,x=math.random(5,500),y=5, onComplete=removeBody}) print("collision ended with player") timer.performWithDelay(60,function() startLevel(level) end) --with flagstart on true the level start end end end border:addEventListener( "collision",onCollision )

Hi @laurent.cth,

Can you describe what is not working at this time?

You should probably not be using the “ended” phase of the collision, unless your objects are sensor types. Normally, collisions are handled in the “began” phase, and then if you need to perform some action which requires a delay, like removeBody(), just perform it then. Using a transition should be fine too.

Best regards,

Brent

hi Brent,

i have update my snippet with the began phase and still the same problem : after a certain delay i have this error :

physcis.removeBody() given a display object that is not a physic object

-------------------------------------------------------------------------------- -- require -------------------------------------------------------------------------------- local physics = require("physics") physics.start() physics.setScale(95) physics.setGravity(0,30) local monitorMem = function() collectgarbage() print( "MemUsage: " .. collectgarbage("count") ) local textMem = system.getInfo( "textureMemoryUsed" ) / 1000000 print( "TexMem: " .. textMem ) end --Runtime:addEventListener( "enterFrame", monitorMem ) -------------------------------------------------------------------------------- --variables -------------------------------------------------------------------------------- local border local player={} local level = 1 local cnt=0 local flagStart=true -------------------------------------------------------------------------------- -- load Elements -------------------------------------------------------------------------------- local function gameInit() border=display.newRect(100,400,100000,10) physics.addBody(border,"static") for i=1, 9 do player[i]=display.newCircle(200+i\*5,100,5) player[i].name="player" player[i].isDead=true player[i].isVisible=false end end -------------------------------------------------------------------------------- -- appears Elements -------------------------------------------------------------------------------- local function startLevel(w) --put the player at the top to fall again on the border if flagStart then flagStart=false for i=1, w do print("startLevel"..w) player[i].y=-i\*20 player[i].x=100 player[i].isDead=false player[i].isVisible=true physics.addBody(player[i]) end end end ---------------------------------------------------------------------- gameInit() startLevel(1) local function onCollision(event) if event.phase == "began" then if event.other.name == "player" then print("collision began with player") event.other.isDead=true event.other.isVisible=false local function removeBody() physics.removeBody(event.other) cnt = cnt +1 --count the number of player dead if cnt == level then flagStart=true cnt=0 --to reset the count because we start a new level level=level+1 if level \> #player then level=1 --to loop end end timer.performWithDelay(60,function() startLevel(level) end) end transition.to(event.other, {time=50,x=math.random(5,500),y=50000, onComplete=removeBody}) print("collision ended with player") end elseif event.phase =="ended" then if event.other.name == "player" then end end end border:addEventListener( "collision",onCollision )

Hi @laurent.cth,

It’s possible that, even when you mark an object as “dead”, it’s still colliding with the “border” again, so then it triggers another “die” process, but the first one has already occurred so the code stumbles and reports that it’s not a physics body any longer.

Try this:

FIRST, remove these lines:

[lua]

event.other.isDead=true

event.other.isVisible=false

[/lua]

Now, surround your transition call with a conditional check on the “isDead” property, and put the above lines inside it:

[lua]

if ( event.other.isDead == false ) then

   event.other.isDead = true

   event.other.isVisible = false

   transition.to(event.other, {time=50,x=math.random(5,500),y=50000, onComplete=removeBody})

end

[/lua]

thanks, it was that. Is it finally a good solution to remove my physic body from the scene. i put a memory usage on both file (one with removebody and  another without removebody) and the result is that without removebody my memory usage is lower.

have you an advice on that ?

-------------------------------------------------------------------------------- -- require -------------------------------------------------------------------------------- local physics = require("physics") physics.start() physics.setScale(95) physics.setGravity(0,30) local monitorMem = function() collectgarbage() print( "MemUsage: " .. collectgarbage("count") ) local textMem = system.getInfo( "textureMemoryUsed" ) / 1000000 print( "TexMem: " .. textMem ) end --Runtime:addEventListener( "enterFrame", monitorMem ) -------------------------------------------------------------------------------- --variables -------------------------------------------------------------------------------- local border local player={} local level = 1 local cnt=0 local flagStart=true -------------------------------------------------------------------------------- -- load Elements -------------------------------------------------------------------------------- local function gameInit() border=display.newRect(100,400,100000,10) physics.addBody(border,"static") for i=1, 9 do player[i]=display.newCircle(200+i\*5,100,5) player[i].name="player" player[i].isDead=true player[i].isVisible=false end end -------------------------------------------------------------------------------- -- appears Elements -------------------------------------------------------------------------------- local function startLevel(w) --put the player at the top to fall again on the border if flagStart then flagStart=false for i=1, w do print("startLevel"..w) player[i].y=-i\*20 player[i].x=100 player[i].isDead=false player[i].isVisible=true physics.addBody(player[i]) end end end ---------------------------------------------------------------------- gameInit() startLevel(1) local function onCollision(event) if event.phase == "began" then if event.other.name == "player" then print("collision began with player") if ( event.other.isDead == false ) then event.other.isDead = true event.other.isVisible = false local function removeBody() physics.removeBody(event.other) cnt = cnt +1 --count the number of player dead if cnt == level then flagStart=true cnt=0 --to reset the count because we start a new level level=level+1 if level \> #player then level=1 --to loop end end timer.performWithDelay(60,function() startLevel(level) end) end transition.to(event.other, {time=50,x=math.random(5,500),y=50000, onComplete=removeBody}) end print("collision ended with player") end elseif event.phase =="ended" then if event.other.name == "player" then end end end border:addEventListener( "collision",onCollision )

Hi again,

If you’re re-using the same objects… but simply adding physics bodies to them when the level starts, and removing physics bodies after they collide with “border”… then your memory usage should remain approximately level.

Really, the main reason to “worry” would be if your memory usage continues going up and up and up, and never falls back down to a normal level. That would mean you have a memory leak somewhere and it would be wise to locate and fix it.

Brent

pfiuuu it was very difficult …if someone have a simpliest solution…thanks a lot

-------------------------------------------------------------------------------- -- require -------------------------------------------------------------------------------- local physics = require("physics") physics.start() physics.setScale(15) physics.setGravity(0,3) -------------------------------------------------------------------------------- --variables -------------------------------------------------------------------------------- local border local player={} local level = 1 local cnt=0 local flagStart=true -------------------------------------------------------------------------------- -- load Elements -------------------------------------------------------------------------------- local function gameInit() border=display.newRect(100,400,100000,10) physics.addBody(border,"static") for i=1, 9 do player[i]=display.newCircle(200+i\*5,100,5) player[i].name="player" player[i].isDead=false player[i].isVisible=false player[i].kill = function() function kill() if not ( physics.removeBody( player[i] ) ) then print( "Could not remove physics body" ) else print("ok") player[i].isDead=true player[i].isVisible=false cnt = cnt +1 --count the number of player dead if cnt == level then flagStart=true cnt=0 --to reset the count because we start a new level level=level+1 if level \> #player then level =1 --to loop end else flagStart=false end end end timer.performWithDelay(5,kill) end end end -------------------------------------------------------------------------------- -- appears Elements -------------------------------------------------------------------------------- local function startLevel(w) --put the player at the top to fall again on the border if flagStart then for i=1, w do print("startLevel") player[i].y=-i\*20 player[i].isDead=false player[i].isVisible=true physics.addBody(player[i]) flagStart=true end end end ---------------------------------------------------------------------- gameInit() startLevel(1) local function onCollision(event) if event.phase == "began" then if event.other.name == "player" then print("collision began with player") event.other.kill() end elseif event.phase =="ended" then if event.other.name == "player" then print("collision ended with player") timer.performWithDelay(10,function() startLevel(level) end) end end end border:addEventListener( "collision",onCollision )

i ave still a problem after a certain delay my code say

Warning: z:\main.lua:33: physics.removeBody() given a display object that is not a physics object

and then my levels stop

…could you help me to remove my bodys properly please ?

Hi @laurent.cth,

On collision, do you simply want to destroy “player” objects? If so, must these player objects continue to exist, or can you remove them entirely from the simulation?

Brent

Hi,

i want only to physics.removeBody my player when a collision occurs to prevent memory due to physics.

My player still exist but the physics is stop for him.

There is no way to make what i want  ?

i make an another approach with a transition and onComplete and it’s the same. It’s crazy i don’t see my mystake…my snippet is logic. everything is possible in programming and there i can not .

i put a video link to show what i do :

https://youtu.be/WmrwcBDOJRA

-------------------------------------------------------------------------------- -- require -------------------------------------------------------------------------------- local physics = require("physics") physics.start() physics.setScale(95) physics.setGravity(0,3) -------------------------------------------------------------------------------- --variables -------------------------------------------------------------------------------- local border local player={} local level = 1 local cnt=0 local flagStart=true -------------------------------------------------------------------------------- -- load Elements -------------------------------------------------------------------------------- local function gameInit() border=display.newRect(100,400,100000,10) physics.addBody(border,"static") for i=1, 9 do player[i]=display.newCircle(200+i\*5,100,5) player[i].name="player" player[i].isDead=true player[i].isVisible=false end end -------------------------------------------------------------------------------- -- appears Elements -------------------------------------------------------------------------------- local function startLevel(w) --put the player at the top to fall again on the border if flagStart then flagStart=false for i=1, w do print("startLevel") player[i].y=-i\*20 player[i].x=100 player[i].isDead=false player[i].isVisible=true physics.addBody(player[i]) end end end ---------------------------------------------------------------------- gameInit() startLevel(1) local function onCollision(event) if event.phase == "began" then if event.other.name == "player" then print("collision began with player") end elseif event.phase =="ended" then if event.other.name == "player" then event.other.isDead=true event.other.isVisible=false local function removeBody() physics.removeBody(event.other)--that s what i want to do cnt = cnt +1 --count the number of player dead if cnt == level then flagStart=true cnt=0 --to reset the count because we start a new level level=level+1 if level \> #player then level =1 --to loop end end end transition.to(event.other, {time=50,x=math.random(5,500),y=5, onComplete=removeBody}) print("collision ended with player") timer.performWithDelay(60,function() startLevel(level) end) --with flagstart on true the level start end end end border:addEventListener( "collision",onCollision )

Hi @laurent.cth,

Can you describe what is not working at this time?

You should probably not be using the “ended” phase of the collision, unless your objects are sensor types. Normally, collisions are handled in the “began” phase, and then if you need to perform some action which requires a delay, like removeBody(), just perform it then. Using a transition should be fine too.

Best regards,

Brent

hi Brent,

i have update my snippet with the began phase and still the same problem : after a certain delay i have this error :

physcis.removeBody() given a display object that is not a physic object

-------------------------------------------------------------------------------- -- require -------------------------------------------------------------------------------- local physics = require("physics") physics.start() physics.setScale(95) physics.setGravity(0,30) local monitorMem = function() collectgarbage() print( "MemUsage: " .. collectgarbage("count") ) local textMem = system.getInfo( "textureMemoryUsed" ) / 1000000 print( "TexMem: " .. textMem ) end --Runtime:addEventListener( "enterFrame", monitorMem ) -------------------------------------------------------------------------------- --variables -------------------------------------------------------------------------------- local border local player={} local level = 1 local cnt=0 local flagStart=true -------------------------------------------------------------------------------- -- load Elements -------------------------------------------------------------------------------- local function gameInit() border=display.newRect(100,400,100000,10) physics.addBody(border,"static") for i=1, 9 do player[i]=display.newCircle(200+i\*5,100,5) player[i].name="player" player[i].isDead=true player[i].isVisible=false end end -------------------------------------------------------------------------------- -- appears Elements -------------------------------------------------------------------------------- local function startLevel(w) --put the player at the top to fall again on the border if flagStart then flagStart=false for i=1, w do print("startLevel"..w) player[i].y=-i\*20 player[i].x=100 player[i].isDead=false player[i].isVisible=true physics.addBody(player[i]) end end end ---------------------------------------------------------------------- gameInit() startLevel(1) local function onCollision(event) if event.phase == "began" then if event.other.name == "player" then print("collision began with player") event.other.isDead=true event.other.isVisible=false local function removeBody() physics.removeBody(event.other) cnt = cnt +1 --count the number of player dead if cnt == level then flagStart=true cnt=0 --to reset the count because we start a new level level=level+1 if level \> #player then level=1 --to loop end end timer.performWithDelay(60,function() startLevel(level) end) end transition.to(event.other, {time=50,x=math.random(5,500),y=50000, onComplete=removeBody}) print("collision ended with player") end elseif event.phase =="ended" then if event.other.name == "player" then end end end border:addEventListener( "collision",onCollision )

Hi @laurent.cth,

It’s possible that, even when you mark an object as “dead”, it’s still colliding with the “border” again, so then it triggers another “die” process, but the first one has already occurred so the code stumbles and reports that it’s not a physics body any longer.

Try this:

FIRST, remove these lines:

[lua]

event.other.isDead=true

event.other.isVisible=false

[/lua]

Now, surround your transition call with a conditional check on the “isDead” property, and put the above lines inside it:

[lua]

if ( event.other.isDead == false ) then

   event.other.isDead = true

   event.other.isVisible = false

   transition.to(event.other, {time=50,x=math.random(5,500),y=50000, onComplete=removeBody})

end

[/lua]

thanks, it was that. Is it finally a good solution to remove my physic body from the scene. i put a memory usage on both file (one with removebody and  another without removebody) and the result is that without removebody my memory usage is lower.

have you an advice on that ?

-------------------------------------------------------------------------------- -- require -------------------------------------------------------------------------------- local physics = require("physics") physics.start() physics.setScale(95) physics.setGravity(0,30) local monitorMem = function() collectgarbage() print( "MemUsage: " .. collectgarbage("count") ) local textMem = system.getInfo( "textureMemoryUsed" ) / 1000000 print( "TexMem: " .. textMem ) end --Runtime:addEventListener( "enterFrame", monitorMem ) -------------------------------------------------------------------------------- --variables -------------------------------------------------------------------------------- local border local player={} local level = 1 local cnt=0 local flagStart=true -------------------------------------------------------------------------------- -- load Elements -------------------------------------------------------------------------------- local function gameInit() border=display.newRect(100,400,100000,10) physics.addBody(border,"static") for i=1, 9 do player[i]=display.newCircle(200+i\*5,100,5) player[i].name="player" player[i].isDead=true player[i].isVisible=false end end -------------------------------------------------------------------------------- -- appears Elements -------------------------------------------------------------------------------- local function startLevel(w) --put the player at the top to fall again on the border if flagStart then flagStart=false for i=1, w do print("startLevel"..w) player[i].y=-i\*20 player[i].x=100 player[i].isDead=false player[i].isVisible=true physics.addBody(player[i]) end end end ---------------------------------------------------------------------- gameInit() startLevel(1) local function onCollision(event) if event.phase == "began" then if event.other.name == "player" then print("collision began with player") if ( event.other.isDead == false ) then event.other.isDead = true event.other.isVisible = false local function removeBody() physics.removeBody(event.other) cnt = cnt +1 --count the number of player dead if cnt == level then flagStart=true cnt=0 --to reset the count because we start a new level level=level+1 if level \> #player then level=1 --to loop end end timer.performWithDelay(60,function() startLevel(level) end) end transition.to(event.other, {time=50,x=math.random(5,500),y=50000, onComplete=removeBody}) end print("collision ended with player") end elseif event.phase =="ended" then if event.other.name == "player" then end end end border:addEventListener( "collision",onCollision )