MechanicsBeginner

Projectile Motion

Explore 2D motion under gravity. Launch projectiles at different angles and velocities to understand parabolic trajectories, range, and time of flight.

What is Projectile Motion?

Projectile motion describes the motion of an object thrown or projected into the air, subject only to the acceleration of gravity. The object is called a projectile, and its path is called its trajectory.

Key Characteristics:

  • Horizontal motion: Constant velocity (no acceleration)
  • Vertical motion: Constant acceleration due to gravity (g = 9.81 m/s²)
  • Independence: Horizontal and vertical motions are independent
  • Trajectory: Forms a parabolic path

Interactive Simulation

Adjust the initial velocity, launch angle, and height. Watch the projectile follow its parabolic path and see velocity vectors change in real-time.

Time Elapsed
0.00 s
Current Height
0.00 m
Horizontal Distance
0.00 m
Current Speed
25.00 m/s

Calculated Values

Time of Flight
3.60 s
Maximum Height
15.93 m
Range
63.71 m
Horizontal Velocity
17.68 m/s
Purple arrow: Initial velocity vector
Red arrow: Current velocity vector
Blue: Horizontal component (constant)
Green: Vertical component (changes with gravity)

Understanding the Physics

Velocity Components

The initial velocity can be broken into horizontal (vx) and vertical (vy) components:

vx = v0 cos(θ) (constant)
vy = v0 sin(θ) - gt (decreases with time)

Position Equations

The position at any time t is given by:

x(t) = vx · t
y(t) = h0 + vy · t - ½gt²

Optimal Angle

For maximum range on level ground (h0 = 0), the optimal launch angle is 45°. At this angle, the horizontal and vertical components are equal, maximizing the distance traveled.

Implementation

projectile.py
import numpy as np
import matplotlib.pyplot as plt

# Projectile Motion Simulation

# ==========================================
# PARAMETERS
# ==========================================

v0 = 25.0        # Initial velocity (m/s)
angle = 45.0     # Launch angle (degrees)
h0 = 0.0         # Initial height (m)
g = 9.81         # Gravitational acceleration (m/s²)

# Convert angle to radians
angle_rad = np.radians(angle)

# Velocity components
vx = v0 * np.cos(angle_rad)  # Horizontal component
vy = v0 * np.sin(angle_rad)  # Vertical component

print(f"Initial velocity: {v0} m/s at {angle}°")
print(f"Horizontal velocity: {vx:.2f} m/s")
print(f"Vertical velocity: {vy:.2f} m/s")

# ==========================================
# KINEMATIC EQUATIONS
# ==========================================

# Position as function of time:
# x(t) = vx * t
# y(t) = h0 + vy * t - 0.5 * g * t²

# Velocity as function of time:
# vx(t) = vx (constant)
# vy(t) = vy - g * t

# ==========================================
# CALCULATE KEY VALUES
# ==========================================

# Time of flight (when y = 0)
# Solve: 0 = h0 + vy*t - 0.5*g*t²
# Using quadratic formula: t = (vy ± sqrt(vy² + 2*g*h0)) / g

discriminant = vy**2 + 2*g*h0
if discriminant >= 0:
    t_flight = (vy + np.sqrt(discriminant)) / g
else:
    t_flight = 0
    print("Warning: Invalid parameters (negative flight time)")

# Maximum height (when vy = 0)
# At apex: vy - g*t = 0, so t = vy/g
t_max_height = vy / g
max_height = h0 + vy * t_max_height - 0.5 * g * t_max_height**2

# Range (horizontal distance)
range_distance = vx * t_flight

print(f"\nTime of flight: {t_flight:.2f} s")
print(f"Maximum height: {max_height:.2f} m")
print(f"Range: {range_distance:.2f} m")

# ==========================================
# SIMULATE TRAJECTORY
# ==========================================

# Create time array
dt = 0.01  # Time step (s)
time_array = np.arange(0, t_flight + dt, dt)

# Calculate position at each time step
x_positions = vx * time_array
y_positions = h0 + vy * time_array - 0.5 * g * time_array**2

# Filter out negative heights (after landing)
valid_indices = y_positions >= 0
x_positions = x_positions[valid_indices]
y_positions = y_positions[valid_indices]
time_array = time_array[valid_indices]

print(f"\nSimulated {len(time_array)} trajectory points")

# ==========================================
# ANALYZE SPECIFIC TIME POINTS
# ==========================================

def analyze_time(t):
    """Analyze projectile state at time t"""
    x = vx * t
    y = h0 + vy * t - 0.5 * g * t**2
    
    vx_t = vx  # Constant
    vy_t = vy - g * t
    
    speed = np.sqrt(vx_t**2 + vy_t**2)
    angle_t = np.degrees(np.arctan2(vy_t, vx_t))
    
    print(f"\n--- Time t = {t:.2f} s ---")
    print(f"Position: ({x:.2f}, {y:.2f}) m")
    print(f"Velocity: ({vx_t:.2f}, {vy_t:.2f}) m/s")
    print(f"Speed: {speed:.2f} m/s")
    print(f"Angle: {angle_t:.1f}°")
    
    return x, y, vx_t, vy_t, speed

