Note: the situation you describe (angle, start, end, and time of flight) is overdetermined. For many (most) inputs, there will be no solution that simultaneously satisfies all of these constraints.
(eg. If we take the start, angle, time, and just the horizontal coordinate of the endpoint, that already completely determines the launch speed - with no guarantee that this hits the necessary vertical coordinate of the endpoint!)
To address this I'll remove the time of flight constraint, so we're finding a ballistic trajectory from the start to the end point, with a given firing angle. The launch speed and duration before it hits the target will be left as unknowns to solve for.
I'll assume we're in 2D here. If 3D, you can reduce it to the 2D case by projecting onto the plane containing the start/end points and the gravity vector.
We'll subtract out the start position, so it becomes zero and disappears from our equations, and our target
vector represents the offset from the start to the end of the trajectory, fired with an initial inclination of angle
in radians.
Our initial velocity is then the speed of the projectile times a unit vector in the firing direction:
initialVelocity = speed * Vector2(cos(angle), sin(angle))
With this, the projectile's position at time t
is given by:
positionAt(t) = initialVelocity * t + (gravity/2) * t*t
(where gravity
is a downward-pointing vector, like (0, -9.8)
)
Taking just the horizontal, x
component at the time of impact T
:
target.x = initialVelocity.x * T
target.x = speed * cos(angle) * T
T = target.x/(speed * cos(angle))
Substituting this into the vertical, y
component:
target.y = speed * sin(angle) * T + (gravity.y/2) * T^2
target.y = speed * sin(angle) * target.x / (speed * cos(angle)
+ (gravity.y/2) * (target.x/(speed * cos(angle))^2
target.y = target.x * tan(angle) + (gravity.y/2) * (target.x^2/(speed^2 * cos^2(angle))
target.y - target.x * tan(angle) = (gravity.y*target.x^2/2*cos^2(angle))/(speed^2)
speed^2 = (gravity.y*target.x^2)/(2*cos^2(angle)*(target.y - target.x*tan(angle))
Finally, since a speed is positive by definition (direction coming from the unit vector above):
speed = sqrt((gravity.y*target.x^2)/(2*cos^2(angle)*(target.y - target.x*tan(angle)))
Ta-dah! :D
A few things to note: this becomes undefined...
if angle
is vertical: you can still hit something directly below you with any velocity at all (gravity does all the work) or directly above you if you fire straight up with speed >= sqrt(-g*target.y/2)
If it's to the left or right at all then we can't hit it with this angle.
if target.y >= target.x * tan(angle)
: the target is too high. The parabola kisses the line y = x * tan(angle)
only at the moment it's fired - from then on gravity pulls it downward, so if the target is above that line then we'll never hit it even with infinite speed.
I've written a few previous answers on the subject of planning ballistic trajectories - you might also find those useful for reference: