Projectile motion for negative height and angle

211 Views Asked by At

I'm trying to implement a turret in a game that compensate for bullet drop, I'm using the equations 1) and 2) from the next image to obtain the angle of the turret and time of flight.

But it doesn't work when the target have a higher altitude (assuming h is the difference in height) like in 3), and the angle is always positive, but I want the turret to aim downwards when it have a higher ground like in 4)

https://i.stack.imgur.com/Jkngw.png

g = gravitational acceleration in m/s^2
v0 = muzzle velocity in m/s
h = difference in height between muzzle and target in meters (will be negative if the target have a higher altitude)
d = projected distance between muzzle and target over the XZ plane in meters
[unknown] angle = angle of the turret in degrees (between -45º and 45º from the horizon)
[unknown] time = estimated time of impact in seconds

function ProjectileMotion(g, v0, h, d)
    denom = sqrt(h * h + d * d)
    coef = ((g * d * d) / (v0 * v0) - h) / denom
    phase = atan(d / h)
    angle = (pi - (acos(coef) + phase)) / 2
    v0_y = v0 * sin(angle)
    time = (v0_y + sqrt(v0_y * v0_y + 2 * g * h)) / g
    return to_deg(angle), time
end

The question is: How can I get the angle (between -45º and 45º) and the time of flight, given:
g = 9.8 m/s^2,
v0 = 50 m/s,
delta_h = turret_height - target_height,
d = horizontal distance
?

EDIT: Finally found a solution.

I used the formula in this video that only works for angles between 45º and 90º, I subtracted 90º to that angle to get a value between 0º and 45º, then for the phase angle the height need to be positive. I used this formula to get the horizontal travel at 0º, if the distance to the target is lower than that, the angle should be negative with the same value that a launch with negative height and gravity. And to calculate the time of flight:
v0 cos(α) t = d
t = d / v0 cos(α)

function MinTravel(g, v0, h)
    return v0 * math.sqrt(math.abs(2 * h / g))
end

function ProjectileMotionAux(g, v0, d, h)
    local phase = math.atan2(d, math.abs(h))
    local denom = math.sqrt(h * h + d * d)
    local coef = (g * d * d) / (v0 * v0) - h
    local angle = (math.pi / 2) - (math.acos(coef / denom) + phase) / 2
    local time = d / (v0 * math.cos(angle))
    return math.deg(angle), time
end

function ProjectileMotion(g, v0, d, h)
    if h > 0 and d < MinTravel(g, v0, h) then
        local angle, time = ProjectileMotionAux(-g, v0, d, -h)
        return -angle, time
    end
    return ProjectileMotionAux(g, v0, d, h)
end