The Maths Behind Motion In Games

The Maths Behind Motion In Games

Anthony Littlewood BSc

Brief:

The entire universe around us is built on fundamental mathematical constructs, these constructs must be replicated if any form of motion is to be possible inside a game, many beginners struggle with this and an even larger number of people have no idea of the significance of mathematics in computer graphics.

Physics:

Physics can be defined as the scientific study of matter, and its motion through space and time.

Motion:

Motion can be defined as a change in position or location over a period of time,

This Article:

I wrote this article mainly for people who have an interest in the maths behind games, while there are many pieces of reference material available that can be applied to simulation, many of them are quite frankly terrifying. This Article is here to provide an easy introduction to the core mathematics that are used to run motion in a game. Note that I use the term motion here where many people would use the term physics or dynamics, I do this because I feel the term physics, is subjective and open to interpretation, it is my own feeling that referring instead to motion will keep things easier to understand, also a lot of people are immediately intimidated by the concept of the maths behind physics.

Prerequisites:

In this article I assume the reader has certain things:

  1. at least half a partially functioning brain
  2. access to a computer

I also feel that other things would be useful but are not essential

  1. some programming background
  2. some mathematical skills
  3. a calculator or alternatively a full partially functioning brain

I also have functioning examples of the code running, available feel free to look at these, experiment with them, and try to understand.

If this information is new to you you may get lost, I have tried to create a very gradual learning curve on the information to help, thank you for reading.

In The Beginning:

In the beginning, there was time, there was space and there was maths.

For an object to be moving or traveling, it must have both a position and a relative time-frame, the key point here is that the difference in position is dependent on the flow of time, this dependency is referred to as velocity. The simple formula for this concept is:



basically the vector quantity velocity or “V” is equal to difference in position over difference in time.

If the object or “Body” in motion has a new force applied to it, then the resultant shift in Acceleration will also effect the objects velocity, which will in-turn effect the objects displacement relative to time.

Acceleration can be defined as the difference in an objects velocity over a difference in time.

By using these rules we can use simple forces to govern the movement of bodies in a simulated world.

Enter Mr Newton:

Sir Issac Newton, was born in 1727, and is best known for his realization of the existence of gravity and his respective laws that govern physics, namely:

Newton’s First Law:

in the absence of a net force the center of gravity of a body is either at rest or moving at a constant velocity.

Newton’s Second Law:

f = ma.

Where

f == Force

m == Mass

a == Acceleration

Newton’s Third Law:

For every force applied to a body there is an exact and opposite counteracting force.

The part we are interested in at the moment is Newton’s Second law,

because, if we can determine the force being applied to an object with this equation:

F = M * A”, then we can reverse that equation to “A = F / M” and use it to instead calculate a bodies acceleration. This can then be used to calculate velocity, and therefore calculate position:

A = F / M

V = V + A * Time_Offset

P = P + V * Time_Offset

Example:

A body with a mass of 10 has a force applied to it of 5 over a period of 3 seconds:

F = 5

M = 10

V = 0

P = 0

Time_Offset = 3

A = 5/10;

A = 0.5;

V = 0 + 0.5 * 3

V = 1.5

P = P + 1.5 * 3

P = 4.5

In this case the object would move by 4.5 units, since newtons first law states than a body not under force will maintain constant velocity, if the force is now canceled, and the calculation moved on a further 3 seconds, the object will have moved to 9 units, this is 9 units over 6 seconds or 1.5 units per second. While this has only been calculated in one dimension it is re-applicable to all three dimensions.

What About Walls:

detecting when two objects collide is not terribly hard, there are a number of algorithms for doing this, but getting the collision detection to work well with the motion, is the challenge.

An obvious issue, lies in collisions, in real world physics, if two bodies of equal size, velocity and mass collide in exactly opposite directions the two forces should neutralize each other. The issue here is that a bullet has a low mass but a high speed, verses a wall that has low speed but high mass, the calculation for an accurate collision will require a very small time-step.

in the above example we assumed an input force of 5 and a time offset of 3 seconds.

