In my game I want skeletons to occasionally lob bones at the player. The player can be anywhere in relation to the skeleton (above or below, to the left or right), and I want the skeletons to throw a bone such that it lands on the player (or its parabolic arc intercepts them while rising, if the player is above the skeleton).
Given an arbitrary starting position, an arbitrary target point, and an arbitrary launch angle, how can I calculate the initial velocity of a ballistic projectile (assuming no air resistance) such that its parabolic trajectory intercepts the target point?
I know there are a number of similar questions on this site, but none of them appear to have this particular set of requirements:
Calculating initial velocities given trajectory parabola requires a known/fixed apex height.
Calculating velocity needed to hit target in parabolic arc and Throw object towards predefined place? assume a known/fixed travel time.
I want to have a fixed launch angle, initial position, and final position, and from those determine the initial velocity.
The Wikipedia article Trajectory of a projectile comes close, but I have no idea how to solve that for velocity.
Reference
In computer coordinates, the Y axis is inverted from Cartesian coordinates. The accepted formula operates independently of this, but it's unintuitive to deal with. This means that gravity will be a positive number, while being above the projectile will result in a negative displacement.
This also means that the fixed angle you choose will be the negative of what the habitual version would suggest.
As a final note, I adjusted for the absolute value of Vx by performing this manipulation before calculating Vy:
if sign(x_velocity) != sign(delta_vector.x):
x_velocity = -1 * x_velocity
var y_velocity = x_velocity * tan(angle)
Full pseudocode reference:
static func get_velocity_of_arc_intercept(initial_position, target_position, angle):
var delta_vector = target_position - initial_position
var x_velocity = sqrt((gravity * delta_vector.x * delta_vector.x) / (2 * (delta_vector.y - (tan(angle) * delta_vector.x))))
# Adjust for lost sign.
if sign(x_velocity) != sign(delta_vector.x):
x_velocity = -1 * x_velocity
var y_velocity = x_velocity * tan(angle)
return Vector2(x_velocity, y_velocity)