Page 1 of 3

Collision and destroy problems

Posted: Thu Nov 06, 2008 3:04 pm
by Nexion
For whatever reason, my collision function will not detect ANY collisions.

Code: Select all

function collision(a,b,c)
	local f, r = c:getFriction(), c:getRestitution() 
    local s = c:getSeparation() 
    local px, py = c:getPosition() 
    local vx, vy = c:getVelocity() 
    local nx, ny = c:getNormal() 
	for k, v in pairs(bulletShapes) do
		if a == v or b == v then
			if b == mobShape or a == mobShape then
				mobDamage = mobDamage + 2
			end
			bulletIndex = k
			a:destroy()
			b:destroy()
			bullets[k]:destroy()
		end
	end
end
I'm just trying to detect if any of the bullets fired (all the bodies are stored in the "bullets" table, and the shapes are also stored exclusively in the "bulletShapes" table) so I can add some damage to the mob.
The weird thing is, I can't even get any callbacks from collision, even with just a simple text display; so it's probably not my code that's wrong.
Did the callback change in 0.5.0?

Also - whenever I CAN get to a point to use :destroy() to get rid of the bullets (I cheated and tried doing it in the update function checking distance, but that's hacky and I want the actual collision function to do it because my mob is a diamond, so the collisions wouldn't be right) LOVE errors and says "attempt to call method 'destroy' (a nil value)". I know you have to delete the shapes first, but it's just erroring.

Code: Select all

	for k, v in pairs(bullets) do
		for j, n in pairs(bullets) do
			if dist(v.b:getX(), v.b:getY(), n.b:getX(), n.b:getY()) <= 2 then
				n.s:destroy() --shape member of the bullets table
				v.s:destroy() --same as above
				n.b:destroy() --body member of the bullets table
				v.b:destroy() --same as above
			end
		end
	end

Re: Collision and destroy problems

Posted: Thu Nov 06, 2008 3:58 pm
by rude
Love.physics has hardly been touched since initial release, and callbacks seem to work fine (see "Mini Physics Callbacks" in the example browser).

As for your problems: what did you pass to Shape:setData? Your second problem is very weird. What does the entries in the bullets-table look like?

Clarification: you do not need to destroy stuff in a specific order, but if you destroy a body before an attatched shape, that body will not really be destroyed until the attatched shape is destroyed too.

Re: Collision and destroy problems

Posted: Thu Nov 06, 2008 9:17 pm
by Nexion
Here, I'll just post the entire code (some changes made since last post)

Code: Select all

local phys = love.physics
local graph = love.graphics
local time = love.timer
local aud = love.audio

local bullets = {}
function load() 
	world = phys.newWorld(1024, 768)
	world:setGravity(0, 15)
	graph.setBackgroundColor(100,100,255)
	LCannonBody = phys.newBody(world, 256, 768, 0)
	LCannonShape = phys.newCircleShape(LCannonBody, 15)
	LCannonShape:setData("LeftCannon");
	LBarrelBody = phys.newBody(world, 256, 758, 0)
	LBarrelShape = phys.newRectangleShape(LBarrelBody, 45, 5)
	LBarrelShape:setData("LeftBarrel")
	LBarrelBody:setAngle(0)
	
	MCannonBody = phys.newBody(world, 512,768,0)
	MCannonShape = phys.newCircleShape(MCannonBody, 15)
	MCannonShape:setData("MidCannon");
	MBarrelBody = phys.newBody(world, 512, 758,0)
	MBarrelShape = phys.newRectangleShape(MBarrelBody, 45, 5)
	MBarrelShape:setData("MidBarrel")
	MBarrelBody:setAngle(0)
	
	RCannonBody = phys.newBody(world, 768,768,0)
	RCannonShape = phys.newCircleShape(RCannonBody, 15)
	RCannonShape:setData("RightCannon");
	RBarrelBody = phys.newBody(world, 768, 758,0)
	RBarrelShape = phys.newRectangleShape(RBarrelBody, 45, 5)
	RBarrelShape:setData("RightBarrel")
	RBarrelBody:setAngle(0)
	
	local f = love.graphics.newFont(love.default_font, 14)
    	love.graphics.setFont(f)
		
	mob = phys.newBody(world, math.random(50,984), 0)
	mobDamage = 0
	mob:setMass(0,0,200,0)
	mobShape = phys.newCircleShape(mob, 5)
	mobShape:setData("Mob")
	nextDamage = 0
	
	mob:applyImpulse(math.random(-15000,15000),75)

	cannonFire = aud.newSound("sounds/cannon.wav")