If we were to instead change the time offset to 300 seconds, there would be a much larger step in displacement, a common problem in physics simulations, is that as the number of active bodies in the world grows, the time taken for the system to update them all also grows, this causes the time gap to grow also and will in turn increase the displacement gap, The problem occurs when the displacement step grows too high and the body will in-fact step over the body it is supposed to be colliding with, and continue through, this occurs most commonly with objects such as projectiles and is an effect known as “tunneling”.

The simple method to get around this can also be used to produce collision responses, while these responses may not be totally realistic, in the interest of performance they are perfectly acceptable and no-one will really care anyway.

The solution is to lock the time-step. If we were to lock the step to a number high enough to detect all collisions, but low enough to not miss anything we have essentially solved the problem. Since we also know that the physics will only be updated lets say every 3 seconds, we have plenty of time to deal with collision detection and response. We can calculate the collision response by using the same calculation we used to get the collision in the first place:

if:

F = 5

A = 5/10

A = 0.5

V = 0 + 0.5 * 3

V = 1.5

P = P + 1.5 * 3

P = 4.5

then

A = -0.5

V = 1.5 + -0.5 * 3

V = 0

P = P + 0 * 3

P =

Why?

if every force applied to a body has an exact and opposite force, it is acceptable to assume that an object forced against an unmovable object with a given force, will bounce back at the exact opposite angle with the exact same force that it hit it with(just like a pool table), obviously in a more complex simulation allocations could also be made for friction,gravity and damping factor.

By using this system with movement flags we can move back a physics step any time we choose.

And can create the starting point of our movement concept code:

float Stored_Acceleration =0.0f;

Int Direction = KeyPressed(A) – KeyPressed(D);

If (Direction<0 )

{

// Move in one direction

F = 5;

A = F / M

V = V + A * Time_Offset

P = P + V * Time_Offset

}

If (Direction>0 )

{

// Move in other direction

F = -5;

A = F / M

V = V + A * Time_Offset

P = P + V * Time_Offset

}

if (Colliding) //if we are colliding

{

V = V – Stored_Acceleration * Time_Offset //simply run the velocity backwards

P = P + V * Time_Offset

}

else

{

Stored_Acceleration = A; get the new Acceleration value

}

Note that the above code is still technically incorrect, I have kept the “Time_Offset” variable in-place for the sake of clarity, but since, the system will be updated with a fixed time step, this variable is in fact totally useless, and should be removed:

float Stored_Acceleration =0.0f;

while (bRunning)

{

if (GetElapsedTimeSinceLastUpdate()>30)//only update the body if the timestep has passed

{

Int Direction = KeyPressed(A) – KeyPressed(D);

If (Direction<0 )

{

// Move in one direction

F = 5;

A = F / M

V = V + A * Time_Offset

P = P + V * Time_Offset

}

If (Direction>0 )

{

// Move in other direction

F = -5;

A = F / M

V = V + A * Time_Offset

P = P + V * Time_Offset

}

if (Colliding) //if we are colliding

{

V = V – Stored_Acceleration * Time_Offset //simply run everything backwards

P = P + V * Time_Offset

}

else

{

Stored_Acceleration = A; get the new Acceleration value

}

}

}

But How About Rotation:

The system we have above is fine for a platfomer but how about when we want to rotate, in a top down shooter for instance, how can we factor our theoretical rotation into the movement.

While the graphical representation of the facing direction of the entity is strictly linked to the graphics side of things as opposed to the physics side, we are very lucky because this very problem has already been solved.

If we treat the displacement from our current position to our next position as a vector, there is no reason why we cannot simply rotate it, if we have the correct set of numbers to multiply it by that is.

Enter Trigonometry:

Most people remember SOH CAH TOA from school, well having that mercilessly burned into your mind is about to pay off.


For those people who weren’t paying attention in school, this is a right angled triangle(you can tell by the right angle ; ) ),

it has 3 sides, the hypotenuse, the opposite and the adjacent.


Enter Mr Pythagoras

Pythagoras born 570bc is well known for his theorem:


He realized that in a right angled triangle, the area of the square formed from the hypotenuse is equal to the sum of the area’s of squares formed from the two other edges, this means that as long as the angle and the size of two edges are known, the final edge can be calculated.


This is what the SOH CAH TOA nonsense really meant:


Sin (X) = Opposite /Hypotenuse

Cos (X) = Adjacent /Hypotenuse

Tan (X) = Opposite / Adjacent

what all of this means is that we can input an angle into Cos() and get back a number representing the x coordinate of a direction vector,

the y coordinate can likewise be calculated using Sin().

Once we have these two values, we can simply create a new formula for calculating the acceleration then we can just plug that into the previous calculation.

Fantastic, Right? Wrong!.

We have one more little problem to resolve,

the Cos and Sin functions don’t use degrees, this means that if we want to rotate by 90 degrees, we need to find a way of converting them to the format used by Cos and Sin namely, the Radian.

WTF Is A Radian?:

A radian is a mathematical method of representing an angle, a lot like a degree, except arguably less accurate, harder to understand and more complicated.

Since mathematicians like life to be difficult for anyone who isn’t a mathematician, they tend to use radians for everything above the really basic stuff.


A radian is basically a angle based on the equal ratio between the arc length and the radius of a unit circle

A radian calculates out to approximately 57.2958 degrees, probably the least helpful number ever imagined by mankind.

What is more important though is what a radian actually means.

The nice thing about a radian is that it provides the only straight forward answer to a question I asked fruitlessly all through school… WTF actually is Pi?.

The truth is that these questions answer each other:

Most people know that there are 360 degrees to a circle.

Likewise there are 2 Pi radians to a circle, or even easier:

there are Pi radians to 180 degrees.

How can we use this

we can create a really easy formula for converting from degrees to radians, then just pass our degrees through that:

int Pi = 3.1415 // close enough

float DegreesToRadians( float AngleInDegrees) return AngleInDegrees * (Pi/180.0f);

then all we need to do is use it:

X = Cos(DegreesToRadians (Angle));

Y = Sin(DegreesToRadians (Angle));

A really nice simple way of doing this code if the dynamics aren’t needed, in the case of projectiles etc is:

X = X+ (deltaTime*Speed) * Cos (Rotationangle * Pi/180.0);

Y = Y+ (deltaTime*Speed) * Sin (Rotationangle * Pi/180.0);

but if you still want them, it is not hard to migrate the calculations:

first, remove the force vectors, since they are no longer used, and instead add a scalar for speed,

the new algorithm for acceleration now becomes:

YAcceleration = Speed* Sin(rotationangle *pi/180.0) / entity0.mass;

XAcceleration = Speed* Cos(rotationangle *pi/180.0) / entity0.mass;

the full algorithm now becomes:

Ay = Speed * Sin(angle * pi/180.0) / M

Ax = Speed * Cos(angle * pi/180.0) / M

Vx = Vx + Ax * Time_Offset

Vy = Vy + Ay * Time_Offset

Px = Px + Vx * Time_Offset

Py = Py + Vy * Time_Offset

Easy Eh?

I have made samples demonstrating this motion, in the interest of keeping things easy to understand and independent, I have amended the collision detection and response from this code.

Collision Detection:

Collision detection is a wide and extensive area, it is also very specific to implementation, and each has various advantages and disadvantages. But this article would not be complete without me showing at least the bare minimal collision detection algorithm:

bool Collide(X1, Y1, Width1, Height1, X2, Y2, Width2, Height2)

{

return ! (

(Y2 > (X1 + Width1 )) ||

(Y1 > (X2 + Width2 )) ||

(Y2 > (Y1 + Height1)) ||

(Y1 > (Y2 + Height2)) )

}

how beautifully simple is that? Basically if the left corner of the rightmost square is less than the right corner of the leftmost square, there has been a collision. Obviously this system does not account for rotation but for most purposes rotation is unnecessary, and in the cases where it is, a simple bounding box is probably not intuitive enough for accurate results, the internet is literally packed with fantastic methods of collision detection and there are a number of very good books which cover the subject, better than I can, If you are genuinely interested they are well worth checking out.

Conclusion

I hope you have enjoyed reading this article as much as I have enjoyed writing it.

If you find an error or mistake on my part please let me know, also please note that the code included here is intended as prototype example code it is here to make things easier to understand, it is not supposed to be copied and pasted.

If you have understood the material, creating the code its self should be trivial. If you have trouble understanding anything, I would be more than happy to help in any way I can,

feel free to contact me at NGangst@goowy.com

No animals were harmed in the making of this article

Thank you -Anthony Littlewood BSc