Collision response

Introduction

The following tutorial attempts to tackle some of
the challenges of writing a collision system for simple games.
Two Lua files are attached at the bottom:
"fizz.lua" containing all the math
and "collision.lua" which is an example script.

Simulation

We begin with "unconstrained" motion
based on simple Newtonian physics.
Each object has a velocity vector that is added
to its position using the formula:

velocity = velocity + gravity*dt
position = position + velocity*dt

These calculations are performed
during each step of the simulation
for every moving (dynamic) object.
For practical reasons, it's useful to limit
the velocity of moving objects to a certain threshold (maxVelocity).
It's also common in games to have non-moving or "static" objects.
Static objects are not affected
by gravity or collisions and can be used
to represent platforms, walls and so on.

1. update the velocities and positions of all moving objects
2. iterate all pairs of intersecting objects
a) move one of the objects (so the two no longer intersect)
b) adjust the velocities of both objects

Detection

First, we want to check if two objects are intersecting.
We'll be looking at axis-aligned rectangles
in particular since they are simple
and sufficient for most old-school games.
One approach is to represent each rectangle shape
as a center position with half-width/height extents.
Axis-aligned rectangle with position and extents

This way, we can simply compare the distance between
the centers of two rectangles against the sum of their extents.
The following algorithm checks the X and Y axis separately:

Separation

Suppose that the previous algorithm detects
an intersection between two rectangles.
Intersection between two rectangles

Next, we have to figure out how much
the first rectangle (a) needs to be displaced (sx, sy)
so that the two shapes are no longer intersecting.
The result is sometimes called the "shortest separation" vector.

Once we know how to find the "separation vector",
it's easy to move the two colliding objects apart.
This alone is enough for games
(like the original Super Mario, Megaman or Contra)
where you just want to ensure that the player cannot
pass through the static environment.

Response

Generally speaking, "realistic" physics simulation is
a difficult problem. So a lot of games have
some collision response (like pushable blocks)
that although not physically accurate,
make a fun addition to the gameplay.
We can produce a variety of effects
by modifying the velocities of one or both
objects during a collision.

Relative velocity

First, we subtract the velocities of the two objects.
This gives us the relative velocity during impact.

Subtracting the velocities of objects a and b allows
us to treat shape b as if it is stationary.

Next, we have to figure out how the moving shape should
react to the collision (bounce, slide or stop completely).
This is done be "splitting" the relative velocity into penetration and tangent components.
Velocity components:
v: velocity (black)
vp: penetration component (red)
vt: tangent component (yellow)
n: collision normal axis (blue)

The dot product (ps) between the relative velocity
and the collision normal (vx*nx + vy*ny)
gives us the speed at which the two objects
are moving toward each other.
This product (ps) may be positive or negative
depending on whether the objects are moving apart or toward each other.

Restitution or bounce

The restitution coefficient (or bounce) describes how "elastic" is the collision.
This coefficient is a value between 0 and 1, where 0 means "inelastic" and 1 means "perfectly elastic".
Example of an elastic (green) versus non-elastic collision (pink).

Restitution always acts along the penetration axis (parallel to the collision normal).
Remember that the "collision normal" is basically the axis of shortest separation between two colliding shapes.

Friction

The friction coefficient describes how much velocity is "lost" when the edges of two shapes are touching.
Friction always acts along the tangent axis (perpendicular to the collision normal).
Note that the two objects may have different friction or
restitution (bounce) coefficients.
Combining each two coefficients "realistically"
involves additional math so we use the "min" and "max"
functions as a simplification.

Finaly, we multiply the penetration component by the restitution (r),
the tangent component by the friction (f) and add them
together to get the resulting change in velocity of the moving shape.

Physics

Mass and momentum

Roland Yonaba pointed out that the equations above do not take mass into consideration.
Therefore a small rectangle can easily push large rectangles when they collide.
In a sense, all rectangles (regardless of their size) are treated as if they have equal mass.
This is usually fine for old-school games and makes the equations a little bit easier to understand.
Mass can be introduced to the simulation as follows:

Coulomb's law and friction

The code in this tutorial makes some obvious
simplifications to the real laws of physics.
However a somewhat subtle error is allowed in the way friction is simulated.
With real life collisions: "the force of friction is always
less than or equal to the normal [separation] force multiplied
by some constant (whose value depends on the materials of the objects)".
Without taking Coulomb's law into consideration
objects with friction tend to behave like they're "sticky".
I mention this perhaps to stir your interest in
real physics and how many of its rich and interesting
equations could be simulated in games.
Demo: simple collision response