University of Wales Trinity Saint David
ACCB5017 - Games Architecture and Mechanics

Linear Momentum

Overview

This worksheet extends the Momentum worksheet from straight lines to the plane, and from describing collisions to calculating them the way a game physics engine does. It introduces the centre of mass of a system, the coefficient of restitution that controls how bouncy a collision is, and a single impulse formula that resolves any two-body collision in one step.

It ends with a C++ console program that resolves collisions between pairs of bodies and checks that momentum comes out the same as it went in.

Learning Objectives

By the end of this lab you will be able to:

Concept

In the Momentum worksheet, impulse was force multiplied by contact time. Real contact forces are not constant. They rise from zero, peak, and fall back as two objects squash together and spring apart. The impulse is the area under the force-time graph, whatever its shape. A physics engine usually does not know the shape at all. It skips straight to the total impulse needed to stop the objects moving into each other, and applies it in a single step.

For a group of objects there is a single point that moves as if all the mass were concentrated there and all the external forces acted on it. This is the centre of mass. Internal forces, such as the forces during a collision between members of the group, cannot change its velocity. That is conservation of momentum seen from a different angle.

Real collisions sit somewhere between perfectly bouncy and perfectly sticky. The coefficient of restitution, ee, measures where. It compares how fast two objects separate after a collision with how fast they approached. In two dimensions, a frictionless collision only affects the part of each velocity along the line through the point of contact, the contact normal. The part sliding along the surface carries on unchanged. Put those ideas together and you get one formula for the impulse that resolves any collision between two bodies.

Tasks

Task 1 - Impulse from a force-time graph

Hook

A baseball bat is in contact with the ball for about one thousandth of a second. During that time the force rises from nothing to a peak and falls away again. With a force that changes so quickly, how can you work out what it does to the ball?

Intuition

Split the contact time into many tiny slices. In each slice the force is nearly constant, so the impulse in that slice is force times a tiny time, a thin rectangle of area. Adding all the slices gives the total area under the curve. Whatever the shape, the area is the impulse, and the impulse is the change in momentum.

Reshape the force curve below. A tall narrow pulse and a low wide pulse can have exactly the same area and give the ball exactly the same change in velocity.

Formalise

The integral sign means "add up the area under". The average force is the impulse spread evenly over the contact time.

J=∫F dt=ΔpFavg=JΔtJ = \int F\,dt = \Delta p \qquad F_{avg} = \frac{J}{\Delta t}

Worked example

A 0.145 kg baseball arrives at 40 m/s and leaves at 45 m/s in the opposite direction. Contact lasts 1 ms.

  1. Change in momentum. Taking the outgoing direction as positive, Δp=0.145×45−0.145×(−40)=0.145×85=12.3 N s\Delta p = 0.145 \times 45 - 0.145 \times (-40) = 0.145 \times 85 = 12.3\text{ N s}.
  2. Average force. Favg=12.3/0.001=12 300 NF_{avg} = 12.3 / 0.001 = 12\,300\text{ N}.
  3. Peak force for a triangular pulse. A triangle's area is half its base times its height, so the same area needs a peak of twice the average, about 24 600 N.

Your turn

A triangular force pulse peaks at 2000 N and lasts 0.01 s. Its impulse is N s.

A force rises steadily from 0 to 500 N over 2 ms, stays at 500 N for 6 ms, then falls to 0 over 2 ms. The impulse is N s.

That impulse acts on a 0.5 kg ball at rest. Its final speed is m/s.

Two force-time graphs have the same area. One is tall and narrow, the other low and wide. Which statement is true?

Change in momentum equals the area, so equal areas give equal changes in momentum.

Why do engines rarely calculate the force during a collision?

Contacts last far less than one frame, so the engine applies the total impulse instantly instead of simulating the changing force.

Task 2 - Centre of mass

Hook

A firework rocket explodes at the top of its flight, sending fragments in every direction. Is there anything about the fragments as a group that still follows the rocket's original curved path?

Intuition

The centre of mass is the mass-weighted average position of a system. For two equal masses it is halfway between them. If one is heavier, it is closer to the heavier one. Its velocity is the total momentum divided by the total mass. Because internal forces cannot change total momentum, they cannot change the centre of mass's velocity either. The fragments of the firework fly apart, but their centre of mass carries on along the parabola the rocket was following, until the first fragment hits the ground.

Formalise

xcm=∑mixi∑miv⃗cm=∑miv⃗iM=p⃗totalMx_{cm} = \frac{\sum m_i x_i}{\sum m_i} \qquad \vec{v}_{cm} = \frac{\sum m_i \vec{v}_i}{M} = \frac{\vec{p}_{total}}{M}

