I am trying to shoot an arrow at a target with a 100% success rate. Given the initial force applied to the arrow, the gravity, the location of the archer, and the location of the target, how can I do this in Unity?
I have read How can I find a projectile's launch angle?, and it contains the equation I am using:
However, this is only accurate when I am at the maximum distance from the object given its power. (Above the maximum distance means that the arrow cannot reach the target.) The closer I move to the target, the less accurate the arrow shot becomes, as it travels past the target. The angle is increased resulting in the arrow traveling a shorter distance as I'd expect, but it is not increased by enough.
The script spawns an arrow (a simple sphere) and launches it towards a target. It fires once per second, but the closer to the target the archer is, the more inaccurate the arrow is. The case of the archer being too far from the arrow is not handled, but that is not my concern right now.
using UnityEngine;
using System.Collections;
public class Archer : MonoBehaviour
{
public GameObject arrow; //Simple 3D Sphere
public GameObject target; //Simple 3D Cube
public float power = 25.0f;
public Vector3 aim;
private void Start()
{
StartCoroutine(ShootArrows());
}
private IEnumerator ShootArrows()
{
while (true)
{
yield return new WaitForSeconds(1.0f);
Vector3 spawnPosition = new Vector3(transform.position.x, transform.position.y, transform.position.z);
GameObject arrowInstance = Instantiate(arrow, spawnPosition, Quaternion.identity) as GameObject;
arrowInstance.GetComponent<Rigidbody>().AddForce(Aim() * power, ForceMode.VelocityChange);
}
}
private Vector3 Aim()
{
float xAim = target.transform.position.x - transform.position.x;
float yAim = Mathf.Rad2Deg * Mathf.Atan(((Mathf.Pow(power, 2) + Mathf.Sqrt((Mathf.Pow(power, 4) - (-Physics.gravity.y) * (-Physics.gravity.y * Mathf.Pow(HorizontalDistance(), 2) + 2 * VerticalDistance() * Mathf.Pow(power, 2))))) / -Physics.gravity.y * HorizontalDistance()));
float zAim = target.transform.position.z - transform.position.z;
Vector3 aim = new Vector3(xAim, yAim, zAim).normalized;
return aim;
}
private float HorizontalDistance()
{
float xDistance = target.transform.position.x - transform.position.x;
float zDistance = target.transform.position.z - transform.position.z;
float distance = Mathf.Sqrt(Mathf.Pow(xDistance, 2) + Mathf.Pow(zDistance, 2));
return distance;
}
private float VerticalDistance()
{
return Mathf.Abs(target.transform.position.y - transform.position.y);
}
}
My best guess is that I am using the equation correctly, but I am plugging the angle into Unity wrong. Why is my script giving me inaccurate results?
computeRequiredAngles
method may be what you are looking for... \$\endgroup\$