Estou tentando lançar um objeto em um alvo, dada a sua posição, a sua posição alvo, a velocidade de lançamento e a gravidade. Eu estou seguindo esta fórmula da Wikipedia :
Simplifiquei o código da melhor maneira possível, mas ainda não consigo atingir o alvo de forma consistente. Estou apenas considerando a trajetória mais alta, das duas disponíveis na opção + - na fórmula.
Alguém sabe o que estou fazendo de errado?
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;
}
}
Respostas:
Sou um pouco cético em usar
atan
aqui, porque a razão tangente dispara até o infinito em certos ângulos e pode levar a erros numéricos (mesmo fora do caso indefinido / dividido por zero para disparar para cima / para baixo).Usando as fórmulas elaboradas nesta resposta , podemos parametrizar isso em termos do tempo (inicialmente desconhecido) para impactar
T
, usando a inicialspeed
do projétil:Você pode escolher T_min ou T_max (ou algo intermediário, se desejar disparar com velocidades de até, mas não necessariamente iguais a, no máximo)
(
T_min
é a trajetória rasa em vermelho na parte inferior eT_max
é a alta em verde. Qualquer trajetória entre eles é viável a uma velocidade possível. Quando os dois se fundem na trajetória em amarelo, o objeto está fora de alcance.)Agora que calculamos um valor para
T
, o resto é direto:Você pode usar essa velocidade diretamente (ela tem um comprimento igual à
speed
construção) ou, se você realmente precisa conhecer o ângulo, pode usaratan2(vy, vx)
Editar: para tornar isso aplicável a mais casos, aqui está uma versão 3D:
fonte
discRoot
é a raiz quadrada do discriminante , que é a parte que aparece sob o sinal de raiz quadrada na fórmula quadrática .b
é -1 vezes a variável b na fórmula quadrática. Infelizmente, não conheço um nome mais descritivo para ele. (Eu o multipliquei por -1 ao atribuir a ordem de aperfeiçoar as etapas posteriores, pois o sinal de menos inicial já está inserido e não afeta o quadrado). Veja a outra resposta para obter uma derivação completa, embora alguns quadrados estejam faltando (serão corrigidos em breve).Graças ao DMGregory, agora tenho um script de extensão C # que pode ser usado para isso. A versão mais recente pode ser encontrada no GitHub .
fonte
Pessoalmente, eu nem me incomodaria em usar qualquer tipo de fórmula complicada.
Apenas atira na direção do alvo. E se você deseja compensar a gravidade, a distância etc., defina
someSortOfMultiplier()
como uma função que retorne um flutuador que compensará quando multiplicado pelo código acima.fonte