Estoy desarrollando un juego de plataformas y me gustaría que hubiera una flecha que apuntara a un token:
Simplemente ajustar la flecha al token está bien, todo funciona correctamente:
const dist_x = player.x - token.x const dist_y = player.y - token.y const angle = Math.atan2(dist_y, dist_x) arrow.angle = anglePero el problema es que me gustaría que la flecha girara alrededor de la ficha como se muestra a continuación. Funciona bien, pero cuando el ángulo de la flecha está cerca de 360 y el ángulo de la ficha está cerca de 0, el código piensa que la flecha debe girar completamente hasta cero, en lugar de simplemente sumar un poco y muy bien. dando vueltas. Este es mi código:
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_distEste problema ha sido un gran obstáculo para mí en múltiples ocasiones, por lo que agradecería cualquier ayuda.
Para arreglar algo como esto, debe verificar si la diferencia del ángulo al que se está balanceando es inferior a 180, y si no es así, agregue 360 al ángulo al que se está balanceando. Creo que eso arreglaría la parte donde giraría. No sé cómo implementaría esto en su código, pero esta es la solución general que encontré en experiencias anteriores.
Por supuesto, necesitarías convertir todo esto en radianes: D
No estoy seguro de si esto ayuda. Supongamos que hay valores de dist_x y dist_y usados para recuperar el ángulo usando atan2() de la siguiente manera
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) ) }que produce
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 <---lo que muestra que los resultados en 3er y 4to cuadrantes
3er cuadrante:
dist_x < 0,dist_y < 0
4.er cuadrante:dist_x > 0,dist_y < 0
debe agregarse con 2 PI para obtener todos los ángulos entre 0 y 2 PI.
Editar
Posible implementación al código dado
.. 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.PIGracias @Aquil Contractor por tu respuesta, jugué con el código y esta es la solución que se me ocurrió:
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.angleLa solución fue mucho más simple de lo que esperaba, pero funciona bien y tiene sentido.
¡Gracias a todos por vuestra ayuda e ideas!