using UnityEngine; using System.Collections; public class TrajectoryCalculation : MonoBehaviour { public Rigidbody projectile; public Transform target; [Header("CalculateBestThrowSpeed")] public float timeToTarget = 1f; [Header("CalculateTrajectory")] public float speed = 10; [Range(0, 1)] public float arc = 0; void Update() { if (Input.GetKeyDown("a")) { GameObject p = Instantiate(projectile, transform.position, transform.rotation) as GameObject; p.GetComponent().AddForce(CalculateBestThrowSpeed(transform.position, target.position, timeToTarget), ForceMode.VelocityChange); Destroy(p, 10); } if (Input.GetKeyDown("b")) { Vector3 velocity; if (CalculateTrajectory(transform.position, target.position, speed, out velocity, arc)) { GameObject p = Instantiate(projectile, transform.position, transform.rotation) as GameObject; p.GetComponent().AddForce(velocity, ForceMode.VelocityChange); Destroy(p, 10); } else { Debug.Log("Target cannot be reached. Increase speed or reduce distance."); } } } // from http://answers.unity3d.com/answers/456066/view.html static Vector3 CalculateBestThrowSpeed(Vector3 origin, Vector3 target, float timeToTarget) { Vector3 toTarget = target - origin; Vector3 toTargetXZ = toTarget; toTargetXZ.y = 0; float y = toTarget.y; float xz = toTargetXZ.magnitude; float v0y = y / timeToTarget + 0.5f * Physics.gravity.magnitude * timeToTarget; float v0xz = xz / timeToTarget; Vector3 result = toTargetXZ.normalized; result *= v0xz; result.y = v0y; return result; } // based on http://gamedev.stackexchange.com/questions/114522/how-can-i-launch-a-gameobject-at-a-target-if-i-am-given-everything-except-for-it/114547 static bool CalculateTrajectory(Vector3 origin, Vector3 target, float speed, out Vector3 velocity, float arc = 0f) { Vector3 toTarget = target - origin; Vector3 toTargetXZ = toTarget; toTargetXZ.y = 0; float y = toTarget.y; float xz = toTargetXZ.magnitude; float gravity = Physics.gravity.magnitude; float b = speed*speed - y * gravity; float discriminant = b * b - gravity * gravity * (xz * xz + y * y); if (discriminant < 0) // out of range, need higher shot speed { velocity = Vector3.zero; return false; } float discRoot = Mathf.Sqrt(discriminant); float minTime = Mathf.Sqrt((b - discRoot) * 2) / Mathf.Abs(gravity); // impact time for the most direct shot that hits float maxTime = Mathf.Sqrt((b + discRoot) * 2) / Mathf.Abs(gravity); // impact time for the highest shot that hits float time = (maxTime - minTime) * arc + minTime; float v0xz = xz / time; float v0y = y / time + time * gravity / 2; velocity = toTargetXZ.normalized; velocity *= v0xz; velocity.y = v0y; return true; } }