Worked example

  1. Two masses. 2 kg at x=0x = 0 and 3 kg at x=5 mx = 5\text{ m}. xcm=(0+15)/5=3 mx_{cm} = (0 + 15) / 5 = 3\text{ m}, closer to the heavier mass.
  2. Skaters pushing apart. 40 kg and 80 kg skaters start at rest. Total momentum is zero, so vcm=0v_{cm} = 0. After pushing apart they move in opposite directions, but the point between them, two thirds of the way toward the heavier skater, stays exactly where it was.

Your turn

A 4 kg mass sits at x = 1 m and a 1 kg mass at x = 6 m. The centre of mass is at x = m.

Three particles: 1 kg at (0, 0), 2 kg at (3, 0) and 1 kg at (0, 4). The centre of mass is at (, ).

A 2 kg ball moves at 6 m/s toward a 4 kg ball at rest. The centre of mass moves at m/s, before and after they collide.

A firework explodes in mid-air. Ignoring air resistance, what path does the centre of mass of the fragments follow?

The explosion forces are internal. Only gravity acts from outside, so the centre of mass keeps following the same projectile path.

In a game, two objects inside a closed system collide. Which statement is always true if the engine conserves momentum?

Conserved total momentum means a constant centre of mass velocity.

Task 3 - Elastic collisions in one dimension

Hook

In a Newton's cradle, one steel ball swings in, stops dead, and the ball at the far end swings out at the same speed. Why does the incoming ball stop, rather than bouncing back or carrying on?

Intuition

An elastic collision conserves both momentum and kinetic energy. Writing out both conservation laws for two objects gives two equations in the two unknown final velocities. Solving them leads to a useful fact. In an elastic collision the relative velocity reverses. The speed at which the objects approach equals the speed at which they separate. Combining that with conservation of momentum gives the final velocities directly.

Formalise

From u1−u2=−(v1−v2)u_1 - u_2 = -(v_1 - v_2) and m1u1+m2u2=m1v1+m2v2m_1u_1 + m_2u_2 = m_1v_1 + m_2v_2.

v1=(m1−m2)u1+2m2u2m1+m2v2=(m2−m1)u2+2m1u1m1+m2v_1 = \frac{(m_1 - m_2)u_1 + 2m_2u_2}{m_1 + m_2} \qquad v_2 = \frac{(m_2 - m_1)u_2 + 2m_1u_1}{m_1 + m_2}
Special caseResult
Equal massesThey swap velocities. A moving ball hitting an identical still ball stops dead, and the still one moves off at the original speed.
Light object hits a very heavy still objectThe light object bounces back at almost its original speed. The heavy object barely moves.
Heavy object hits a very light still objectThe heavy object carries on almost unchanged. The light object shoots off at nearly twice the heavy object's speed.

Worked example

A 1 kg cart at 6 m/s hits a stationary 2 kg cart elastically.

  1. First cart. v1=(1−2)×6+03=−2 m/sv_1 = \dfrac{(1 - 2) \times 6 + 0}{3} = -2\text{ m/s}. It bounces back.
  2. Second cart. v2=0+2×1×63=4 m/sv_2 = \dfrac{0 + 2 \times 1 \times 6}{3} = 4\text{ m/s}.
  3. Check momentum. Before 6, after −2+8=6-2 + 8 = 6. Check kinetic energy. Before 18 J, after 2+16=18 J2 + 16 = 18\text{ J}.

Your turn

A 3 kg ball at 2 m/s collides elastically head-on with a 1 kg ball moving at -2 m/s. Afterward the 3 kg ball moves at m/s and the 1 kg ball at m/s.

A 2 kg puck at 5 m/s hits an identical stationary puck elastically. The first puck ends at m/s and the second at m/s.

In Newton's cradle, why does the incoming ball stop?

Identical balls and a nearly elastic collision mean the moving ball hands all its velocity to the next one.

A ping-pong ball bounces off a stationary bowling ball elastically. What happens?

A light object hitting a very heavy one reverses at nearly the same speed.

What is true of the relative velocity in a perfectly elastic collision?

The separation speed equals the approach speed. That is the defining property of an elastic collision, e = 1.

Task 4 - Coefficient of restitution

Hook

Drop a tennis ball and a lump of clay from the same height. The tennis ball bounces back up to about half its height. The clay does not bounce at all. How can a game describe both with one number?

Intuition

The coefficient of restitution ee is the ratio of separation speed to approach speed. For a perfectly elastic collision e=1e = 1. For a perfectly inelastic, sticky collision e=0e = 0. Real materials sit in between. For a ball bouncing on a fixed floor, the ball leaves at ee times the speed it arrived at. Since height depends on speed squared, each bounce reaches e2e^2 of the previous height.

Change ee below and drop the ball.

Formalise

With uu for velocities before and vv for after, and for a ball on a fixed floor.

