On this page
The projectile formulas in your textbook assume no air. That is fine for exam problems, but it hides how motion actually builds up moment by moment. Writing a small simulation fixes that. You will tell the computer Newton's second law and let it step forward in time. This post gives you a working program in under 30 lines, a way to check it, and a few changes that teach you more physics than the formula alone.
Why simulate something you can already solve?
Because the formula only works for the simple case. Physics educators Ruth Chabay and Bruce Sherwood (2008) argued in the American Journal of Physics that programming in an introductory course lets students explore models in ways the analytical tools of a first-year student cannot. Add air resistance to a projectile and there is no neat formula, but the program barely changes.
The idea is simple. Over a very short time dt, acceleration hardly changes. So:
new velocity = old velocity + acceleration × dt
new position = old position + new velocity × dt
Repeat thousands of times and you have the trajectory.
The program
You need Python 3 and nothing else. Save this as projectile.py and run it from a terminal with the command python3 projectile.py.
import math
g = 9.8 # gravity, m/s^2
v0 = 20.0 # launch speed, m/s
angle = 45.0 # launch angle, degrees
dt = 0.001 # time step, s
k = 0.0 # drag per unit mass, 1/m (0 = no air)
theta = math.radians(angle)
x, y = 0.0, 0.0
vx = v0 * math.cos(theta)
vy = v0 * math.sin(theta)
t, ymax = 0.0, 0.0
while y >= 0:
v = math.hypot(vx, vy) # current speed
ax = -k * v * vx # drag opposes motion
ay = -g - k * v * vy
vx = vx + ax * dt # update velocity...
vy = vy + ay * dt
x = x + vx * dt # ...then position
y = y + vy * dt
t = t + dt
ymax = max(ymax, y)
print(f"Range {x:.2f} m, flight time {t:.2f} s, max height {ymax:.2f} m")
R = v0 * v0 * math.sin(2 * theta) / g
print(f"Formula range {R:.2f} m")How it works: the first block sets the inputs. The next block converts the angle to radians and splits the launch velocity into components. The while loop runs until the ball falls below the ground. Inside it, the code works out the acceleration, updates velocity, then updates position.
Does the program give the right answer?
Always check a simulation against a case you can solve by hand. With k = 0 there is no air, so the textbook results apply. For v0 = 20 m/s, θ = 45° and g = 9.8 m/s²:
Range R = v0² sin 2θ / g = 400 × 1 / 9.8 = 40.82 m
Time of flight T = 2 v0 sin θ / g = 2 × 20 × 0.7071 / 9.8 = 2.89 s
Maximum height H = v0² sin²θ / (2g) = 400 × 0.5 / 19.6 = 10.20 m
The program prints a range of 40.81 m, a flight time of 2.89 s and a maximum height of 10.20 m. The tiny gap in range comes from the finite time step.
What happens with air drag?
Set k = 0.01. The drag term gives an acceleration of k v² opposite to the velocity, which at 20 m/s is 0.01 × 400 = 4 m/s², about 40% of g, so this is fairly strong drag. Now the program prints a range of 31.34 m, a flight time of 2.67 s and a maximum height of 8.78 m. Drag cut the range by about a quarter.
Now change the angle and rerun. With this drag, 35° gives 30.32 m, 40° gives 31.25 m, 43° gives 31.41 m and 45° gives 31.34 m. The angle that gives the longest range is no longer 45°; it is a little lower. The textbook rule "45° gives maximum range" is true only without air.
Common mistakes and how to spot them
Degrees instead of radians. Python's math functions work in radians, and math.radians converts. If you delete that conversion, the program treats 45 as 45 radians and prints a range of 36.49 m. The formula line agrees, because it uses the same wrong angle. That is why you should also print vx at launch: it should be 14.14 m/s.
Getting the force direction wrong. In a Georgia Tech mechanics course where 1,357 students learned to model motion in code, Caballero, Kohlmyer and Schatz (2012) found that a small set of errors explained most failed programs, and reversing the direction of the force was the most common. Here, drag must have a minus sign, and gravity must reduce vy.
A time step that is too big. With dt = 0.1 s the range comes out as 39.60 m instead of 40.81 m. Halve dt until the answer stops changing much.
Not knowing what the loop order does. This program updates velocity first, then position. If you swap the order, the no-drag range becomes 40.84 m instead of 40.81 m. Both are close here, but try it, so you know your answer depends on the method as well as the physics.
A practice routine with your program
Day 1: Run it with k = 0. Change v0 to 10 and 30 m/s and check each range against the formula.
Day 2: Find the angle that gives maximum range with k = 0.01 by trying angles one degree apart.
Day 3: Launch from a cliff by starting at y = 20. Compare the range with your hand calculation using the quadratic for time.
Day 4: Replace drag with a constant wind by adding a fixed value to ax. Predict the effect before you run it.
If you want to see these ideas without writing code first, the Fermi Simulation Lab has interactive simulations for ideas that are easier to see than read. Use it to build a picture, then write your own program to test it. Our post on simulations versus static diagrams covers why that combination helps.
Copy the program, run it once with k = 0, and confirm you get 40.81 m before changing anything.