end

function update(dt)
	world:update(dt)
	CurTime = love.timer.getTime()
	mPosX, mPosY = love.mouse.getPosition()
	
	lbPosX, lbPosY = LBarrelBody:getPosition()
	mbPosX, mbPosY = MBarrelBody:getPosition()
	rbPosX, rbPosY = RBarrelBody:getPosition()
	
	LBarrelBody:setAngle(math.deg(math.atan2(lbPosY-mPosY,lbPosX-mPosX)))
	MBarrelBody:setAngle(math.deg(math.atan2(mbPosY-mPosY,mbPosX-mPosX)))
	RBarrelBody:setAngle(math.deg(math.atan2(rbPosY-mPosY,rbPosX-mPosX)))

	for k, v in pairs(bullets) do
		if v.b:getX() > 1024 or v.b:getX() < 0 or v.b:getY() < 0 then
			table.remove(bullets, k)
		end
	end
end

function dist(x1,y1,x2,y2) 
	return ((x1^2+y1^2)^.5) - ((x2^2+y2^2)^.5)
end


text = ""
function draw() 

	graph.draw(text, 50, 50)
	graph.setColor(200, 200, 200);
		
	graph.polygon(love.draw_line, LBarrelShape:getPoints())
	graph.polygon(love.draw_line, MBarrelShape:getPoints())
	graph.polygon(love.draw_line, RBarrelShape:getPoints())
	graph.circle(0,LCannonBody:getX(), LCannonBody:getY(), 15, 360)
	graph.circle(0,MCannonBody:getX(), MCannonBody:getY(), 15, 360)
	graph.circle(0,RCannonBody:getX(), RCannonBody:getY(), 15, 360)
	for k,v in ipairs(bullets) do
		graph.circle(2, v.b:getX(), v.b:getY(), 2, 360)
	end
	
	graph.setColor(255,100,100)
	graph.circle(0, mob:getX(), mob:getY(), 10, 4)
	graph.setColor(255,255,255)
	graph.rectangle(0, mob:getX() - 13.5, mob:getY() - 19, 27, 7)
	graph.setColor(255,50,50)
	mobHealth = (25 - mobDamage)
	graph.rectangle(0, mob:getX() - 12.5, mob:getY() - 18, mobHealth, 5)
	
	graph.draw(mobDamage, 100, 100) 
end 

function keypressed(k) 
	if k == love.key_r then
		love.system.restart()
	end
end 

lastclick = 0
function mousepressed(x1, y1, button) 
	if button == love.mouse_left and lastclick + 0.1 <= love.timer.getTime() then--or button == love.mouse_wheeldown or button == love.mouse_wheelup then --
		lastclick = love.timer.getTime()
		
		local spawner
		if x1 < 384 then spawner = LBarrelBody elseif x1 < 640 then spawner = MBarrelBody else spawner = RBarrelBody end
		local x2, y2 = spawner:getPosition()
		local sPosX, sPosY = 512, 768
		local sAngle = spawner:getAngle()

		sPosX = x2 + math.cos(math.rad(sAngle-180)) * 30
		sPosY = y2 + math.sin(math.rad(sAngle-180)) * 30

		t = {}
		bulletShapes = {}
		t.b = phys.newBody(world, sPosX, sPosY, 1)
		t.s = phys.newCircleShape(t.b, 3)
		table.insert(bulletShapes, t.s)
		--t.b:setBullet(true)
		t.s:setData("Bullet")
		table.insert(bullets, t)
		t.b:setVelocity(math.cos(math.rad(sAngle-180)) * 5000000,math.sin(math.rad(sAngle-180)) * 5000000)
		
		aud.play(cannonFire)
	end 
