Estoy tratando de lanzar un objeto a un objetivo, dada su posición, su posición de destino, la velocidad de lanzamiento y la gravedad. Estoy siguiendo esta fórmula de Wikipedia :
Simplifiqué el código lo mejor que pude, pero todavía no puedo alcanzar el objetivo. Solo estoy considerando la trayectoria más alta, de los dos disponibles de la opción + - en la fórmula.
¿Alguien sabe lo que estoy haciendo mal?
using UnityEngine;
public class Launcher : MonoBehaviour
{
public float speed = 10.0f;
void Start()
{
Launch(GameObject.Find("Target").transform);
}
public void Launch(Transform target)
{
float angle = GetAngle(transform.position, target.position, speed, -Physics2D.gravity.y);
var forceToAdd = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * speed;
GetComponent<Rigidbody2D>().AddForce(forceToAdd, ForceMode2D.Impulse);
}
private float GetAngle(Vector2 origin, Vector2 destination, float speed, float gravity)
{
float angle = 0.0f;
//Labeling variables to match formula
float x = Mathf.Abs(destination.x - origin.x);
float y = Mathf.Abs(destination.y - origin.y);
float v = speed;
float g = gravity;
//Formula seen above
float valueToBeSquareRooted = Mathf.Pow(v, 4) - g * (g * Mathf.Pow(x, 2) + 2 * y * Mathf.Pow(v, 2));
if (valueToBeSquareRooted >= 0)
{
angle = Mathf.Atan((Mathf.Pow(v, 2) + Mathf.Sqrt(valueToBeSquareRooted)) / g * x);
}
else
{
//Destination is out of range
}
return angle;
}
}
Respuestas:
Soy un poco escéptico de usar
atan
aquí, porque la relación tangente se dispara al infinito en ciertos ángulos, y puede conducir a errores numéricos (incluso fuera del caso indefinido / dividir por cero para disparar hacia arriba / abajo).Usando las fórmulas elaboradas en esta respuesta , podemos parametrizar esto en términos del tiempo (inicialmente desconocido) para impactar
T
, usando la inicialspeed
del proyectil:Puedes elegir T_min o T_max (o algo intermedio si quieres disparar con velocidades de hasta un máximo, pero no necesariamente iguales )
(
T_min
es la trayectoria roja poco profunda en la parte inferior, yT_max
es la verde alta. Cualquier trayectoria entre ellos es viable a una velocidad factible. Cuando los dos se funden en la trayectoria amarilla, el objeto está fuera de alcance).Ahora que hemos calculado un valor para
T
, el resto es sencillo:Puede usar esta velocidad directamente (tiene una longitud igual a
speed
por construcción), o si realmente necesita conocer el ángulo, puede usaratan2(vy, vx)
Editar: para que esto sea aplicable a más casos, aquí hay una versión 3D:
fuente
discRoot
es la raíz cuadrada del discriminante , que es la parte que aparece debajo del signo de raíz cuadrada en la fórmula cuadrática .b
es -1 veces la variable b en la fórmula cuadrática. Lamentablemente no sé un nombre más descriptivo para ello. (Lo multipliqué por -1 cuando asigné a Neaten los pasos posteriores, ya que el menos inicial ya está integrado y no afecta la cuadratura). Vea la otra respuesta para obtener una derivación completa, aunque faltan un par de cuadrados (se solucionará en breve)Gracias a DMGregory, ahora tengo un script de extensión C # que se puede usar para esto. La versión más reciente se puede encontrar en GitHub .
fuente
Personalmente, ni siquiera me molestaría en usar ningún tipo de fórmula complicada.
Simplemente lo dispara en la dirección del objetivo. Y si desea compensar la gravedad, la distancia, etc., configure
someSortOfMultiplier()
una función que devuelva un flotador que compensará cuando se multiplique con el código anterior.fuente