diff options
author | Matthew Kosarek <mattkae@protonmail.com> | 2021-05-25 21:33:50 -0400 |
---|---|---|
committer | Matthew Kosarek <mattkae@protonmail.com> | 2021-05-25 21:33:50 -0400 |
commit | 7a4cb77ddccbce28cded0c97cf3bb975aafbec16 (patch) | |
tree | cd62762dc11e190f0706fbed3581021e51d160f6 /2d/rigidbody/rigidbody_2/main.cpp | |
parent | 76b6fa0ce8cfaaab8e2052bdd43266ded8e404b6 (diff) |
Wow, this is why my rotational motion has been so broken for so loing
Diffstat (limited to '2d/rigidbody/rigidbody_2/main.cpp')
-rw-r--r-- | 2d/rigidbody/rigidbody_2/main.cpp | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/2d/rigidbody/rigidbody_2/main.cpp b/2d/rigidbody/rigidbody_2/main.cpp new file mode 100644 index 0000000..5f875b8 --- /dev/null +++ b/2d/rigidbody/rigidbody_2/main.cpp @@ -0,0 +1,280 @@ +#include "../../../shared_cpp/OrthographicRenderer.h" +#include "../../../shared_cpp/types.h" +#include "../../../shared_cpp/WebglContext.h" +#include "../../../shared_cpp/mathlib.h" +#include "../../../shared_cpp/MainLoop.h" +#include <cstdio> +#include <cmath> +#include <emscripten/html5.h> +#include <unistd.h> +#include <pthread.h> +#include <cmath> +#include <cfloat> + +struct Rigidbody { + Vector2 linearForce = { 0, 0 }; + 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 }; + velocity = { 0, 0 }; + rotationalVelocity = 0.f; + rotation = 0.f; + } + + void applyForce(Vector2 force, Vector2 pointOfApplication) { + linearForce += force; + torque += pointOfApplication.getPerp().dot(force); + } + + void applyGravity() { + applyForce(Vector2 { 0.f, -100.f }, Vector2 { 0.f, 0.f }); + } + + void update(float32 deltaTimeSeconds) { + applyGravity(); + + Vector2 acceleration = linearForce / mass; + velocity += (acceleration * deltaTimeSeconds); + position += (velocity * deltaTimeSeconds); + linearForce = Vector2 { 0.f, 0.f }; + + // New: Update the rotational velocity as well + float32 rotationalAcceleration = torque / momentOfInertia; + rotationalVelocity += (rotationalAcceleration * deltaTimeSeconds); + rotation += (rotationalVelocity * deltaTimeSeconds); + torque = 0.f; + } +}; + +struct Rectangle { + OrthographicShape shape; + Rigidbody body; + Vector2 originalPoints[4]; + Vector2 transformedPoints[4]; + + void load(OrthographicRenderer* renderer, Vector4 color, float32 width, float32 height) { + color = color.toNormalizedColor(); + + float32 halfWidth = width / 2.f; + float32 halfHeight = height / 2.f; + + OrthographicVertex vertices[6]; + vertices[0].position = Vector2 { -halfWidth, -halfHeight }; + vertices[1].position = Vector2 { -halfWidth, halfHeight }; + vertices[2].position = Vector2 { halfWidth, halfHeight }; + vertices[3].position = Vector2 { -halfWidth, -halfHeight }; + vertices[4].position = Vector2 { halfWidth, -halfHeight }; + vertices[5].position = Vector2 { halfWidth, halfHeight }; + + for (int32 i = 0; i < 6; i++) { + vertices[i].color = color; + } + + originalPoints[0] = vertices[0].position; + originalPoints[1] = vertices[1].position; + originalPoints[2] = vertices[2].position; + originalPoints[3] = vertices[4].position; + + shape.load(vertices, 6, renderer); + body.reset(); + + body.momentOfInertia = (width * width + height * height) * (body.mass / 12.f); + } + + void update(float32 dtSeconds) { + body.update(dtSeconds); + shape.model = Mat4x4().translateByVec2(body.position).rotate2D(body.rotation); + + // Note: This helps us check if the cursor is within the bounds of the + // rectangle later on. + for (int idx = 0; idx < 4; idx++) { + transformedPoints[idx] = shape.model * originalPoints[idx]; + } + } + + void render(OrthographicRenderer* renderer) { + shape.render(renderer); + } + + void unload() { + shape.unload(); + } +}; + +struct Circle { + OrthographicShape shape; + Rigidbody body; + + float32 radius = 5.f; + + void load(OrthographicRenderer* renderer, Vector4 color) { + const int32 numSegments = 36; + const float32 radiansPerSegment = (2.f * PI) / static_cast<float>(numSegments); + const int32 numVertices = numSegments * 3; + + color = color.toNormalizedColor(); + + OrthographicVertex vertices[numSegments * 3]; + for (int idx = 0; idx < numSegments; idx++) { + int vIdx = idx * 3; + + vertices[vIdx].color = color; + vertices[vIdx].position = Vector2 { radius * cosf(radiansPerSegment * idx), radius * sinf(radiansPerSegment * idx) }; + vertices[vIdx + 1].color = color; + vertices[vIdx + 1].position = Vector2 { 0.f, 0.f }; + vertices[vIdx + 2].color = color; + vertices[vIdx + 2].position = Vector2 { radius * cosf(radiansPerSegment * (idx + 1)), radius * sinf(radiansPerSegment * (idx + 1)) }; + } + + shape.load(vertices, numVertices, renderer); + body.reset(); + } + + void update(float32 dtSeconds) { + shape.model = Mat4x4().translateByVec2(body.position); + } + + void render(OrthographicRenderer* renderer) { + shape.render(renderer); + } + + void unload() { + shape.unload(); + } +}; + +EM_BOOL onPlayClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData); +EM_BOOL onStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData); +EM_BOOL onMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData); + +void load(); +void update(float32 time, void* userData); +void unload(); + +WebglContext context; +OrthographicRenderer renderer; +MainLoop mainLoop; +Rectangle rectangle; +Circle pointer; +bool isIntersectingPointer = false; + +int main() { + context.init("#gl_canvas"); + emscripten_set_click_callback("#gl_canvas_play", NULL, false, onPlayClicked); + emscripten_set_click_callback("#gl_canvas_stop", NULL, false, onStopClicked); + emscripten_set_mousemove_callback("#gl_canvas", NULL, false, onMouseMove); + + return 0; +} + +void load() { + renderer.load(&context); + + rectangle.load(&renderer, Vector4 { 55.f, 235.f, 35.f, 255.f }, 128.f, 64.f); + rectangle.body.position = Vector2 { context.width / 3.f, context.height / 3.f }; + rectangle.body.velocity = Vector2 { 100.f, 250.f }; + + pointer.load(&renderer, Vector4 { 25.f, 235.f, 235.f, 255.f }); + + mainLoop.run(update); +} + +bool isPointInRectangle(Vector2 p, Rectangle r) { + // https://math.stackexchange.com/a/190373 + Vector2 A = r.transformedPoints[0]; + Vector2 B = r.transformedPoints[1]; + Vector2 D = r.transformedPoints[3]; + + float32 amDotAb = (p - A).dot(B - A); + float32 abDotAb = (B - A).dot(B - A); + + float32 amDotAd = (p - A).dot(D - A); + float32 aDDotAd = (D - A).dot(D - A); + + return amDotAb > 0 && amDotAb < abDotAb && amDotAd > 0 && amDotAd < aDDotAd; + +} + +void update(float32 deltaTimeSeconds, void* userData) { + rectangle.update(deltaTimeSeconds); + pointer.update(deltaTimeSeconds); + + if (isPointInRectangle(pointer.body.position, rectangle)) { + if (!isIntersectingPointer) { + isIntersectingPointer = true; + Vector2 pointOfApplication = pointer.body.position - rectangle.body.position; + rectangle.body.applyForce(pointer.body.linearForce, pointOfApplication); + } + } else if (isIntersectingPointer) { + isIntersectingPointer = false; + } + + + // Check collisions with walls so we don't go out of the scene. Simply reflect here. + if (rectangle.body.position.x <= 0.f) { + rectangle.body.position.x = 0.f; + rectangle.body.velocity = rectangle.body.velocity - Vector2 { 1.f, 0.f } * (2 * (rectangle.body.velocity.dot(Vector2 { 1.f, 0.f }))); + } + if (rectangle.body.position.y <= 0.f) { + rectangle.body.position.y = 0.f; + rectangle.body.velocity = rectangle.body.velocity - Vector2 { 0.f, 1.f } * (2 * (rectangle.body.velocity.dot(Vector2 { 0.f, 1.f }))); + } + if (rectangle.body.position.x >= 800.f) { + rectangle.body.position.x = 800.f; + rectangle.body.velocity = rectangle.body.velocity - Vector2 { -1.f, 0.f } * (2 * (rectangle.body.velocity.dot(Vector2{ -1.f, 0.f }))); + } + if (rectangle.body.position.y >= 600.f) { + rectangle.body.position.y = 600.f; + rectangle.body.velocity = rectangle.body.velocity - Vector2 { 0.f, -1.f } * (2 * (rectangle.body.velocity.dot(Vector2 { 0.f, -1.f }))) ; + } + + // Renderer + renderer.render(); + rectangle.render(&renderer); + pointer.render(&renderer); +} + +void unload() { + mainLoop.stop(); + renderer.unload(); + rectangle.unload(); + pointer.unload(); +} + +// +// Interactions with DOM handled below +// +EM_BOOL onPlayClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) { + printf("Play clicked\n"); + + load(); + return true; +} + +EM_BOOL onStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) { + printf("Stop clicked\n"); + unload(); + return true; +} + +EM_BOOL onMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) { + if (!mainLoop.isRunning) { + 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.body.position.x = static_cast<float32>(mouseEvent->targetX); + pointer.body.position.y = static_cast<float32>(600.f - mouseEvent->targetY); + + return true; +} |