Trigonometry Problem

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
palcodev
Prole
Posts: 3
Joined: Mon Feb 29, 2016 3:45 pm

Trigonometry Problem

Post by palcodev »

Well, first of all, I'm not English fluent so sorry for any misspell or something like that. I'm actually Brazilian.

I'm developing a game (for android) in which a space ship can turn and shot in any direction. My first solution for doing this was a movement pad at the left and turning buttons at the right near to the fire button, like this:

Image
The print was took from it running on my pc, in the phone the controls look smaller

Well, some of my testers (read close friends with nothing better to do) complained about the difficult to turn and shot at the same time (I did not found it that hard but everyone that tested complained) so I choose to change it. Then I decided that the ship should aim the same direction that the pad is making it move (the force applied to the ship is proportional to the distance of the touch from the center of the circle). So I have the x variation of the touch and the y variation, but I needed an angle that I could set to the ship. My solution was to use acos(x) function that give me an angle for the relation (XVariation / LineLength), but it gives only values between 0 and pi and, this way, my ship would never aim up.

My solution for that was: aways that the YVariation (TouchY - CenterOfTheCircleY) where negative I just multiplied acos(x) by -1. That worked but the ship movement got really ugly because I was instantly setting the angle of the movement to the ship, what means: if you move to the right and then touch the left it instantly aims to the left (like an angular teleport). I want the ship to choose the shorter direction and turn fast, but not instantly and I'm failing miserable to find a solution for that.

Is there any other way to get the angle from YVariation and XVariation that would not get stucked between 0 and pi (or -pi / 2 and pi / 2 for asin(x))? Because the problem is that the movement angle is only between 0 and pi but the angle of the ship should be able to be any value (if it only turns into the clockway it would always increase) so I can't compare then for choosing the shorter angular distance.

Please help me.
Thanks for reading.
I already löve you. :awesome:
User avatar
Nuthen224
Citizen
Posts: 50
Joined: Sun Jul 28, 2013 9:40 pm

Re: Trigonometry Problem

Post by Nuthen224 »

I am not very sure of what your problem is exactly, but I think you need to be using "math.atan2(YVariation, XVariation)". It will find the angle you need.
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Trigonometry Problem

Post by ivan »

atan2 can be used if you have one vector:
vector = touchPosition - padCenterPosition
angle = atan2(vector.y, vector.x)

Code: Select all

--- Returns the angle in radians between two points
--- Non-commutative:
-- ang(a,b) == -ang(b,a)
--- Result:
-- 0 <= A <= pi (depending on the angle between the two points)
-- A is zero when the two points are equal
--- Parameters:
-- @param ax, ay first point
-- @param bx, by second point
-- @return the angle between the two points
function vec.ang(x1, y1, x2, y2)
  return atan2(y1 - y2, x1 - x2)
