summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--frontend/2d/_collisions/circle_line.js3
-rw-r--r--frontend/2d/_collisions/rectangle_line.js105
-rw-r--r--frontend/_shared/math/line2.js10
-rw-r--r--frontend/_shared/math/mat4.js20
-rw-r--r--frontend/_shared/math/rectangle.js14
-rw-r--r--frontend/_shared/math/vec2.js8
-rw-r--r--frontend/index.css26
7 files changed, 162 insertions, 24 deletions
diff --git a/frontend/2d/_collisions/circle_line.js b/frontend/2d/_collisions/circle_line.js
index e5898f0..0736e2c 100644
--- a/frontend/2d/_collisions/circle_line.js
+++ b/frontend/2d/_collisions/circle_line.js
@@ -125,7 +125,8 @@
circleObject.position = lSubdividedCircle.position;
circleObject.velocity = addVec2(lSubdividedCircle.velocity, scaleVec2(lCollisionNormal, lImpulseMagnitude / circleObject.mass));
- circleObject.rotationVelocity = lSubdividedCircle.rotationVelocity + dot2(lFirstPerp, scaleVec2(lCollisionNormal, lImpulseMagnitude));
+ circleObject.rotationVelocity = lSubdividedCircle.rotationVelocity
+ + dot2(lFirstPerp, scaleVec2(lCollisionNormal, lImpulseMagnitude)) / getCircleMomentOfInertia(circleObject);
updateCircle(circleObject, pDeltaTimeSeconds - lSubdividedDeltaTime);
diff --git a/frontend/2d/_collisions/rectangle_line.js b/frontend/2d/_collisions/rectangle_line.js
index ac73f71..dec5108 100644
--- a/frontend/2d/_collisions/rectangle_line.js
+++ b/frontend/2d/_collisions/rectangle_line.js
@@ -34,7 +34,8 @@
rectangleObject = rectangle(programContext.gl, {
width: 50,
- height: 25,
+ height: 50,
+ mass: 1,
color: { x: 0.3, y: 0.5, z: 0.1, w: 0.7 },
position: vec2(programContext.width / 2.0 - 100, programContext.height / 2.0 + 100)
});
@@ -43,16 +44,16 @@
lineObjectList = [];
lineObjectList.push(line2({ x: 100, y: 100 }, { x: programContext.width - 100, y: 200 }, programContext.gl,
- { x: 1, y: 0, z: 0, w: 1 }, 2.0));
+ { x: 1, y: 0, z: 0, w: 1 }, 10000000.0));
lineObjectList.push(line2({ x: 100, y: 200 }, { x: programContext.width - 100, y: 100 }, programContext.gl,
- { x: 1, y: 1, z: 0, w: 1 }, 2.0));
+ { x: 1, y: 1, z: 0, w: 1 }, 10000000.0));
lineObjectList.push(line2({ x: 100, y: 0 }, { x: 100, y: programContext.height }, programContext.gl,
- { x: 0, y: 1, z: 0, w: 1 }, 2.0));
+ { x: 0, y: 1, z: 0, w: 1 }, 10000000.0));
lineObjectList.push(line2({ x: programContext.width - 100, y: 0 }, { x: programContext.width - 100, y: programContext.height }, programContext.gl,
- { x: 0, y: 1, z: 0, w: 1 }, 2.0));
+ { x: 0, y: 1, z: 0, w: 1 }, 10000000.0));
exitRequestFunc = requestUpdateLoop(update, cleanup);
@@ -68,7 +69,101 @@
}
function collision(pDeltaTimeSeconds) {
+ for (var lineIdx = 0; lineIdx < lineObjectList.length; lineIdx++) {
+ var lLine = lineObjectList[lineIdx];
+
+ if (areIntersecting(rectangleObject, lLine, pDeltaTimeSeconds)) {
+ break;
+ }
+ }
+ }
+
+ function doesPointIntersect(pPoint, pLine) {
+ const EPSILON = 0.98;
+ return distanceFromPoint2ToLine2(pPoint, pLine) <= EPSILON;
+ }
+
+ function getIntersectionInformation(pRectangle, pCollisionPoint, pLine) {
+ var lCollisionNormal = pLine.normal,
+ lRectCollisionPoint_WorldCoords = multMat4ByVec2(pRectangle.model, pCollisionPoint),
+ lRectPosition = pRectangle.position,
+ lTrueRectCollisionPoint = normalize2(subVec2(lRectPosition, lRectCollisionPoint_WorldCoords));
+
+ console.log(lTrueRectCollisionPoint);
+
+ return {
+ relativeVelocity: subVec2(pRectangle.velocity, pLine.velocity),
+ collisionNormal: lCollisionNormal,
+ rectangleCollisionPoint: lTrueRectCollisionPoint
+ }
+ }
+
+ function areIntersecting(pRectangle, pLine, pDeltaTimeSeconds) {
+ var lCollisionPoint = undefined,
+ lCheckCollision = function(pRectangle) {
+ var lLowerLeft = multMat4ByVec2(pRectangle.model, vec2(-pRectangle.width / 2.0, -pRectangle.height / 2.0)),
+ lUpperLeft = multMat4ByVec2(pRectangle.model, vec2(-pRectangle.width / 2.0, pRectangle.height / 2.0)),
+ lUpperRight = multMat4ByVec2(pRectangle.model, vec2(pRectangle.width / 2.0, pRectangle.height / 2.0)),
+ lLowerRight = multMat4ByVec2(pRectangle.model, vec2(pRectangle.width / 2.0, -pRectangle.height / 2.0));
+
+ if (doesPointIntersect(lLowerLeft, pLine)) {
+ console.log('Lwer left');
+ lCollisionPoint = vec2(-pRectangle.width / 2.0, -pRectangle.height / 2.0);
+ return true;
+ } else if (doesPointIntersect(lUpperLeft, pLine)) {
+ console.log('Upper left');
+ lCollisionPoint = vec2(-pRectangle.width / 2.0, pRectangle.height / 2.0);
+ return true;
+ } else if (doesPointIntersect(lUpperRight, pLine)) {
+ console.log('Upepr right');
+ lCollisionPoint = vec2(pRectangle.width / 2.0, pRectangle.height / 2.0);
+ return true;
+ } else if (doesPointIntersect(lLowerRight, pLine)) {
+ console.log('Lower right');
+ lCollisionPoint = vec2(pRectangle.width / 2.0, -pRectangle.height / 2.0);
+ return true;
+ }
+
+ return false;
+ };
+
+ if (!lCheckCollision(pRectangle)) {
+ return;
+ }
+
+ // Subdivide until we find the exact moment where we intersected
+ var lSubdividedDeltaTime = pDeltaTimeSeconds,
+ lSubRectangle = undefined;
+ do {
+ lSubRectangle = JSON.parse(JSON.stringify(pRectangle));
+ lSubRectangle.position = {...pRectangle.prevPos};
+ lSubRectangle.velocity = {...pRectangle.prevVelocity};
+ lSubRectangle.getMomentOfInertia = pRectangle.getMomentOfInertia;
+ lSubdividedDeltaTime = lSubdividedDeltaTime / 2.0;
+ updateRigidBody2(lSubRectangle, lSubdividedDeltaTime);
+ if (lSubdividedDeltaTime === 0) {
+ console.error('This should NOT be happening');
+ break;
+ }
+ } while (lCheckCollision(lSubRectangle));
+ var lIntersectionResult = getIntersectionInformation(lSubRectangle, lCollisionPoint, pLine),
+ lRelativeVelocity = lIntersectionResult.relativeVelocity,
+ lCollisionNormal = lIntersectionResult.collisionNormal,
+ lRectPerp = getPerp2(lIntersectionResult.rectangleCollisionPoint);
+
+ const lNumerator = dot2(scaleVec2(lRelativeVelocity, -(1.0 + 1.0)), lCollisionNormal);
+ const lLinearDenomPart = dot2(lCollisionNormal, (scaleVec2(lCollisionNormal, 1.0 / pRectangle.mass)));
+ const lRotationalDenomPart = (Math.pow(dot2(lRectPerp, lCollisionNormal), 2) / pRectangle.getMomentOfInertia());
+
+ const lImpulseMagnitude = lNumerator / (lLinearDenomPart + lRotationalDenomPart);
+
+ pRectangle.position = lSubRectangle.position;
+ pRectangle.velocity = addVec2(lSubRectangle.velocity, scaleVec2(lCollisionNormal, lImpulseMagnitude / pRectangle.mass));
+ pRectangle.rotationVelocity = lSubRectangle.rotationVelocity + dot2(lRectPerp, scaleVec2(lCollisionNormal, lImpulseMagnitude)) / pRectangle.getMomentOfInertia();
+
+ updateRigidBody2(pRectangle, pDeltaTimeSeconds - lSubdividedDeltaTime);
+ return true;
}
function render() {
diff --git a/frontend/_shared/math/line2.js b/frontend/_shared/math/line2.js
index a9e72be..8b30c1c 100644
--- a/frontend/_shared/math/line2.js
+++ b/frontend/_shared/math/line2.js
@@ -32,7 +32,8 @@ function line2(pStart, pEnd, pGl, pColor, pMass) {
length: length2(lDiffVector),
mass: pMass,
direction: normalize2(lDiffVector),
- velocity: vec2(0, 0)
+ velocity: vec2(0, 0),
+ position: vec2()
};
}
@@ -40,6 +41,13 @@ function getLine2MomentOfInertia(pLine) {
return (1.0 / 12.0) * pLine.mass * Math.pow(pLine.length, 2);
}
+function getLine2MidPoint(pLine) {
+ return {
+ x: (pLine.end.x + pLine.start.x) / 2.0,
+ y: (pLine.end.y + pLine.start.y) / 2.0
+ }
+}
+
function renderLine2(pGl, pProgramInfo, pLine) {
pGl.uniformMatrix4fv(pProgramInfo.uniformLocations.model, false, mat4()); // Model on a line is always default matrix
pGl.bindBuffer(pGl.ARRAY_BUFFER, pLine.buffer);
diff --git a/frontend/_shared/math/mat4.js b/frontend/_shared/math/mat4.js
index 6ab29e2..d31a20e 100644
--- a/frontend/_shared/math/mat4.js
+++ b/frontend/_shared/math/mat4.js
@@ -40,4 +40,24 @@ function scaleMatrix(m, x, y, z) {
m[5] = m[5] * y;
m[10] = m[10] * z;
return m;
+}
+
+function multMat4ByVec2(matrix, vec) {
+ var lInnerVec = {...vec};
+ lInnerVec.z = 0.0;
+ lInnerVec.w = 1.0;
+
+ return {
+ x: lInnerVec.x * matrix[0] + lInnerVec.y * matrix[4] + lInnerVec.z * matrix[8] + lInnerVec.w * matrix[12],
+ y: lInnerVec.x * matrix[1] + lInnerVec.y * matrix[5] + lInnerVec.z * matrix[9] + lInnerVec.w * matrix[13]
+ };
+}
+
+function multMat4ByVec4(matrix, vec) {
+ return {
+ x: vec.x * matrix[0] + vec.y * matrix[4] + vec.z * matrix[8] + vec.w * matrix[12],
+ y: vec.x * matrix[1] + vec.y * matrix[5] + vec.z * matrix[9] + vec.w * matrix[13],
+ z: vec.x * matrix[2] + vec.y * matrix[6] + vec.z * matrix[10] + vec.w * matrix[14],
+ w: vec.x * matrix[3] + vec.y * matrix[7] + vec.z * matrix[11] + vec.w * matrix[15]
+ };
} \ No newline at end of file
diff --git a/frontend/_shared/math/rectangle.js b/frontend/_shared/math/rectangle.js
index c24fa12..012c460 100644
--- a/frontend/_shared/math/rectangle.js
+++ b/frontend/_shared/math/rectangle.js
@@ -7,19 +7,19 @@ function rectangle(pGl, pData) {
pGl.bindBuffer(pGl.ARRAY_BUFFER, lBuffer);
var lBufferedData = [
- 0, 0, lColor.x, lColor.y, lColor.z, lColor.w,
- 0, pData.height, lColor.x, lColor.y, lColor.z, lColor.w,
- pData.width, pData.height, lColor.x, lColor.y, lColor.z, lColor.w,
- pData.width, pData.height, lColor.x, lColor.y, lColor.z, lColor.w,
- pData.width, 0, lColor.x, lColor.y, lColor.z, lColor.w,
- 0, 0, lColor.x, lColor.y, lColor.z, lColor.w
+ -pData.width / 2.0, -pData.height / 2.0, lColor.x, lColor.y, lColor.z, lColor.w,
+ -pData.width / 2.0, pData.height / 2.0, lColor.x, lColor.y, lColor.z, lColor.w,
+ pData.width / 2.0, pData.height / 2.0, lColor.x, lColor.y, lColor.z, lColor.w,
+ pData.width / 2.0, pData.height /2.0, lColor.x, lColor.y, lColor.z, lColor.w,
+ pData.width / 2.0, -pData.height / 2.0, lColor.x, lColor.y, lColor.z, lColor.w,
+ -pData.width / 2.0, -pData.height / 2.0, lColor.x, lColor.y, lColor.z, lColor.w
];
pGl.bufferData(pGl.ARRAY_BUFFER, new Float32Array(lBufferedData), pGl.STATIC_DRAW)
pGl.bindBuffer(pGl.ARRAY_BUFFER, undefined);
pData.getMomentOfInertia = function() {
- return Math.pow(pData.width * pData.height, 3.0) / 12.0;
+ return (1.0 / 12.0) * pData.mass * (pData.height * pData.height + pData.width * pData.width);
};
return makeRigidBody2({
diff --git a/frontend/_shared/math/vec2.js b/frontend/_shared/math/vec2.js
index cff38ce..11e71cd 100644
--- a/frontend/_shared/math/vec2.js
+++ b/frontend/_shared/math/vec2.js
@@ -53,4 +53,12 @@ function negate2(v) {
x: -v.x,
y: -v.y
};
+}
+
+// Algorithm plucked from: https://matthew-brett.github.io/teaching/rotation_2d.html
+function rotateAboutOrigin2(v, angle) {
+ return {
+ x: v.x * Math.cos(angle) - v.y * Math.sin(angle),
+ y: v.x * Math.sin(angle) + v.y * Math.cos(angle),
+ };
} \ No newline at end of file
diff --git a/frontend/index.css b/frontend/index.css
index 00ea6e9..5f9619c 100644
--- a/frontend/index.css
+++ b/frontend/index.css
@@ -1,19 +1,23 @@
body {
font-size: 16px;
- font-family: "Open Sans", sans-serif;
+ font-family: "Helvetica", sans-serif;
+ line-height: 1.3rem;
width: 100%;
height: 100vh;
- display: flex;
- flex-direction: column;
- align-items: center;
margin: 0rem;
padding: 0rem;
+ overflow-x: auto;
+ overflow-y: auto;
}
header {
+ background-color: lemonchiffon;
padding-top: 1rem;
+ padding-bottom: 1rem;
+ font-size: 20px;
+ margin: auto;
width: 1260px;
- flex: 0 1 auto;
+ max-width: 1260px;
text-align: center;
}
@@ -27,10 +31,11 @@ main {
display: flex;
flex-direction: row;
color: #1a1a1a;
- width: 1200px;
+ width: 1260px;
+ margin: auto;
+ max-width: 1260px;
background-color: white;
flex: 1 1 100%;
- height: 100%;
margin-bottom: 1rem;
overflow-y: hidden;
}
@@ -38,13 +43,15 @@ main {
section {
min-width: 74%;
width: 74%;
- overflow-y: auto;
+ overflow-y: hidden;
}
/*
Navigation bar
*/
nav {
+ padding-top: 1rem;
+ position: sticky;
width: 20%;
min-width: 20%;
max-width: 20%;
@@ -55,7 +62,6 @@ nav {
text-align: left;
font-size: 1rem;
user-select: none;
- border-right: 1px solid black;;
}
.outer-tree {
@@ -201,7 +207,7 @@ article .opengl_canvas_container .play_button {
height: 128px;
position: absolute;
top: calc(50% - 56px);
- left: calc(50% - 184px);
+ left: calc(50% - 214px);
border: 1px solid white;
color: white;
background-color: transparent;