end 

function collision(a,b,c)
	local f, r = c:getFriction(), c:getRestitution() 
    local s = c:getSeparation() 
    local px, py = c:getPosition() 
    local vx, vy = c:getVelocity() 
    local nx, ny = c:getNormal() 
	--for k, v in pairs(bulletShapes) do
		if a == "Bullet" or b == "Bullet" then
			if b == "Mob" or a == "Mob" then
				mobDamage = mobDamage + 2
			end
			bulletIndex = k
			a:destroy()
			b:destroy()
			bullets[k]:destroy()
		end
	--end
end
I wasn't sure if you could reference the shapes directly in the collision function or if you had to pass them with their setData value. Either way it still didn't work.
And I know you have to destroy them in the right order, and I believe I am doing it correctly, that's not what i'm saying. :destroy() is simply throwing an error saying it doesnt exist whenever i try to use it.

Re: Collision and destroy problems

Posted: Fri Nov 07, 2008 12:17 am
by rude
Nexion wrote:And I know you have to destroy them in the right order
No you don't, see my post:
rude wrote:Clarification: you do not need to destroy stuff in a specific order, but if you destroy a body before an attatched shape, that body will not really be destroyed until the attatched shape is destroyed too.
As far as I can tell, you're setting the data of the bullets as strings:

Code: Select all

t.s:setData("Bullet")
In your collision callback, this string will be passed as one of the parameters:

Code: Select all

function collision(a,b,c)
-- ...
-- a and b are strings, and do obviously not
-- have a destroy() method.
a:destroy()
b:destroy()
-- ...
end
I made an example which demonstates how to remove bodies/shapes in different ways. It may not be the best example ever, but hopefully it can help you a little.

Re: Collision and destroy problems

Posted: Fri Nov 07, 2008 1:44 am
by Nexion
oh ok, i misread what you had posted.

And if a and b are strings, then the docs are wrong, because the docs say that collision passes the shapes, not their data strings

Re: Collision and destroy problems

Posted: Fri Nov 07, 2008 2:02 am
by rude
Do you know which page? I would like to correct it if it really says that.

Re: Collision and destroy problems

Posted: Fri Nov 07, 2008 2:28 am
by Nexion
http://love2d.org/docs/Contact.html
It doesn't REALLY say that, but from looking at it that was the impression I got from it.

And I put
text = a .. ", " .. b
in the collision function then drew text with the draw function, and no matter what hits where, it never shows ANYTHING

Re: Collision and destroy problems

Posted: Fri Nov 07, 2008 2:38 am
by Nexion
*sigh* nevermind I'm an idiot, I forgot to set the callback to the world...

Re: Collision and destroy problems

Posted: Fri Nov 07, 2008 2:48 am
by rude
Ah, I just noticed that myself! :D

Silly me, I should have paid more attention to your code. On the plus side, all this love.physics-investigating has been been very useful. I found at least one weakness I didn't consider.

This code will create a cyclic dependency, and the shape/body can never be garbage collected.

Code: Select all

local b = love.physics.newBody()
local s = love.physics.newShape(b)
local t = { b = b, s = s }
s:setData(t)
I suppose weak tables or something would be a solution to this.

Re: Collision and destroy problems

Posted: Fri Nov 07, 2008 3:19 am
by Nexion
I'm trying to implement your code into mine, and I think I have everything right, but LOVE is still complaining about destroy() being a nil value, even though its being called on entities.b and .s

Do you have MSN or GTalk or something so we don't have to take up forum space and for faster responses?