e=−v2−v1u2−u1vup=e vdownhn+1hn=e2e = -\frac{v_2 - v_1}{u_2 - u_1} \qquad v_{\text{up}} = e\,v_{\text{down}} \qquad \frac{h_{n+1}}{h_n} = e^2

Worked example

A ball dropped from 2 m bounces to 1.28 m.

  1. Height ratio. 1.28/2=0.64=e21.28 / 2 = 0.64 = e^2.
  2. Coefficient. e=0.64=0.8e = \sqrt{0.64} = 0.8.
  3. Next bounce. 1.28×0.64=0.82 m1.28 \times 0.64 = 0.82\text{ m}.

In a game engine, ee is usually a property set on each material, often called bounciness or restitution. When two materials meet, the engine combines their values, commonly by taking the larger, the smaller or the average.

Your turn

A ball dropped from 1.5 m bounces to 0.96 m. Its coefficient of restitution is .

A ball hits a floor at 5 m/s with e = 0.6. It leaves the floor at m/s.

A ball with e = 0.8 is dropped from 2 m. After its third bounce it reaches m, to 3 significant figures.

Explain why a value of e greater than 1 would break conservation of energy for a ball bouncing on a fixed floor.

If e were greater than 1 the ball would leave the floor faster than it arrived, so its kinetic energy after the bounce would be greater than before, and it would bounce higher each time. Nothing supplies that extra energy, so it would be created from nothing, which is impossible.

Task 5 - Collisions in two dimensions

Hook

In pool, the cue ball strikes another ball off centre and the two balls fly apart at an angle. How do you predict both directions?

Intuition

At the instant of contact, the only force between two smooth balls acts along the line joining their centres, the contact normal. So split each velocity into a part along the normal and a part along the tangent. The tangent parts are untouched. The normal parts behave exactly like a one-dimensional collision. Recombine the parts and you have the final velocities.

Game engines go one step further and fold all of that into a single impulse jj along the normal, calculated from the closing speed, the restitution and the two masses. Move the offset slider below to go from a head-on hit to a glancing blow. With equal masses and e=1e = 1, notice the angle between the two outgoing velocities.

Formalise

With n^\hat{n} the unit normal pointing from A to B. If the closing speed (v⃗B−v⃗A)⋅n^(\vec{v}_B - \vec{v}_A)\cdot\hat{n} is positive the bodies are already separating and no impulse is applied.

j=−(1+e) (v⃗B−v⃗A)⋅n^1mA+1mBv⃗A′=v⃗A−jmAn^v⃗B′=v⃗B+jmBn^j = \frac{-(1 + e)\,(\vec{v}_B - \vec{v}_A)\cdot\hat{n}}{\dfrac{1}{m_A} + \dfrac{1}{m_B}} \qquad \vec{v}_A' = \vec{v}_A - \frac{j}{m_A}\hat{n} \qquad \vec{v}_B' = \vec{v}_B + \frac{j}{m_B}\hat{n}

Worked example

Body A, 2 kg at 3 m/s, meets body B, 1 kg at -1 m/s, head on along x, so n^=(1,0)\hat{n} = (1, 0). Take e=0.5e = 0.5.

  1. Closing speed. (−1−3)×1=−4 m/s(-1 - 3) \times 1 = -4\text{ m/s}. Negative, so they are approaching.
  2. Impulse. j=−(1.5)(−4)/(0.5+1)=6/1.5=4 N sj = -(1.5)(-4) / (0.5 + 1) = 6 / 1.5 = 4\text{ N s}.
  3. New velocities. vA′=3−4/2=1 m/sv_A' = 3 - 4/2 = 1\text{ m/s}, vB′=−1+4/1=3 m/sv_B' = -1 + 4/1 = 3\text{ m/s}.
  4. Checks. Momentum before 6−1=56 - 1 = 5, after 2+3=52 + 3 = 5. Separation speed 3−1=2=0.5×43 - 1 = 2 = 0.5 \times 4.

Your turn

Two 1 kg discs, A moving at (3, 0) m/s and B at rest, touch with contact normal n^=(0.8,0.6)\hat{n} = (0.8, 0.6). Take e=1e = 1.

The closing speed along the normal is m/s and the impulse is N s.

After the collision, A moves at (, ) m/s.

After the collision, B moves at (, ) m/s.

In the exercise above, what is the angle between the two final velocities?

Their dot product is 1.08 × 1.92 - 1.44 × 1.44 = 0. Equal masses with e = 1 and one at rest always leave at right angles.

In a frictionless 2D collision, which part of each velocity is unchanged?

The contact force acts only along the normal, so it cannot change the tangential components.

Task 6 - Impulse-based collision response in code

Collision response in a physics engine happens in two stages. Collision detection finds which bodies are touching and the contact normal between them. Collision response then changes their velocities. This task builds the response stage for circular bodies using the impulse formula from Task 5.

