From ff82253a66ee51fe2f0c088ca964402d53545845 Mon Sep 17 00:00:00 2001
From: Matthew Kosarek <mattkae@protonmail.com>
Date: Thu, 24 Jun 2021 11:30:36 -0400
Subject: (mkosarek) Rigidbody with rotations

---
 2d/rigidbody/rigidbody_2/dist/output.wasm | Bin 48126 -> 50226 bytes
 2d/rigidbody/rigidbody_2/main.cpp         |  80 ++++++++++++++++++++++++------
 2 files changed, 64 insertions(+), 16 deletions(-)

(limited to '2d/rigidbody/rigidbody_2')

diff --git a/2d/rigidbody/rigidbody_2/dist/output.wasm b/2d/rigidbody/rigidbody_2/dist/output.wasm
index f7dcbd9..29c319a 100755
Binary files a/2d/rigidbody/rigidbody_2/dist/output.wasm and b/2d/rigidbody/rigidbody_2/dist/output.wasm differ
diff --git a/2d/rigidbody/rigidbody_2/main.cpp b/2d/rigidbody/rigidbody_2/main.cpp
index 5f875b8..bad6949 100644
--- a/2d/rigidbody/rigidbody_2/main.cpp
+++ b/2d/rigidbody/rigidbody_2/main.cpp
@@ -11,46 +11,90 @@
 #include <cmath>
 #include <cfloat>
 
+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 {
-	Vector2 linearForce = { 0, 0 };
+    int32 numImpulses = 0;
+    Impulse activeImpulses[NUM_IMPULSES];
     Vector2 velocity = { 0, 0 };
     Vector2 position = { 0, 0 };
     float32 mass = 1.f;
 
-	float32 torque = 0.f;
 	float32 rotationalVelocity = 0.f;
 	float32 rotation = 0.f;
 	float32 momentOfInertia = 1.f;
 
     void reset() {
-        linearForce = { 0, 0 };
+        numImpulses = 0;
         velocity = { 0, 0 };
 		rotationalVelocity = 0.f;
 		rotation = 0.f;
     }
 
-    void applyForce(Vector2 force, Vector2 pointOfApplication) {
-        linearForce += force;
-	    torque += pointOfApplication.getPerp().dot(force);
+    void applyImpulse(Impulse i) {
+        if (numImpulses > NUM_IMPULSES) {
+            printf("Unable to apply impulse. Buffer full.\n");
+            return;
+        }
+
+        activeImpulses[numImpulses] = i;
+        numImpulses++;
     }
 
-    void applyGravity() {
-		applyForce(Vector2 { 0.f, -100.f }, Vector2 { 0.f, 0.f });
+    void applyGravity(float32 deltaTimeSeconds) {
+        velocity += (Vector2 { 0.f, -9.8f } * deltaTimeSeconds);
     }
 
     void update(float32 deltaTimeSeconds) {
-        applyGravity();
+        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; // Do the remainder of the time
+                i.isDead = true;
+            }
+            
+            float32 impulseDtSeconds = nextTimeAppliedSeconds - i.timeAppliedSeconds;
+            Vector2 forceToApply = i.force * (impulseDtSeconds / i.timeOfApplicationSeconds);
+            force += forceToApply * impulseDtSeconds;
+            torque += i.pointOfApplication.getPerp().dot(forceToApply);
+
+            i.timeAppliedSeconds = nextTimeAppliedSeconds;
+        }
         
-        Vector2 acceleration = linearForce / mass;
+        Vector2 acceleration = force / mass;
         velocity += (acceleration * deltaTimeSeconds);
         position += (velocity * deltaTimeSeconds);
-        linearForce = Vector2 { 0.f, 0.f };
 
-		// New: Update the rotational velocity as well
+        // New: Update the rotational velocity as well
 		float32 rotationalAcceleration = torque / momentOfInertia;
 		rotationalVelocity += (rotationalAcceleration * deltaTimeSeconds);
 		rotation += (rotationalVelocity * deltaTimeSeconds);
-		torque = 0.f;
+
+        // 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++) {
+                    activeImpulses[j - 1] = activeImpulses[j];
+                }
+
+                idx = idx - 1;
+                numImpulses--;
+            }
+        }
     }
 };
 
@@ -112,6 +156,7 @@ struct Rectangle {
 struct Circle {
 	OrthographicShape shape;
     Rigidbody body;
+    Vector2 force;
 
 	float32 radius = 5.f;
 
@@ -211,7 +256,10 @@ void update(float32 deltaTimeSeconds, void* userData) {
 		if (!isIntersectingPointer) {
 			isIntersectingPointer = true;
 			Vector2 pointOfApplication = pointer.body.position - rectangle.body.position;
-			rectangle.body.applyForce(pointer.body.linearForce, pointOfApplication);
+            Impulse i;
+            i.force = pointer.force;
+            i.pointOfApplication = pointOfApplication;
+			rectangle.body.applyImpulse(i);
 		}
 	} else if (isIntersectingPointer) {
 		isIntersectingPointer = false;
@@ -270,8 +318,8 @@ EM_BOOL onMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void
 		return true;
 	}
 
-	pointer.body.linearForce.x = static_cast<float32>(mouseEvent->movementX) * 1000.f;
-	pointer.body.linearForce.y = static_cast<float32>(-mouseEvent->movementY) * 1000.f;
+    pointer.force.x = static_cast<float32>(mouseEvent->movementX) * 1000.f;
+	pointer.force.y = static_cast<float32>(-mouseEvent->movementY) * 1000.f;
 
 	pointer.body.position.x = static_cast<float32>(mouseEvent->targetX);
 	pointer.body.position.y = static_cast<float32>(600.f - mouseEvent->targetY);
-- 
cgit v1.2.1