Example Lab Report

Technical Design Document: Simulation of Projectile Motion


In many games, there will be objects moving under free flight. If a game is to be perceived as realistic, these various projectiles must have movements that are realistic. When an object is launched with some velocity and allowed to fly freely, that is there's no thrust from a motor or wings or the like, its said to be in “ballistic” flight. Most objects in ballistic flight, experience only an acceleration due to gravity. This means that even in a 3D environment, the simulation of motion can be treated as a 2D problem by separating the motion into a vertical and horizontal component. If an object's size is large compared to its mass, or if the speed of the object is high, then wind resistance can be an important factor. Although including the effects of wind resistance does add complexity to a simulation, its inclusion can bring a much higher level of realism to a game or simulation.


In this simulation, all quantities are measured in standard SI metric units so that positions are measured in meters, velocities in meters per second, accelerations in meters per second squared and time in seconds. All physical parameters are treated at single-precision floating point variables.

The simulation of projectile motion can be treated as two separate 1D problems, one in the horizontal and one in the vertical direction. The initial position for the projectile is taken to be the origin (x=0, y=0), and the magnitude and direction for the initial velocity, $v_i$ is supplied by the user with the direction being the angle above the horizontal, $\theta$, measured in degrees. The user is also asked to supply a coefficient wind resistance, which is taken to be the same for both directions.

After acquiring the initial data from the user, the angle for the initial velocity must be converted to radians so that it may be passed to the single-precision cosine and sine functions in the <cmath> library, cosf() and sinf(), when determining the initial horizontal and vertical velocities,

\begin{align} \theta_{rad} = \theta_{deg} * \left( \frac {\pi} {180} \right) \end{align}
\begin{align} v_x = v_i \cdot \cos \left( \theta \right) \end{align}


\begin{align} v_y = v_i \cdot \sin \left( \theta \right). \end{align}

Neglecting wind resistance, the only acceleration considered for the projectile is the vertical acceleration due to gravity taken as 9.8 m/s2 in the downward direction. The acceleration due to the effects of wind resistance is modeled by the following:

\begin{equation} a_{wind} = - c v \end{equation}

where $c$ is the “coefficient of wind resistance” measured in units of $1/s$ and $v$ is the velocity measured in $m/s$. Since we consider the acceleration as result of wind resistance to be linear with velocity, the above equation can be treated strictly as a scalar equation.

Motion from one timestep to the next is integrated using the Forward Euler Method in which we update position using the previous value of the velocity and then update the velocity using the previous value of the acceleration. While this algorithm is not as precise as others, it is simpler to code and executes much faster. The primary artifact of the Forward Euler Method is that projectiles will tend to fly farther than they should, but if the timestep is kept small, this error can be kept to a minimum. With that in mind, the timestep, $dt$, used for the simulation is 0.04 s which corresponds to a frame rate of 25 fps. Including the effects of wind resistance, the velocities in the horizontal and vertical directions are modeled in the following way:

\begin{equation} x_{new} = x_{old} + v_{x~old} dt \end{equation}


\begin{equation} y_{new} = y_{old} + v_{y~old} dt \end{equation}

Once the new position are known, we calculate the new velocities,

\begin{equation} v_{x~new} = v_{x~old} - a_{x~old} dt \end{equation}


\begin{equation} v_{y~new} = v_{y~old} - a_{y~old} dt. \end{equation}

Lastly, we update the acceleration,

\begin{align} a_{x~new} = - c \cdot v_{x~new} \end{align}


\begin{align} a_{y~new} = -9.8 - c \cdot v_{y~new} \end{align}

Every timestep, the elapsed time and the position of the particle are displayed via a console window. The simulation terminates when the vertical position of the projectile is less than zero, indicating that the projectile has reached the ground. At the end of the simulation, the total elapsed time and the total horizontal distance are displayed.



Postmortem: Simulation of Projectile Motion


Examining a couple of test situations will reveal the validity of the methodology described above. If there is no wind resistance, then the total range for a projectile launched over flat terrain is given by

