Rigidbody #1: Linear Forces

In this first installment of my 2D rigidbody tutorial, we are going to explore linear forces and how we can begin to simulate them in real time on a computer. As you'll come to see, 2D forces are quite easy to understand and implement if you have some basic knowledge of 2D maths. On top of that, they really add a lot of life into what would otherwise be a static 2D scene.

What do we mean by 'Rigid Body Physics'?

In implementing a rigidy body physics system, we're primarily interested in two sub-fields of physics, namely dynamics and kinematics. Although I'm far as can be from being an expert in either of these fields, I will explain - from a programmer's perspective - what they mean to me: Although the distinction between these two subfields may seem inconsequential, it impacts the conceptual way in which we might begin to setup our 2D rigidbody simulation: the kinematic variables are the data that we act upon, while the dynamics variables are the data that we apply.

The Kinematics Data Structure

Now that we have an understanding of these two fundamental fields of physics, we can begin setting up our rigidbody data structure. #SNIPPET rigidbody_1/snippet1.cpp As you can see, the base data structure exactly mirrors what we already know from 2D newtonian physics. Every frame, we will have some force applied to our rigidbody. We will use that force to get accleration, which, when differentied with respect to time, yields velocity and, ultimately, the new position of our rigidbody. For all of this to work, of course, we need a constant mass for this object.

The Dynamics Functions

Now, let's put that Rigidbody data structure to work! As I mentioned earlier, you can think of dynamics as the input to the system. What we're going to do now is add a way apply some sort of force to our rigidbody instantaneously. #SNIPPET rigidbody_1/snippet2.cpp We have three new functions here:

Voila! We have everything we need to start applying forces. But wait! There is one more thing to consider...

Impulses & Frame-Rate Independence

Although it might be good enough for your use case, allow me to explain why the previous approach is neither realistic nor reliable:

When a force is applied in the real world, it doesn't just get applied for a single moment (i.e. frame) in time: it gets applied over time, or for a given duration of time. At the moment, our current implementation fails to account for this. forces are applied for a given frame, and then forgotten about.

Our current approach has another problem too: the applied force is not frame-rate independent. If you were to apply a force of 50N in the Y direction right now, slower computers would experience larger resultant velocities because their deltaTimeSeconds would be much larger. This is generally something that you'd want to avoid in most applications.

One potential fix for this is to use impulses: #SNIPPET rigidbody_1/snippet3.cpp While a bit more verbose than our previous example, this approach has more reliable behavior. Forces are no longer treated as single moments in time, but rather "forces applied over time". Because we ensure that the force is applied over time, we guarantee that all users see the same amount of force applied, regardless of frame-rate.

For anyone interested, the algorithm for using impulses is as follows:

Keep in mind that you can still have what amounts to an "instant" force being applied if you set the duration of the impulse to be very small. Feel free to look at the example program below (and browse/download the code) if you want to see it in action.

Live Example

Click 'Play' on the WebAssembly demo below to see a square bouncing around the screen. When you drag the pointer through the square, we will apply an impulse equivalent to how fast you were moving your mouse in the direction that you were moving it.