Page 1 of 1

Apply velocity in relation to getAngle()

Posted: Mon Sep 22, 2008 2:29 pm
by Nexion
I'm trying to get some simple cannons to work, but my angles keep getting screwed up for some reason.
My current code attempts to get the end of the barrel (which doesn't work quite right either) then throws the bullet outward with the angle of the barrel, but it always has a bias to the right.

Code: Select all

lastclick = 0
function mousepressed(x, y, button)
	if button == love.mouse_left then -- and lastclick + 0.1 <= love.timer.getTime() then
		lastclick = love.timer.getTime()

		local sPosX, sPosY
		local spawner

		if x < 256 then spawner = LBarrelBody elseif x < 768 then spawner = MBarrelBody elseif x > 768 then spawner = RBarrelBody end
		sPosX = spawner:getX() * math.cos(spawner:getAngle()) - spawner:getY() * math.sin(spawner:getAngle())
		sPosY = spawner:getX() * math.sin(spawner:getAngle()) + spawner:getY() * math.cos(spawner:getAngle())
		
		local x1, y1 = love.mouse.getPosition()
		local x2, y2 = spawner:getPosition()
		
		local dirx = math.atan2(y2 - y1, x2 - x1) * 180 / math.pi
		local diry = math.atan2(y1 - y2, x1 - x2) * 180 / math.pi		
		if x1 <= x2 then x1 = x2 + 5 end
		local t = {}
		t.b = phys.newBody(world, spawner:getX() + (dirx / 11), spawner:getY() + (diry / 3), 1)
		t.s = phys.newCircleShape(t.b, 5)
		t.b:setBullet(true)
		t.dirx = dirx
		t.diry = diry
		t.s:setData(t)
		table.insert(bullets, t)
		t.b:setVelocity(t.dirx / 3,t.diry * 2)
	end
end
There are 3 different barrels, only one fires at a time, detected by the location of the mouse on the screen.
Can anyone suggest how to apply velocity to the bullets more accurately then this? Sort of like an object:ApplyVelocityForward(force) using the angle the object is at.

Re: Apply velocity in relation to getAngle()

Posted: Mon Sep 22, 2008 6:57 pm
by Mr. Strange
Well for starters, I think it's less than ideal to be calculating the angle of your gun barrels at the time of firing - I think you would be better off computing their angle every frame, drawing them with that information, and then simply passing that orientation off to the projectiles. This requires a few more calculations, but it will show you right away where your errors are, since the barrels themselves will be mis-aligned.

You are using spawner:getX() and spawner:getY(), but later you use x,y = spawner:getPosition(). Wouldn't it be more sensible (and easier to read) if you did that just once?

Code: Select all

      local spawner
      local x1, y1 = love.mouse.getPosition()
      local x2, y2 = spawner:getPosition()
      local sPosX, sPosY
      local sAngle = spawner:getAngle()

      sPosX = x2 * math.cos(sAngle) - y2 * math.sin(sAngle)
      sPosY = x2 * math.sin(sAngle) + y2 * math.cos(sAngle)
      
      local dirx = math.atan2(y2 - y1, x2 - x1) * 180 / math.pi
      local diry = math.atan2(y1 - y2, x1 - x2) * 180 / math.pi      
      if x1 <= x2 then x1 = x2 + 5 end
All I've done is collapsed some of the stuff you wrote above - nothing has really changed yet.

The thing that jumps out to me is your calculations for sPosX and sPosY - you are scaling your sine and cosine results by the location of your turrets - that seems odd to me.

Here is what I imagine you are trying to do - your turret is at a fixed location, and fires a projectile at the point occupied by the mouse. In that case, you know that the base of your turret, the muzzle, and the mouse point are all collinear, which means your can eliminate lots of redundancy. If the turret has some tracking speed maximum, which would lead to it trailing behind the pointer, then you can't assume that.

Anyway, a reorganized code snippet and a better explanation of your constraints would be a big help.

--Mr. Strange

Re: Apply velocity in relation to getAngle()

Posted: Tue Sep 23, 2008 1:31 pm
by Nexion
Yeah, sorry about the slightly redundant code. I always clean things up after i get them working, which kinda screws me over some times.

Re: Apply velocity in relation to getAngle()

Posted: Tue Sep 23, 2008 1:40 pm
by Nexion
Mr. Strange wrote: The thing that jumps out to me is your calculations for sPosX and sPosY - you are scaling your sine and cosine results by the location of your turrets - that seems odd to me.
I was doing that to try to get the projectile to spawn at the end of the barrel

Here is the update function of the code

Code: Select all

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

	for k, v in ipairs(bullets) do
		if v.b:getX() > 1024 or v.b:getX() < 0 or v.b:getY() < 0 then
			table.remove(bullets, k) --Remove the bullets from the table once they're off the screen
                        v.b:destroy() --Remove the bullets from the game space
		end
	end
end

function angleBetween(ax, ay, bx, by) 
	local dotproduct, lengtha, lengthb, result;

	dotproduct = (ax * bx) + (ay * by);
	lengtha = length(ax,ay);
	lengthb = length(bx,by);

	result = math.acos( dotproduct / (lengtha * lengthb) );

	if dotproduct < 0 then
		if result > 0 then
			result = result + math.pi;
		else
			result = result - math.pi;
		end
	end
	
	return result;
end

function length(x,y)
	return math.sqrt(x*x+y*y)
end
Again a little redundancy, but it might help.

I just realized that some of this code I borrowed from another game (since I don't plan on releasing this) and it was screwing up some things.