DOCTYPE html html lang en head meta charset UTF 8 meta name viewport content width device width initial scale 1 0 title Rotating Box with Springs title style canvas border 1px solid black background color f0f0f0 style head body div id log div canvas id canvas width 800 height 400 canvas script const canvas document getElementById canvas const ctx canvas getContext 2d Box parameters const box x 50 y 200 width 50 height 30 linearVelocityX 3 linearVelocityY 0 gravity 0 5 bounce 0 5 angle 0 Rotation angle angularVelocity 0 torque 0 maxAngle 1 0 Maximum rotation angle radians springs length 20 restLength 20 k 0 1 offsetX 25 offsetY 15 Front wheel relative to box center length 20 restLength 20 k 0 1 offsetX 25 offsetY 15 Back wheel relative to box center Ground segments const groundSegments startX 0 startY 300 endX 100 endY 250 startX 100 startY 250 endX 200 endY 300 startX 200 startY 300 endX 300 endY 200 startX 300 startY 200 endX 400 endY 250 startX 400 startY 250 endX 500 endY 300 startX 500 startY 300 endX 600 endY 280 startX 600 startY 280 endX 700 endY 200 startX 700 startY 200 endX 800 endY 250 function update Move box forward using linear velocity box x box linearVelocityX const frontWheelPos getWheelPosition box springs 0 const backWheelPos getWheelPosition box springs 1 Get the ground penetration depth for the front and back wheels const frontPenetration getGroundY frontWheelPos x frontWheelPos y 15 const backPenetration getGroundY backWheelPos x backWheelPos y 15 let kd 0 2 Calculate the spring force for the front wheel based on penetration const frontSpringForce frontPenetration 0 kd frontPenetration 0 Calculate the spring force for the back wheel based on penetration const backSpringForce backPenetration 0 kd backPenetration 0 Calculate torque based on spring forces const frontTorque frontSpringForce box springs 0 offsetX const backTorque backSpringForce box springs 1 offsetX Total torque applied to the box box torque frontTorque backTorque 0 0001 Update angular velocity based on torque box angularVelocity box torque box angle box angularVelocity Limit the angle to maxAngle if box angle box maxAngle box angle box maxAngle box angularVelocity 0 Stop further rotation else if box angle box maxAngle box angle box maxAngle box angularVelocity 0 Stop further rotation Update vertical velocity based on gravity and spring forces box linearVelocityY box gravity frontSpringForce backSpringForce box linearVelocityY 0 8 box linearVelocityX 0 8 Update vertical position box y box linearVelocityY Reset position if out of canvas if box x canvas width box x 0 box y 200 Reset to initial height box angle 0 Reset rotation box angularVelocity 0 Reset angular velocity box linearVelocityY 0 Reset vertical velocity function getWheelPosition spring const centerX box x box width 2 const centerY box y box height 2 const cos Math cos box angle const sin Math sin box angle const rotatedX centerX spring offsetX cos spring offsetY sin const rotatedY centerY spring offsetX sin spring offsetY cos return x rotatedX y rotatedY function getGroundY x y for let segment of groundSegments if x segment startX x segment endX const slope segment endY segment startY 0 001 segment endX segment startX const groundY segment startY slope x segment startX const boxBottomY y box height Bottom of the box return boxBottomY groundY Return penetration depth return 0 0001 Default to no penetration function draw ctx clearRect 0 0 canvas width canvas height Draw ground ctx strokeStyle black for let segment of groundSegments ctx beginPath ctx moveTo segment startX segment startY ctx lineTo segment endX segment endY ctx stroke const centerX box x box width 2 const centerY box y box height 2 Save current state ctx save Translate to the center of the box and rotate ctx translate centerX centerY ctx rotate box angle Draw box ctx fillStyle blue ctx fillRect box width 2 box height 2 box width box height ctx drawImage img width 2 1 height 2 1 width height Restore state ctx restore Draw penetration depth lines const frontWheelPos getWheelPosition box springs 0 const backWheelPos getWheelPosition box springs 1 const frontPenetration getGroundY frontWheelPos x frontWheelPos y const backPenetration getGroundY backWheelPos x backWheelPos y ctx beginPath ctx arc centerX centerY 3 0 2 Math PI ctx stroke ctx beginPath ctx arc frontWheelPos x frontWheelPos y 15 0 2 Math PI ctx stroke ctx beginPath ctx arc backWheelPos x backWheelPos y 15 0 2 Math PI ctx stroke ctx strokeStyle red if frontPenetration 0 ctx beginPath ctx moveTo frontWheelPos x frontWheelPos y Bottom of the box ctx lineTo frontWheelPos x frontWheelPos y frontPenetration Up to penetration depth ctx stroke if backPenetration 0 ctx beginPath ctx moveTo backWheelPos x backWheelPos y Bottom of the box ctx lineTo backWheelPos x backWheelPos y backPenetration Up to penetration depth ctx stroke let cp getGroundY cursorpos 0 cursorpos 1 ctx beginPath ctx moveTo cursorpos 0 cursorpos 1 Bottom of the box ctx lineTo cursorpos 0 cursorpos 1 cp Up to penetration depth ctx stroke const example document getElementById canvas var cursorpos 0 0 example onmousemove function e const x e pageX e currentTarget offsetLeft const y e pageY e currentTarget offsetTop cursorpos x y onkeydown box linearVelocityX 10 function loop update draw requestAnimationFrame loop loop script body html
const centerX box x box width 2 const centerY box y box height 2 const cos Math cos box angle const sin Math sin box angle const rotatedX centerX spring offsetX cos spring offsetY sin const rotatedY centerY spring offsetX sin spring offsetY cos return x rotatedX y rotatedY function getGroundY x y for let segment of groundSegments if x segment startX x segment endX const slope segment endY segment startY 0 001 segment endX segment startX const groundY segment startY slope x segment startX const boxBottomY y box height Bottom of the box return boxBottomY groundY Return penetration depth return 0 0001 Default to no penetration function draw ctx clearRect 0 0 canvas width canvas height Draw ground ctx strokeStyle black for let segment of groundSegments ctx beginPath ctx moveTo segment startX segment startY ctx lineTo segment endX segment endY ctx stroke const centerX box x box width 2 const centerY box y box height 2 Save current state ctx save Translate to the center of the box and rotate ctx translate centerX centerY ctx rotate box angle Draw box ctx fillStyle blue ctx fillRect box width 2 box height 2 box width box height ctx drawImage img width 2 1 height 2 1 width height Restore state ctx restore Draw penetration depth lines const frontWheelPos getWheelPosition box springs 0 const backWheelPos getWheelPosition box springs 1 const frontPenetration getGroundY frontWheelPos x frontWheelPos y const backPenetration getGroundY backWheelPos x backWheelPos y ctx beginPath ctx arc centerX centerY 3 0 2 Math PI ctx stroke ctx beginPath ctx arc frontWheelPos x frontWheelPos y 15 0 2 Math PI ctx stroke ctx beginPath ctx arc backWheelPos x backWheelPos y 15 0 2 Math PI ctx stroke ctx strokeStyle red if frontPenetration 0 ctx beginPath ctx moveTo frontWheelPos x frontWheelPos y Bottom of the box ctx lineTo frontWheelPos x frontWheelPos y frontPenetration Up to penetration depth ctx stroke if backPenetration 0 ctx beginPath ctx moveTo backWheelPos x backWheelPos y Bottom of the box ctx lineTo backWheelPos x backWheelPos y backPenetration Up to penetration depth ctx stroke let cp getGroundY cursorpos 0 cursorpos 1 ctx beginPath ctx moveTo cursorpos 0 cursorpos 1 Bottom of the box ctx lineTo cursorpos 0 cursorpos 1 cp Up to penetration depth ctx stroke const example document getElementById canvas var cursorpos 0 0 example onmousemove function e const x e pageX e currentTarget offsetLeft const y e pageY e currentTarget offsetTop cursorpos x y onkeydown box linearVelocityX 10 function loop update draw requestAnimationFrame loop loop script body html