Create a new Console App (C++) project named CollisionResponse and replace its source file with the skeleton below, saved as CollisionResponse.cpp. Every scenario in main places two discs of radius 0.5 m exactly touching, so detection is already done.

  1. Calculate the contact normal n, the vector from a.position to b.position divided by its length.
  2. Calculate the closing speed as the dot product of b.velocity - a.velocity with n.
  3. If the closing speed is positive, return straight away.
  4. Calculate the impulse magnitude j.
  5. Subtract n * (j / a.mass) from a.velocity and add n * (j / b.mass) to b.velocity.

Success condition: in every scenario the momentum before matches the momentum after. Equal masses head on swap velocities. The glancing blow gives (1.08, -1.44) and (1.92, 1.44), matching your answers to Task 5. The worked example gives 1 and 3 m/s. The already separating pair is left unchanged.

CollisionResponse.cpp
#include <cmath>
#include <iomanip>
#include <iostream>
#include <string>

struct Vec2
{
    double x;
    double y;
};

Vec2 operator+(Vec2 a, Vec2 b) { return { a.x + b.x, a.y + b.y }; }
Vec2 operator-(Vec2 a, Vec2 b) { return { a.x - b.x, a.y - b.y }; }
Vec2 operator*(Vec2 a, double s) { return { a.x * s, a.y * s }; }
double dot(Vec2 a, Vec2 b) { return a.x * b.x + a.y * b.y; }
double length(Vec2 a) { return std::sqrt(dot(a, a)); }

struct Body
{
    double mass;
    Vec2 position;
    Vec2 velocity;
};

Vec2 momentum(const Body& a, const Body& b)
{
    return a.velocity * a.mass + b.velocity * b.mass;
}

double kineticEnergy(const Body& a, const Body& b)
{
    return 0.5 * a.mass * dot(a.velocity, a.velocity)
         + 0.5 * b.mass * dot(b.velocity, b.velocity);
}

void resolveCollision(Body& a, Body& b, double e)
{
    // TODO: the contact normal n is the unit vector from a's centre to b's

    // TODO: the closing speed is the relative velocity (b minus a) along n

    // TODO: if that value is positive the bodies are already moving apart,
    // so return without changing anything

    // TODO: impulse magnitude j = -(1 + e) * closing / (1 / ma + 1 / mb)

    // TODO: push a back along n by j / ma and b forward along n by j / mb
}

void runScenario(const std::string& name, Body a, Body b, double e)
{
    Vec2 pBefore = momentum(a, b);
    double keBefore = kineticEnergy(a, b);

    resolveCollision(a, b, e);

    Vec2 pAfter = momentum(a, b);
    std::cout << name << "  (e = " << e << ")\n";
    std::cout << "  A after  (" << a.velocity.x << ", " << a.velocity.y << ")\n";
    std::cout << "  B after  (" << b.velocity.x << ", " << b.velocity.y << ")\n";
    std::cout << "  momentum before (" << pBefore.x << ", " << pBefore.y << ")"
              << "  after (" << pAfter.x << ", " << pAfter.y << ")\n";
    std::cout << "  kinetic energy before " << keBefore << " J"
              << "  after " << kineticEnergy(a, b) << " J\n\n";
}

int main()
{
    std::cout << std::fixed << std::setprecision(3);

    // Each pair of discs has radius 0.5 m and is placed exactly touching
    runScenario("Head-on, equal masses",
        { 1.0, { 0.0, 0.0 }, { 3.0, 0.0 } }, { 1.0, { 1.0, 0.0 }, { 0.0, 0.0 } }, 1.0);
    runScenario("Head-on, heavy hits light",
        { 4.0, { 0.0, 0.0 }, { 3.0, 0.0 } }, { 1.0, { 1.0, 0.0 }, { 0.0, 0.0 } }, 1.0);
    runScenario("Glancing blow, equal masses",
        { 1.0, { 0.0, 0.0 }, { 3.0, 0.0 } }, { 1.0, { 0.8, 0.6 }, { 0.0, 0.0 } }, 1.0);
    runScenario("Worked example from Task 5",
        { 2.0, { 0.0, 0.0 }, { 3.0, 0.0 } }, { 1.0, { 1.0, 0.0 }, { -1.0, 0.0 } }, 0.5);
    runScenario("Already separating",
        { 1.0, { 0.0, 0.0 }, { -1.0, 0.0 } }, { 1.0, { 1.0, 0.0 }, { 1.0, 0.0 } }, 1.0);
    return 0;
}

Why does the response need to return early when the bodies are already separating?

Detection only checks whether two bodies overlap, not which way they are moving. Two bodies can still be overlapping on the frame after a collision has already been resolved, while they move apart. Applying another impulse then would push them back together, so they would stick or jitter. Checking the closing speed makes sure an impulse is only applied while they are approaching.

Solution

Try the tasks above before revealing the solution.