Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

224
Vistas
Calculate minimum angle to rotate arrow to token

I am developing a platform game, and I would like there to be an arrow pointing to a token:

enter image description here

Just snapping the arrow to the token is fine - everything works correctly:

const dist_x = player.x - token.x
const dist_y = player.y - token.y
const angle = Math.atan2(dist_y, dist_x)

arrow.angle = angle

But the problem is that I would like the arrow to swing around the token as shown below. It works OK, but when the angle of the arrow is near 360 and the angle of the token is near 0, the code thinks that the arrow needs to swing all the way around to zero - as opposed to just adding up a bit and nicely looping around. This is my code:

const dist_x = player.x - token.x
const dist_y = player.y - token.y
const angle = Math.atan2(dist_y, dist_x) // angle between arrow & token

arrow.angle += arrow.rot_speed // acceleration
arrow.rot_speed *= .9 // slowly calm down

// distance between goal angle of arrow and angle at the moment
const angle_dist = angle - arrow.angle

// move in that direction
arrow.rot_speed += angle_dist

This problem has been a large stopping blocker for me on multiple occasions so I would appreciate any help.

about 4 years ago · Juan Pablo Isaza
3 Respuestas
Responde la pregunta

0

To fix something like this, you'd need to check if the difference of the angle you're swinging to is below 180, and if it's not, add 360 to the angle you're swinging to. I think that would fix the part where it would swing around. I don't know how you'd implement this in your code, but this is the general solution I came across on previous experiences.

Ofcourse, you'd need to convert all of this into radians :D

about 4 years ago · Juan Pablo Isaza Denunciar

0

I am not sure whether this helps. Suppose that there are values of dist_x and dist_y used to get the angle back using atan2() as follow

N = 8
r = 1
console.log("angle dist_x dist_y atan2 angle")
for(i = 0; i < N; i++)  {
  q = (i / 8) * 2 * Math.PI
  dist_x = r * Math.cos(q)
  dist_y = r * Math.sin(q)
  theta = Math.atan2(dist_y, dist_x)
  theta2 = theta
  if(q > Math.PI) {
    theta2 += 2 * Math.PI
  }
  console.log(
    q.toFixed(3),
    dist_x.toFixed(3),
    dist_y.toFixed(3),
    theta.toFixed(3),
    theta2.toFixed(3)
  )
}

that produces

angle   dist_x  dist_y  atan2  angle
0.000   1.000   0.000   0.000  0.000
0.785   0.707   0.707   0.785  0.785
1.571   0.000   1.000   1.571  1.571
2.356  -0.707   0.707   2.356  2.356
3.142  -1.000   0.000   3.142  3.142
3.927  -0.707  -0.707  -2.356  3.927   <---
4.712  -0.000  -1.000  -1.571  4.712   <---
5.498   0.707  -0.707  -0.785  5.498   <---

which is showing that results in 3rd and 4th quadrants

3rd quadrant: dist_x < 0, dist_y < 0
4rd quadrant: dist_x > 0, dist_y < 0

must be added with 2 PI to get all angle between 0 and 2 PI.

Edit
Possible implementation to the given code

..
const angle = Math.atan2(dist_y, dist_x) // angle between arrow & token

/* 
result of atan2():
dist_x > 0, dist_y > 0 ==>    0  < angle <  PI/2  (1st quadrant)
dist_x < 0, dist_y > 0 ==>  PI/2 < angle <  PI    (2nd quadrant)
dist_x < 0, dist_y < 0 ==> -PI   < angle < -PI/2  (3rd quadrant)
dist_x > 0, dist_y < 0 ==> -PI/2 < angle <  0     (4th quadrant)
*/

// Map all angles from (-PI, PI) to (0, 2 PI)
if(dist_y < 0) angle += 2 * Math.PI
about 4 years ago · Juan Pablo Isaza Denunciar

0

Thank you @Aquil Contractor for your answer, I had a play around with the code and this is the solution I came up with:

const dist_x = player.x - token.x
const dist_y = player.y - token.y

let angle = Math.atan2(dist_y, dist_x) // angle between arrow & token

const quarter = Math.PI / 2 // equivalent to 90° (I just thought I'd mention)

/* if the distance between the angles is greater
than 180°, bring the goal angle toward the current. */
if (arrow.angle > quarter && angle < -quarter) angle += Math.PI * 2
else if (arrow.angle < -quarter && angle > quarter) angle -= Math.PI * 2

arrow.angle += arrow.rot_speed
arrow.rot_speed *= .9
arrow.rot_speed += angle - arrow.angle

The solution was a lot simpler than I expected, but it works well and it makes sense.

Thanks all for your help and ideas!

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda