From bcb38594492aec4f1116b3fdf0e9821d4016903a Mon Sep 17 00:00:00 2001 From: Arjun Satarkar Date: Wed, 30 Oct 2024 22:27:17 -0400 Subject: Implement the physics --- src/index.js | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 src/index.js (limited to 'src/index.js') diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..1275360 --- /dev/null +++ b/src/index.js @@ -0,0 +1,94 @@ +import RAPIER from "./rapier.es.js"; + +RAPIER.init().then(() => { + const CLICK_IMPULSE_MULTIPLIER = 300_000; + const GRAVITY = { x: 0.0, y: 2000 }; + const LINEAR_DAMPING = 0.5; + const OBJ_BASE_RADIUS = 30; + const OBJ_BASE_SIZE = { x: OBJ_BASE_RADIUS * 2, y: OBJ_BASE_RADIUS * 2 }; + const OBJ_MASS = 100; + const STEP_MS = 33; + const TARGET_WIDTH_FACTOR = 0.05; + const VIEWPORT_SIZE = { + x: document.documentElement.clientWidth, + y: document.documentElement.clientHeight, + }; + const WIDTH_JUMP_FACTOR = 5; + + let world = new RAPIER.World(GRAVITY); + + const wallColliderDescs = { + x: RAPIER.ColliderDesc.cuboid(VIEWPORT_SIZE.x, 1).setRestitution(1), + y: RAPIER.ColliderDesc.cuboid(1, VIEWPORT_SIZE.y).setRestitution(1), + }; + world.createCollider(wallColliderDescs.x); + world.createCollider(wallColliderDescs.x.setTranslation(0, VIEWPORT_SIZE.y)); + world.createCollider(wallColliderDescs.y); + world.createCollider(wallColliderDescs.y.setTranslation(VIEWPORT_SIZE.x, 0)); + + let objRigidBodyDesc = RAPIER.RigidBodyDesc.dynamic() + .setTranslation(VIEWPORT_SIZE.x / 2, VIEWPORT_SIZE.y / 3) + .setLinearDamping(LINEAR_DAMPING) + .setCcdEnabled(true); + let obj = world.createRigidBody(objRigidBodyDesc); + world.createCollider( + RAPIER.ColliderDesc.ball(OBJ_BASE_RADIUS).setMass(OBJ_MASS), + obj, + ); + + const objElement = document.querySelector("div#throwable"); + const objSize = { + x: OBJ_BASE_SIZE.x, + y: OBJ_BASE_SIZE.y, + }; + let objVelocityLastFrame = null; + + let mainLoop = () => { + world.step(); + + const objPosition = obj.translation(); + objElement.style.left = `${objPosition.x}px`; + objElement.style.top = `${objPosition.y}px`; + + const objVelocity = obj.linvel(); + if (objVelocityLastFrame !== null) { + // Just delta velocity across a frame, technically + const objAcceleration = { + x: objVelocity.x - objVelocityLastFrame.x, + y: objVelocity.y - objVelocityLastFrame.y, + }; + let targetWidth = + OBJ_BASE_SIZE.x + TARGET_WIDTH_FACTOR * Math.abs(objAcceleration.y); + let targetHeight = + OBJ_BASE_SIZE.y + TARGET_WIDTH_FACTOR * Math.abs(objAcceleration.x); + + objSize.x = objSize.x + (targetWidth - objSize.x) / WIDTH_JUMP_FACTOR; + objSize.y = objSize.y + (targetHeight - objSize.y) / WIDTH_JUMP_FACTOR; + } + objVelocityLastFrame = objVelocity; + + objElement.style.width = `${objSize.x}px`; + objElement.style.height = `${objSize.y}px`; + + setTimeout(mainLoop, STEP_MS); + }; + + document.addEventListener("click", (e) => { + const clickPosition = { x: e.clientX, y: e.clientY }; + const objPosition = obj.translation(); + const direction = { + x: clickPosition.x - objPosition.x, + y: clickPosition.y - objPosition.y, + }; + const distance = Math.sqrt(direction.x ** 2 + direction.y ** 2); + obj.setLinvel({x: 0, y: 0}); + if (distance > 0) { + obj.applyImpulse({ + x: (direction.x * CLICK_IMPULSE_MULTIPLIER) / distance, + y: (direction.y * CLICK_IMPULSE_MULTIPLIER) / distance, + }); + } + }); + + mainLoop(); +}); -- cgit v1.2.3-57-g22cb