summaryrefslogtreecommitdiff
path: root/2d
diff options
context:
space:
mode:
authorMatthew Kosarek <mattkae@protonmail.com>2021-06-24 13:49:23 -0400
committerMatthew Kosarek <mattkae@protonmail.com>2021-06-24 13:49:23 -0400
commit410a072c3862481f729c293402ddd49c5ae98769 (patch)
tree6fbd4b31b355cd0228bd790415762b446dcd4ab3 /2d
parent0f1275d7ba1a7e3ad838423c15d78e23c960f80e (diff)
(mkosarek) Decent enough discussion of 2d rotational forces
Diffstat (limited to '2d')
-rw-r--r--2d/rigidbody/rigidbody_1.html8
-rw-r--r--2d/rigidbody/rigidbody_1.html.content4
-rw-r--r--2d/rigidbody/rigidbody_2.html175
-rw-r--r--2d/rigidbody/rigidbody_2.html.content71
-rw-r--r--2d/rigidbody/rigidbody_2/main.cpp7
-rw-r--r--2d/rigidbody/rigidbody_2/snippet1.cpp12
-rw-r--r--2d/rigidbody/rigidbody_2/snippet2.cpp8
-rw-r--r--2d/rigidbody/rigidbody_2/snippet3.cpp88
-rw-r--r--2d/rigidbody/rigidbody_2/tinysnippet.cpp4
9 files changed, 366 insertions, 11 deletions
diff --git a/2d/rigidbody/rigidbody_1.html b/2d/rigidbody/rigidbody_1.html
index 8e78972..79fd09b 100644
--- a/2d/rigidbody/rigidbody_1.html
+++ b/2d/rigidbody/rigidbody_1.html
@@ -103,7 +103,7 @@
</section>
<section>
- <h2>The Kinematics Data Structure</h2>
+ <h2>The Data Structure</h2>
<p>
Now that we have an understanding of these two fundamental fields of physics, we can begin setting up our rigidbody data structure.
@@ -118,7 +118,7 @@
</p>
</section>
<section>
- <h2>The Dynamics Functions</h2>
+ <h2>The Functions</h2>
<p>
Now, let's put that Rigidbody data structure to work! As I mentioned earlier, you can think of dynamics as the <i>input</i> to the system. What we're going to do now is add a way apply some sort of force to our rigidbody instantaneously.
@@ -174,7 +174,7 @@
<span class="code_keyword">bool</span> isDead = false;
};
-const <span class="code_keyword">int32</span> NUM_IMPULSES = 4;
+<span class="code_keyword">const</span> <span class="code_keyword">int32</span> NUM_IMPULSES = 4;
<span class="code_keyword">struct</span> Rigidbody {
<span class="code_keyword">int32</span> numImpulses = 0;
@@ -228,7 +228,7 @@ const <span class="code_keyword">int32</span> NUM_IMPULSES = 4;
<span class="code_keyword">void</span> applyImpulse(Impulse i) {
if (numImpulses > NUM_IMPULSES) {
printf("Unable to apply impulse. Buffer full.\n");
- return;
+ <span class="code_keyword">return</span>;
}
activeImpulses[numImpulses] = i;
diff --git a/2d/rigidbody/rigidbody_1.html.content b/2d/rigidbody/rigidbody_1.html.content
index c54fdab..567ca98 100644
--- a/2d/rigidbody/rigidbody_1.html.content
+++ b/2d/rigidbody/rigidbody_1.html.content
@@ -51,7 +51,7 @@
</section>
<section>
- <h2>The Kinematics Data Structure</h2>
+ <h2>The Data Structure</h2>
<p>
Now that we have an understanding of these two fundamental fields of physics, we can begin setting up our rigidbody data structure.
@@ -61,7 +61,7 @@
</p>
</section>
<section>
- <h2>The Dynamics Functions</h2>
+ <h2>The Functions</h2>
<p>
Now, let's put that Rigidbody data structure to work! As I mentioned earlier, you can think of dynamics as the <i>input</i> to the system. What we're going to do now is add a way apply some sort of force to our rigidbody instantaneously.
diff --git a/2d/rigidbody/rigidbody_2.html b/2d/rigidbody/rigidbody_2.html
index 4d85e50..53df782 100644
--- a/2d/rigidbody/rigidbody_2.html
+++ b/2d/rigidbody/rigidbody_2.html
@@ -68,13 +68,186 @@
</script>
<article>
<h1>Rigidbody #2: Rotational Forces</h1>
+ <p>
+ Now that we have linear forces acting upon the 2D objects in our scene, it is about time we incorporate rotational forces into our simulation. Please keep in mind that I do not go too into depth on why the rotational quantities and formulas are the way that they are. If you are looking for this information, I have linked to some great articles on physics (specifically Chris Hecker's articles!) on the home page.
+ </p>
<section>
- <h2>Explanation</h2>
+ <h2>What are rotational forces?</h2>
+ <p>
+ Rotational forces help us to model how an object is rotating around its center of mass. The great part is that they have a lot in common with their linear counterparts: <b>torque</b> (&#x3C4;) is the rotational equivalent of linear force; <b>angular acceleration</b> (&#x3B1;) is the rotational equivalent of linear acceleration; <b>angular velocity</b> (&#969;) is the rotational equivalent of linear velocity; <b>moment of inertia</b> (I) is the rotational equivalent of center of mass; and the current <b>rotation</b> of an object is the equivalent of the position of the object. In two dimensions, all of the angular quantities can be defined using a single floating point number (in 3D, this gets a little more complicated).
+ </p>
+ </section>
+ <section>
+ <h2>The Data Structure</h2>
+ <p>
+ Rotational forces introduce three new quanities into our Rigid Body data structure:
+ <ul>
+ <li><b>Rotational Velocity</b> <i>(float)</i>: Much like linear velocity, this value defines the rate at which our object is currently rotating around its center of mass.</li>
+ <li><b>Rotation</b> <i>(float)</i>: Much like position in the linear world, this value describes the current rotation of our object around its center of mass.</li>
+ <li><b>Moment of inertia</b> <i>(float)</i>: This quanitity defined how much our object <i>wants to</i> rotate around its center of mass. A higher moment of inertia means an object is less likely to rotate, while a lower moment of a inertia means an object is more likely to rotate.</li>
+ </ul>
+
+ Adding these three new quanities to the Rigidbody struct from last time, we get someting that looks like this:
+
+ <pre><code><span class="code_keyword">struct</span> Rigidbody {
+ <span class="code_keyword">int32</span> numImpulses = 0;
+ Impulse activeImpulses[NUM_IMPULSES];
+ <span class="code_keyword">Vector2</span> velocity = { 0, 0 };
+ <span class="code_keyword">Vector2</span> position = { 0, 0 };
+ <span class="code_keyword">float32</span> mass = 1.f;
+ <span class="code_keyword">float32</span> rotationalVelocity = 0.f;
+ <span class="code_keyword">float32</span> rotation = 0.f;
+ <span class="code_keyword">float32</span> momentOfInertia = 1.f;
+ ...
+}
+</code></pre>
+ Now, that's enough for the data side, let's see how we can input some forces into this data structure to make it move.
+ </p>
+ </section>
+ <section>
+ <h2>The Functions</h2>
+ <p>
+ When we inputted a force into our system in the first rigidbody example, we simply told the system "apply this force to the whole object over time." With the introduction of the rotational quantities into our model, we now say "apply this force <i>at this particualr point of the object</i> over time." This point is what we'll call the <b>point of application</b>. Our Impulse struct from last time will now look something like this:
+
+ <pre><code><span class="code_keyword">struct</span> Impulse {
+ <span class="code_keyword">Vector2</span> force = { 0, 0 };
+ <span class="code_keyword">Vector2</span> pointOfApplication = { 0, 0 };
+ <span class="code_keyword">float32</span> timeOfApplicationSeconds = 0.25f;
+ <span class="code_keyword">float32</span> timeAppliedSeconds = 0.f;
+ <span class="code_keyword">bool</span> isDead = false;
+};
+</code></pre>
+ So what's the big deal about including this point of application? Well, from physics, we get the following formula:
+ <br/>
+ <div class="formula">
+ <math class="formula">
+ &#x3C4; = r x F
+ </math>
+ </div>
+
+ In laymen's terms, this says that the torque is equal to the perpendicular of the force at <i>r</i>, which is the point of application. When you think about this in your head, it makes a lot of sense. For example, if you smack the top of a pencil from the top with your hand, it's not really going to rotate. However, if you smack the top of the pencil <i>from the side</i> with your hand, it is going to rotate a lot. This is because taking the cross product of the end of the pencil (i.e. the point of application) with the force of your hand (i.e. the force acting on the object) is much larger when <i>r</i> is perpendicular to <i>F</i>.
+
+ <br/><br/>
+
+ One thing to note is that, in 2D, we do not have the cross product, per se. The closest thing we can do is get the vector perpendicular to another vector using the following function:
+
+ <pre><code><span class="code_keyword">Vector2</span> getPerp() {
+ <span class="code_keyword">return</span> { y, -x };
+}
+</code></pre>
+ <br/><br/>
+
+ Now that we've calculate torque, we just need to get angular acceleration, which, when differentiated with respect to time, will yield the velocity and position. Angualr acceleration relates to torque according to this formula:
+ <br/>
+ <div class="formula">
+ <math class="formula">
+ &#x3C4; = I * &#x3B1;<br/>
+ &#x3B1 = &#x3C4; / I
+ </math>
+ </div>
+
+ The <i>I</i> in this case refers to the <b>moment of inertia</b> that I mentioned earlier. As you can tell, the larger the moment of inertia, the less like my object is going to be rotating. You can experience moment of inertia with the following example: Grab the middle of a pencil between your index and thumb fingers. Rotate it back and forth, and note how easy it is do so. Next, grab the end of the pencil and do the same thing. Note that it feels slightly more difficult to rotate the pencil now. This is because of moment of inertia! While you can calculate this quanitity (either manually or programatically), you will find the moment of inertia of many simple objects online.
+
+ <br/><br/>
+
+ With all of this in mind, we're ready for the code that puts it all together!:
+
+ <pre><code><span class="code_keyword">struct</span> Impulse {
+ <span class="code_keyword">Vector2</span> force = { 0, 0 };
+ <span class="code_keyword">Vector2</span> pointOfApplication = { 0, 0 };
+ <span class="code_keyword">float32</span> timeOfApplicationSeconds = 0.25f;
+ <span class="code_keyword">float32</span> timeAppliedSeconds = 0.f;
+ <span class="code_keyword">bool</span> isDead = false;
+};
+
+<span class="code_keyword">const</span> <span class="code_keyword">int32</span> NUM_IMPULSES = 4;
+
+<span class="code_keyword">struct</span> Rigidbody {
+ <span class="code_keyword">int32</span> numImpulses = 0;
+ Impulse activeImpulses[NUM_IMPULSES];
+ <span class="code_keyword">Vector2</span> velocity = { 0, 0 };
+ <span class="code_keyword">Vector2</span> position = { 0, 0 };
+ <span class="code_keyword">float32</span> mass = 1.f;
+
+ <span class="code_keyword">float32</span> rotationalVelocity = 0.f;
+ <span class="code_keyword">float32</span> rotation = 0.f;
+ <span class="code_keyword">float32</span> momentOfInertia = 1.f;
+
+ <span class="code_keyword">void</span> reset() {
+ numImpulses = 0;
+ velocity = { 0, 0 };
+ rotationalVelocity = 0.f;
+ rotation = 0.f;
+ }
+
+ <span class="code_keyword">void</span> applyImpulse(Impulse i) {
+ if (numImpulses > NUM_IMPULSES) {
+ printf("Unable to apply impulse. Buffer full.\n");
+ <span class="code_keyword">return</span>;
+ }
+
+ activeImpulses[numImpulses] = i;
+ numImpulses++;
+ }
+
+ <span class="code_keyword">void</span> applyGravity(float32 deltaTimeSeconds) {
+ velocity += (Vector2 { 0.f, -9.8f } * deltaTimeSeconds);
+ }
+
+ <span class="code_keyword">void</span> update(float32 deltaTimeSeconds) {
+ applyGravity(deltaTimeSeconds);
+
+ <span class="code_keyword">Vector2</span> force;
+ <span class="code_keyword">float32</span> torque = 0.f;
+ for (int32 idx = 0; idx < numImpulses; idx++) {
+ Impulse& i = activeImpulses[idx];
+
+ <span class="code_keyword">float32</span> nextTimeAppliedSeconds = i.timeAppliedSeconds + deltaTimeSeconds;
+ if (nextTimeAppliedSeconds >= i.timeOfApplicationSeconds) {
+ nextTimeAppliedSeconds = i.timeOfApplicationSeconds;
+ i.isDead = true;
+ }
+
+ <span class="code_keyword">float32</span> impulseDtSeconds = nextTimeAppliedSeconds - i.timeAppliedSeconds;
+ <span class="code_keyword">Vector2</span> forceToApply = i.force * (impulseDtSeconds / i.timeOfApplicationSeconds);
+ force += forceToApply * impulseDtSeconds;
+
+ <span class="code_comment">// New! Increment the torque for each force</span>
+ torque += i.pointOfApplication.getPerp().dot(forceToApply);
+
+ i.timeAppliedSeconds = nextTimeAppliedSeconds;
+ }
+
+ <span class="code_keyword">Vector2</span> acceleration = force / mass;
+ velocity += (acceleration * deltaTimeSeconds);
+ position += (velocity * deltaTimeSeconds);
+
+ <span class="code_comment">// New! Update the rotational velocity as well</span>
+ <span class="code_keyword">float32</span> rotationalAcceleration = torque / momentOfInertia;
+ rotationalVelocity += (rotationalAcceleration * deltaTimeSeconds);
+ rotation += (rotationalVelocity * deltaTimeSeconds);
+
+ for (int32 idx = 0; idx < numImpulses; idx++) {
+ if (activeImpulses[idx].isDead) {
+ for (int j = idx + 1; j < numImpulses; j++) {
+ activeImpulses[j - 1] = activeImpulses[j];
+ }
+
+ idx = idx - 1;
+ numImpulses--;
+ }
+ }
+ }
+};
+</code></pre> </p>
</section>
<section>
<h2>
Live Example
</h2>
+ <p>
+ This demo is much like the one in the first rigidbody example, with the addition of torque.
+ </p>
<div class="opengl_canvas_container">
<canvas id="gl_canvas" width="800" height="600"></canvas>
<button id="gl_canvas_play" class="play_button">
diff --git a/2d/rigidbody/rigidbody_2.html.content b/2d/rigidbody/rigidbody_2.html.content
index 351d544..5ac04a7 100644
--- a/2d/rigidbody/rigidbody_2.html.content
+++ b/2d/rigidbody/rigidbody_2.html.content
@@ -16,13 +16,82 @@
</script>
<article>
<h1>Rigidbody #2: Rotational Forces</h1>
+ <p>
+ Now that we have linear forces acting upon the 2D objects in our scene, it is about time we incorporate rotational forces into our simulation. Please keep in mind that I do not go too into depth on why the rotational quantities and formulas are the way that they are. If you are looking for this information, I have linked to some great articles on physics (specifically Chris Hecker's articles!) on the home page.
+ </p>
<section>
- <h2>Explanation</h2>
+ <h2>What are rotational forces?</h2>
+ <p>
+ Rotational forces help us to model how an object is rotating around its center of mass. The great part is that they have a lot in common with their linear counterparts: <b>torque</b> (&#x3C4;) is the rotational equivalent of linear force; <b>angular acceleration</b> (&#x3B1;) is the rotational equivalent of linear acceleration; <b>angular velocity</b> (&#969;) is the rotational equivalent of linear velocity; <b>moment of inertia</b> (I) is the rotational equivalent of center of mass; and the current <b>rotation</b> of an object is the equivalent of the position of the object. In two dimensions, all of the angular quantities can be defined using a single floating point number (in 3D, this gets a little more complicated).
+ </p>
+ </section>
+ <section>
+ <h2>The Data Structure</h2>
+ <p>
+ Rotational forces introduce three new quanities into our Rigid Body data structure:
+ <ul>
+ <li><b>Rotational Velocity</b> <i>(float)</i>: Much like linear velocity, this value defines the rate at which our object is currently rotating around its center of mass.</li>
+ <li><b>Rotation</b> <i>(float)</i>: Much like position in the linear world, this value describes the current rotation of our object around its center of mass.</li>
+ <li><b>Moment of inertia</b> <i>(float)</i>: This quanitity defined how much our object <i>wants to</i> rotate around its center of mass. A higher moment of inertia means an object is less likely to rotate, while a lower moment of a inertia means an object is more likely to rotate.</li>
+ </ul>
+
+ Adding these three new quanities to the Rigidbody struct from last time, we get someting that looks like this:
+
+ #SNIPPET rigidbody_2/snippet1.cpp
+
+ Now, that's enough for the data side, let's see how we can input some forces into this data structure to make it move.
+ </p>
+ </section>
+ <section>
+ <h2>The Functions</h2>
+ <p>
+ When we inputted a force into our system in the first rigidbody example, we simply told the system "apply this force to the whole object over time." With the introduction of the rotational quantities into our model, we now say "apply this force <i>at this particualr point of the object</i> over time." This point is what we'll call the <b>point of application</b>. Our Impulse struct from last time will now look something like this:
+
+ #SNIPPET rigidbody_2/snippet2.cpp
+
+ So what's the big deal about including this point of application? Well, from physics, we get the following formula:
+ <br/>
+ <div class="formula">
+ <math class="formula">
+ &#x3C4; = r x F
+ </math>
+ </div>
+
+ In laymen's terms, this says that the torque is equal to the perpendicular of the force at <i>r</i>, which is the point of application. When you think about this in your head, it makes a lot of sense. For example, if you smack the top of a pencil from the top with your hand, it's not really going to rotate. However, if you smack the top of the pencil <i>from the side</i> with your hand, it is going to rotate a lot. This is because taking the cross product of the end of the pencil (i.e. the point of application) with the force of your hand (i.e. the force acting on the object) is much larger when <i>r</i> is perpendicular to <i>F</i>.
+
+ <br/><br/>
+
+ One thing to note is that, in 2D, we do not have the cross product, per se. The closest thing we can do is get the vector perpendicular to another vector using the following function:
+
+ #SNIPPET rigidbody_2/tinysnippet.cpp
+
+ <br/><br/>
+
+ Now that we've calculate torque, we just need to get angular acceleration, which, when differentiated with respect to time, will yield the velocity and position. Angualr acceleration relates to torque according to this formula:
+ <br/>
+ <div class="formula">
+ <math class="formula">
+ &#x3C4; = I * &#x3B1;<br/>
+ &#x3B1 = &#x3C4; / I
+ </math>
+ </div>
+
+ The <i>I</i> in this case refers to the <b>moment of inertia</b> that I mentioned earlier. As you can tell, the larger the moment of inertia, the less like my object is going to be rotating. You can experience moment of inertia with the following example: Grab the middle of a pencil between your index and thumb fingers. Rotate it back and forth, and note how easy it is do so. Next, grab the end of the pencil and do the same thing. Note that it feels slightly more difficult to rotate the pencil now. This is because of moment of inertia! While you can calculate this quanitity (either manually or programatically), you will find the moment of inertia of many simple objects online.
+
+ <br/><br/>
+
+ With all of this in mind, we're ready for the code that puts it all together!:
+
+ #SNIPPET rigidbody_2/snippet3.cpp
+ </p>
</section>
<section>
<h2>
Live Example
</h2>
+ <p>
+ This demo is much like the one in the first rigidbody example, with the addition of torque.
+ </p>
<div class="opengl_canvas_container">
<canvas id="gl_canvas" width="800" height="600"></canvas>
<button id="gl_canvas_play" class="play_button">
diff --git a/2d/rigidbody/rigidbody_2/main.cpp b/2d/rigidbody/rigidbody_2/main.cpp
index bad6949..123cf7e 100644
--- a/2d/rigidbody/rigidbody_2/main.cpp
+++ b/2d/rigidbody/rigidbody_2/main.cpp
@@ -63,13 +63,15 @@ struct Rigidbody {
float32 nextTimeAppliedSeconds = i.timeAppliedSeconds + deltaTimeSeconds;
if (nextTimeAppliedSeconds >= i.timeOfApplicationSeconds) {
- nextTimeAppliedSeconds = i.timeOfApplicationSeconds; // Do the remainder of the time
+ nextTimeAppliedSeconds = i.timeOfApplicationSeconds;
i.isDead = true;
}
float32 impulseDtSeconds = nextTimeAppliedSeconds - i.timeAppliedSeconds;
Vector2 forceToApply = i.force * (impulseDtSeconds / i.timeOfApplicationSeconds);
force += forceToApply * impulseDtSeconds;
+
+ // New! Increment the torque for each force
torque += i.pointOfApplication.getPerp().dot(forceToApply);
i.timeAppliedSeconds = nextTimeAppliedSeconds;
@@ -79,12 +81,11 @@ struct Rigidbody {
velocity += (acceleration * deltaTimeSeconds);
position += (velocity * deltaTimeSeconds);
- // New: Update the rotational velocity as well
+ // New! Update the rotational velocity as well
float32 rotationalAcceleration = torque / momentOfInertia;
rotationalVelocity += (rotationalAcceleration * deltaTimeSeconds);
rotation += (rotationalVelocity * deltaTimeSeconds);
- // Cleanup any impulses that have expired in the mean time
for (int32 idx = 0; idx < numImpulses; idx++) {
if (activeImpulses[idx].isDead) {
for (int j = idx + 1; j < numImpulses; j++) {
diff --git a/2d/rigidbody/rigidbody_2/snippet1.cpp b/2d/rigidbody/rigidbody_2/snippet1.cpp
new file mode 100644
index 0000000..fbc7bf1
--- /dev/null
+++ b/2d/rigidbody/rigidbody_2/snippet1.cpp
@@ -0,0 +1,12 @@
+
+struct Rigidbody {
+ int32 numImpulses = 0;
+ Impulse activeImpulses[NUM_IMPULSES];
+ Vector2 velocity = { 0, 0 };
+ Vector2 position = { 0, 0 };
+ float32 mass = 1.f;
+ float32 rotationalVelocity = 0.f;
+ float32 rotation = 0.f;
+ float32 momentOfInertia = 1.f;
+ ...
+}
diff --git a/2d/rigidbody/rigidbody_2/snippet2.cpp b/2d/rigidbody/rigidbody_2/snippet2.cpp
new file mode 100644
index 0000000..bd0cdb2
--- /dev/null
+++ b/2d/rigidbody/rigidbody_2/snippet2.cpp
@@ -0,0 +1,8 @@
+
+struct Impulse {
+ Vector2 force = { 0, 0 };
+ Vector2 pointOfApplication = { 0, 0 };
+ float32 timeOfApplicationSeconds = 0.25f;
+ float32 timeAppliedSeconds = 0.f;
+ bool isDead = false;
+};
diff --git a/2d/rigidbody/rigidbody_2/snippet3.cpp b/2d/rigidbody/rigidbody_2/snippet3.cpp
new file mode 100644
index 0000000..7b7130c
--- /dev/null
+++ b/2d/rigidbody/rigidbody_2/snippet3.cpp
@@ -0,0 +1,88 @@
+
+struct Impulse {
+ Vector2 force = { 0, 0 };
+ Vector2 pointOfApplication = { 0, 0 };
+ float32 timeOfApplicationSeconds = 0.25f;
+ float32 timeAppliedSeconds = 0.f;
+ bool isDead = false;
+};
+
+const int32 NUM_IMPULSES = 4;
+
+struct Rigidbody {
+ int32 numImpulses = 0;
+ Impulse activeImpulses[NUM_IMPULSES];
+ Vector2 velocity = { 0, 0 };
+ Vector2 position = { 0, 0 };
+ float32 mass = 1.f;
+
+ float32 rotationalVelocity = 0.f;
+ float32 rotation = 0.f;
+ float32 momentOfInertia = 1.f;
+
+ void reset() {
+ numImpulses = 0;
+ velocity = { 0, 0 };
+ rotationalVelocity = 0.f;
+ rotation = 0.f;
+ }
+
+ void applyImpulse(Impulse i) {
+ if (numImpulses > NUM_IMPULSES) {
+ printf("Unable to apply impulse. Buffer full.\n");
+ return;
+ }
+
+ activeImpulses[numImpulses] = i;
+ numImpulses++;
+ }
+
+ void applyGravity(float32 deltaTimeSeconds) {
+ velocity += (Vector2 { 0.f, -9.8f } * deltaTimeSeconds);
+ }
+
+ void update(float32 deltaTimeSeconds) {
+ applyGravity(deltaTimeSeconds);
+
+ Vector2 force;
+ float32 torque = 0.f;
+ for (int32 idx = 0; idx < numImpulses; idx++) {
+ Impulse& i = activeImpulses[idx];
+
+ float32 nextTimeAppliedSeconds = i.timeAppliedSeconds + deltaTimeSeconds;
+ if (nextTimeAppliedSeconds >= i.timeOfApplicationSeconds) {
+ nextTimeAppliedSeconds = i.timeOfApplicationSeconds;
+ i.isDead = true;
+ }
+
+ float32 impulseDtSeconds = nextTimeAppliedSeconds - i.timeAppliedSeconds;
+ Vector2 forceToApply = i.force * (impulseDtSeconds / i.timeOfApplicationSeconds);
+ force += forceToApply * impulseDtSeconds;
+
+ // New! Increment the torque for each force
+ torque += i.pointOfApplication.getPerp().dot(forceToApply);
+
+ i.timeAppliedSeconds = nextTimeAppliedSeconds;
+ }
+
+ Vector2 acceleration = force / mass;
+ velocity += (acceleration * deltaTimeSeconds);
+ position += (velocity * deltaTimeSeconds);
+
+ // New! Update the rotational velocity as well
+ float32 rotationalAcceleration = torque / momentOfInertia;
+ rotationalVelocity += (rotationalAcceleration * deltaTimeSeconds);
+ rotation += (rotationalVelocity * deltaTimeSeconds);
+
+ for (int32 idx = 0; idx < numImpulses; idx++) {
+ if (activeImpulses[idx].isDead) {
+ for (int j = idx + 1; j < numImpulses; j++) {
+ activeImpulses[j - 1] = activeImpulses[j];
+ }
+
+ idx = idx - 1;
+ numImpulses--;
+ }
+ }
+ }
+};
diff --git a/2d/rigidbody/rigidbody_2/tinysnippet.cpp b/2d/rigidbody/rigidbody_2/tinysnippet.cpp
new file mode 100644
index 0000000..2f8fbdd
--- /dev/null
+++ b/2d/rigidbody/rigidbody_2/tinysnippet.cpp
@@ -0,0 +1,4 @@
+
+Vector2 getPerp() {
+ return { y, -x };
+}