\begin{align} \Delta x = \frac {v^2} {g} \sin \left( 2 \theta \right) \end{align}

This means that the maximum range for a given initial speed happens when the initial angle is 45 degrees, and that initial angles of 30 degrees and 60 degrees should yield the same range. Below is a table showing the range for a projectile launched at 20 m/s for a variety of angles.

Speed (m/s) Angle (degrees) Simulated Range (m) Analytical Range (m)
20 15 21.6 20.4
20 30 36.7 35.3
20 45 41.9 40.8
20 60 36.0 35.3
20 75 20.7 20.4

To evaluate the validity of simulations treatment of wind resistance, the maximum range should happen at an angle slightly less than 45 degrees, and at each angle the total range should be less than the corresponding range without wind resistance. The table below shows the results of the simulation using an initial velocity of 20 m/s as before, but with a coefficient of wind resistance of 0.2 1/s.

Speed (m/s) Angle (degrees) Simulated Range (m)
20 30 27.0
20 37.5 28.9
20 45 28.2
20 52.5 26.8
20 60 23.3


This numeric model for projectile motion functions quite well. Although there were deviations from the analytical solution, the errors were small, and in a game environment these small errors would not be a significant hindrance. If higher precision were needed, a smaller time-step could be used, but this comes at the cost of performance and could negatively impact the game's frame rate. The wind resistance model performed very well. There was no analytically derived data for comparison, but performance of the model matched the qualitative expectations and is sufficient for most game environments.

For more demanding applications, in which precision is of greater importance, it is advisable to utilize an integration method other than Forward Euler. While it sufficed for this current project, in an artillery-themed game, the inaccuracies inherent in the Forward Euler Method can lead to friendly-fire incidents. In these situations or for actual physical simulations, it is recommended that the motion be integrated using a higher-order method such as Velocity Verlet.


/    ProjectileMotion.cpp simulates the motion of a projectile fired
/    at a user-supplied angle and velocity over flat terrain.  The user
/    will also supply a value for the horizontal wind velocity and a
/    coefficient for wind resistance.  The particle's position is
/    displayed via the console after every timestep until the projectile
/    reaches the ground once again.
/    J. Douglas Patterson, 
/    Johnson County Community College
/    v1.0  Jan 2009
#include <cmath>
#include <iostream>
using namespace std;
void main() {
    float t=0.0f;        // elapsed time for the simulation (s)
    float dt=0.04f;        // timestep corresponding to 25 fps (s)
    float x=0.0f;        // horizontal position (m)
    float y=0.0f;        // vertical position (m)
    float g=9.8f;        // acceleration due to gravity (m/s^2)
    float cwind=0.0f;    // coefficient of wind resistance (1/s)
    float vx=0.0f;        // horizontal velocity (m/s)
    float vy=0.0f;        // vertical velocity (m/s)
    float ax=0.0f;        // horizontal acceleration (m/s^2)
    float ay=0.0f;        // vertical acceleration (m/s^2)
    float vi=0.0f;        // initial speed (m/s)
    float theta=0.0f;    // initial elevation (degrees)
    cout<<"Enter the initial speed and angle in degrees: ";
    theta = theta * 0.0174533f;        //convert elevation to radians
    cout<<"Enter the coefficient of wind resistance: ";
    /* Determine velocity vector components */
    vx = vi * cosf(theta);            
    vy = vi * sinf(theta);
    /* Determine acceleration vector components */
    ax = -cwind * vx;            
    ay = (-cwind * vy) - g;
    /* Simulation loop.  Continue until projectile reaches the ground */
    while (y >= 0) {
        /* update the position */
        x += vx * dt;
        y += vy * dt;
        t += dt;
        /* update the velocity */
        vx += ax * dt;
        vy += ay * dt;
        /* update the acceleration */
        ax = -cwind * vx;
        ay = (-cwind * vy) - g;
        cout<<"Time: "<<t<<" s, Position ("<<x<<", "<<y<<") m\n";
    cout<<"The projectile lands "<<x<<" m down range.\n";
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License