# Analyze at launch, apex, and landing
print("\n" + "="*40)
print("TRAJECTORY ANALYSIS")
print("="*40)

analyze_time(0)  # Launch
analyze_time(t_max_height)  # Apex
analyze_time(t_flight)  # Landing

# ==========================================
# ENERGY ANALYSIS
# ==========================================

def calculate_energy(t, mass=1.0):
    """Calculate kinetic and potential energy"""
    y = h0 + vy * t - 0.5 * g * t**2
    vy_t = vy - g * t
    
    KE = 0.5 * mass * (vx**2 + vy_t**2)
    PE = mass * g * y
    total_E = KE + PE
    
    return KE, PE, total_E

print("\n" + "="*40)
print("ENERGY CONSERVATION (m = 1 kg)")
print("="*40)

for t in [0, t_max_height, t_flight]:
    KE, PE, E_total = calculate_energy(t)
    print(f"\nt = {t:.2f} s:")
    print(f"  KE = {KE:.2f} J")
    print(f"  PE = {PE:.2f} J")
    print(f"  Total = {E_total:.2f} J")

# ==========================================
# VISUALIZATION
# ==========================================

plt.figure(figsize=(12, 8))

# Subplot 1: Trajectory
plt.subplot(2, 2, 1)
plt.plot(x_positions, y_positions, 'b-', linewidth=2, label='Trajectory')
plt.plot([x_positions[0]], [y_positions[0]], 'go', markersize=10, label='Launch')
plt.plot([x_positions[-1]], [y_positions[-1]], 'ro', markersize=10, label='Landing')
plt.xlabel('Distance (m)')
plt.ylabel('Height (m)')
plt.title('Projectile Trajectory')
plt.grid(True, alpha=0.3)
plt.legend()
plt.axis('equal')

# Subplot 2: Height vs Time
plt.subplot(2, 2, 2)
plt.plot(time_array, y_positions, 'g-', linewidth=2)
plt.axhline(y=max_height, color='r', linestyle='--', alpha=0.5, label=f'Max: {max_height:.1f} m')
plt.xlabel('Time (s)')
plt.ylabel('Height (m)')
plt.title('Height vs Time')
plt.grid(True, alpha=0.3)
plt.legend()

# Subplot 3: Velocity Components
plt.subplot(2, 2, 3)
vx_array = np.full_like(time_array, vx)
vy_array = vy - g * time_array
plt.plot(time_array, vx_array, 'b-', linewidth=2, label='vx (horizontal)')
plt.plot(time_array, vy_array, 'r-', linewidth=2, label='vy (vertical)')
plt.axhline(y=0, color='k', linestyle='-', alpha=0.3)
plt.xlabel('Time (s)')
plt.ylabel('Velocity (m/s)')
plt.title('Velocity Components')
plt.grid(True, alpha=0.3)
plt.legend()

# Subplot 4: Energy
plt.subplot(2, 2, 4)
KE_array = 0.5 * (vx**2 + (vy - g * time_array)**2)
PE_array = g * y_positions
E_total_array = KE_array + PE_array

plt.plot(time_array, KE_array, 'b-', linewidth=2, label='Kinetic Energy')
plt.plot(time_array, PE_array, 'r-', linewidth=2, label='Potential Energy')
plt.plot(time_array, E_total_array, 'k--', linewidth=2, label='Total Energy')
plt.xlabel('Time (s)')
plt.ylabel('Energy (J/kg)')
plt.title('Energy vs Time')
plt.grid(True, alpha=0.3)
plt.legend()

plt.tight_layout()
plt.show()

# ==========================================
# OPTIMAL ANGLE FOR MAX RANGE
# ==========================================

print("\n" + "="*40)
print("OPTIMAL LAUNCH ANGLE")
print("="*40)

angles = np.linspace(0, 90, 91)
ranges = []

for ang in angles:
    ang_rad = np.radians(ang)
    vx_temp = v0 * np.cos(ang_rad)
    vy_temp = v0 * np.sin(ang_rad)
    
    disc = vy_temp**2 + 2*g*h0
    if disc >= 0:
        t_temp = (vy_temp + np.sqrt(disc)) / g
        r_temp = vx_temp * t_temp
        ranges.append(r_temp)
    else:
        ranges.append(0)

max_range_idx = np.argmax(ranges)
optimal_angle = angles[max_range_idx]
max_range = ranges[max_range_idx]

print(f"For v0 = {v0} m/s and h0 = {h0} m:")
print(f"Optimal angle: {optimal_angle:.1f}°")
print(f"Maximum range: {max_range:.2f} m")
print(f"\nNote: For h0 = 0, optimal angle is 45°")

Real-World Applications

🏀 Sports

Basketball shots, football passes, golf swings - all follow projectile motion

💧 Water Fountains

Water jets form parabolic arcs based on nozzle angle and pressure

🚀 Ballistics

Artillery shells and rockets follow projectile paths (ignoring air resistance)

🎮 Game Physics

Video games simulate projectile motion for realistic object throwing

Related Topics

Newton's LawsComing Soon

Understand forces and motion principles

Energy ConservationComing Soon

Track kinetic and potential energy transformations

Air ResistanceComing Soon

See how drag affects trajectory

CollisionsComing Soon

Analyze momentum and energy in collisions

Discussion