end
if you have 2 angles (let's call these 'target angle' and 'heading angle')
and we want to find the 'arc' between them:
arc = ( heading - target + math.pi ) % ( 2 * math.pi ) - math.pi

Code: Select all

--- Returns the angle in radians between two vectors
--- Description:
-- Uses atan2 to find the angle (R) which is slightly less accurate then acos
-- Rd = atan2(b) - atan2(a)
-- R = (Rd + pi)%(2*pi) - pi
--- Non-commutative:
-- vang2(a,b) == -vang2(b,a)
--- Result:
-- -pi <= R < pi (depending on the angle between the vectors)
-- R could be -pi but never pi
-- R could be non-zero even when one of the vectors has zero length
--- Parameters:
-- @param ax, ay first vector
-- @param bx, by second vector
-- @return the angle between the two vectors
function vec.vang2(ax, ay, bx, by)
  local a = atan2(by, bx) - atan2(ay, ax)
  return (a + pi)%(pi2) - pi
end
arcos can be used when you have two vectors and you want the angle between them.

Code: Select all

--- Returns the angle in radians between two vectors
--- Description:
-- Uses the dot product (D) to find the angle (A) between two vectors (a,b)
-- normalized vectors:
-- D = dot(a,b)
-- cos(A) = D
-- A = acos(D)
-- non-normalized vectors:
-- D = dot(a,b)
-- cos(A) = D/(len(a)*len(b))
-- A = acos(D/(len(a)*len(b)))
--- Non-commutative:
-- vang(a,b) == -vang(b,a)
--- Result:
-- -pi <= A <= pi (depending on the angle between the two vectors)
-- A is zero when one of the vectors has zero length
--- Parameters:
-- @param ax, ay first vector
-- @param bx, by second vector
-- @return the angle between the two vectors
function vec.vang(ax, ay, bx, by)
  -- local a = len2(ax, ay)*len2(bx, by)
  local a = (ax*ax + ay*ay)*(bx*bx + by*by)
  a = sqrt(a)
  if a > 0 then
    -- a = acos(dot(ax, ay, bx, by)/a)
    a = acos((ax*bx + ay*by)/a)
    if ax*by - ay*bx < 0 then
      a = -a
    end
  end
  return a
end
The key difference between atan2 and acos in the latter two examples:
with atan2(by, bx) - atan2(ay, ax) the result could be non-zero even when one of the vectors has zero length
while with acos the result is zero when one of the vectors has zero length
User avatar
pgimeno
Party member
Posts: 3657
Joined: Sun Oct 18, 2015 2:58 pm

Re: Trigonometry Problem

Post by pgimeno »

Another formulation for the angle between two vectors is: atan2(|axb|, a·b), which when z = 0 simplifies to the following Lua function:

Code: Select all

function vangle(ax, ay, bx, by)
  return math.atan2(ax*by-bx*ay, ax*bx+ay*by)
end
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Trigonometry Problem

Post by ivan »

Hi, can you please explain or show some references, from what I see, the code equates to:
? = atan2(cross(a,b), dot(a,b))
some online sources mention atan2(norm(cross(a,b)), dot(a,b)) but I have to do more research
monolifed
Party member
Posts: 188
Joined: Sat Feb 06, 2016 9:42 pm

Re: Trigonometry Problem

Post by monolifed »

norm(a cross b) = |a||b|sinC
a dot b = |a||b|cosC

C angle between a and b

Edit:
Also AFAIK C is the small angle thus between 0 and pi
and atan2 might give results between 0 and pi I am too lazy to verify it though
Edit2:
ax*by-bx*ay is different from norm(a x b) as it preserves sign
thus atan2 gives results accordingly
User avatar
pgimeno
Party member
Posts: 3657
Joined: Sun Oct 18, 2015 2:58 pm

Re: Trigonometry Problem

Post by pgimeno »

Yes, that. In 3D, angles out of the range [0, pi] don't make sense, but in 2D the sign counts.
palcodev
Prole
Posts: 3
Joined: Mon Feb 29, 2016 3:45 pm

Re: Trigonometry Problem

Post by palcodev »

Thank you a lot, I got the solution just like some of you said. Got two vectors: the PadVector and the ShipVector (wich I had only the angle so I used [cos(ShipAngle), sin(ShipAngle)] as a vector because it's length is 1.

cos(a) = (Padvector . ShipVector) / (PadVectorLength * ShipVectorLength)

so: a = acos((PadDX * sin(ShipAngle) + PadDY * cos(ShipAngle))) / (PadVectorLength * 1) )

Then I've got an angle that could be positive or negative telling me to turn clockwise or not. But when this results to zero that means Padvector . ShipVector == 0 so the angle between the pad and the ship is math.pi / 2. What means that when I was moving left the ship was faceing up and when I was moving up the ship was faceing right. But I alredy found a solution for that. I do not use the Ship.body:getAngle() but a Ship.Angle wich is math.pi / 2 smaller then the body angle. It works fluid and fine. If you want to I could share the code I'm working on. I'm not sure what I'll do with that, but I'll certainly finish it.

Thank you a lot, it's the first time I posted here and you are awesome! I'll try to help others to.
Last edited by palcodev on Tue Mar 01, 2016 2:15 pm, edited 2 times in total.
palcodev
Prole
Posts: 3
Joined: Mon Feb 29, 2016 3:45 pm

Re: Trigonometry Problem

Post by palcodev »

ingsoc451 wrote:norm(a cross b) = |a||b|sinC
a dot b = |a||b|cosC

C angle between a and b

Edit:
Also AFAIK C is the small angle thus between 0 and pi
and atan2 might give results between 0 and pi I am too lazy to verify it though
Edit2:
ax*by-bx*ay is different from norm(a x b) as it preserves sign
thus atan2 gives results accordingly
Yeah! That's what I used, thanks! The sign preservation was vital so I could know wich way to turn. for the ship vector I just use [cos(ShipAngle), sin(ShipAngle)] and it got too easy.
Post Reply

Who is online

Users browsing this forum: No registered users and 7 guests