I am developing a platform game, and I would like there to be an arrow pointing to a token:
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.
CodePudding user response:
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
CodePudding user response:
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