On this page
Project: Projectile Lab
The problem
Launch a projectile at speed \(v_0\) and angle \(\theta\). Where does it land? How high does it go? This is parametric motion — \(x\) and \(y\) each driven by trig of the launch angle.
The equations
Split the launch velocity into components, then let gravity act on \(y\) (y up, \(g = 9.81\)):
$$
x(t) = v_0\cos\theta \cdot t, \qquad
y(t) = v_0\sin\theta \cdot t - \tfrac{1}{2}gt^2
$$
Setting \(y = 0\) gives flight time \(T = 2v_0\sin\theta / g\), and substituting back gives the famous results:
$$
R = \frac{v_0^2\sin 2\theta}{g} \quad \text{(range)}, \qquad
H = \frac{(v_0\sin\theta)^2}{2g} \quad \text{(max height)}
$$
Since \(\sin 2\theta \le 1\) with equality at \(\theta = 45°\): 45° maximizes range on flat ground. (With air resistance or elevated targets the optimum shifts — a good follow-up experiment.)
Simulate it (Python)
import math
def trajectory(v0, angle_deg, g=9.81, dt=0.05):
r = math.radians(angle_deg)
vx, vy = v0 * math.cos(r), v0 * math.sin(r)
t, points = 0.0, []
while True:
x, y = vx * t, vy * t - 0.5 * g * t * t
if y < 0 and t > 0:
break
points.append((x, max(y, 0.0)))
t += dt
return points
def range_formula(v0, angle_deg, g=9.81):
return v0**2 * math.sin(2 * math.radians(angle_deg)) / g
pts = trajectory(20, 45)
print(f"simulated range: {pts[-1][0]:.2f} m")
print(f"formula range: {range_formula(20, 45):.2f} m") # 40.77 m — they agreeDraw it (JavaScript canvas)
Canvas y grows down, so flip: py = groundY - y * scale.
// Projectile arcs for 30°, 45°, 60° at v0 = 20 m/s
var v0 = 20, g = 9.81, scale = 6, groundY = H - 30;
var colors = { 30: '#38bdf8', 45: '#fbbf24', 60: '#f472b6' };
[30, 45, 60].forEach(function (deg) {
var r = deg * Math.PI / 180;
ctx.strokeStyle = colors[deg];
ctx.lineWidth = 3;
ctx.beginPath();
for (var t = 0; t <= 2 * v0 * Math.sin(r) / g; t += 0.02) {
var x = v0 * Math.cos(r) * t;
var y = v0 * Math.sin(r) * t - 0.5 * g * t * t;
var px = 40 + x * scale, py = groundY - y * scale;
t === 0 ? ctx.moveTo(px, py) : ctx.lineTo(px, py);
}
ctx.stroke();
print(deg + '° range: ' + (v0 * v0 * Math.sin(2 * r) / g).toFixed(2) + ' m');
});Try it
- Verify the 45° rule numerically: compute ranges for 30°, 45°, 60° at the same speed. Why are 30° and 60° equal? (Hint: \(\sin 2\theta = \sin(180° − 2\theta)\).)
- Invert the formula: at \(v_0 = 20\) m/s, what angle hits a target 30 m away on flat ground? (Two answers — why?)
- Animate it: advance one dot along the 45° arc with
loop()and small time steps.
Next: Project: Turret Aiming — atan2 locks onto the mouse.