///
///
///
///
///
///
///
///
(function() {
// Define Constants
const CIRCLE_RADIUS = 16;
const GRAVITY = 20.0;
const COF_OF_RESTITUITION = 0.75;
const TORQUE_MULTIPLIER = 100.0; // TODO: This may be unncessary
var programContext,
circleObject,
lineObjectList,
programInfo,
exitRequestFunc;
function main() {
programContext = getContext('#circle_line_collision');
if (programContext.gl === null) {
console.error('Unable to initialize WebGL. Your browser or machine may not support it.');
return;
}
programContext.gl.clearColor(0.1, 0.15, 0.2, 1.0);
programContext.gl.clear(programContext.gl.COLOR_BUFFER_BIT);
programContext.playButton.on('click', run);
}
function run() {
console.log('Running Circle-Line Collisions');
programContext.load().then(function(pProgramInfo) {
programInfo = pProgramInfo;
circleObject = circle(programContext.gl, CIRCLE_RADIUS, 30, [
{ x: 1, y: 0, z: 0, w: 1 },
{ x: 0, y: 1, z: 0, w: 1 },
{ x: 0, y: 0, z: 1, w: 1 }
], vec2(programContext.width * (3.0 / 4.0), programContext.height / 2.0 + 100));
circleObject.velocity = vec2(0, -50);
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));
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));
lineObjectList.push(line2({ x: 100, y: 0 }, { x: 100, y: programContext.height }, programContext.gl,
{ x: 0, y: 1, z: 0, w: 1 }, 2.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));
exitRequestFunc = requestUpdateLoop(update, cleanup);
programContext.stopButton.on('click', reset);
});
}
function update(pDeltaTimeSeconds) {
pDeltaTimeSeconds = pDeltaTimeSeconds;
updateCircle(circleObject, pDeltaTimeSeconds);
collision(pDeltaTimeSeconds);
render();
}
function updateCircle(pCircle, pDeltaTimeSeconds) {
applyForce(pCircle, vec2(0, -1.0 * (pCircle.mass * GRAVITY)));
const lCurrentAcceleration = scaleVec2(pCircle.force, 1.0 / pCircle.mass);
pCircle.prevVelocity = pCircle.velocity;
pCircle.velocity = addVec2(pCircle.velocity, scaleVec2(lCurrentAcceleration, pDeltaTimeSeconds));
pCircle.prevPos = { ...pCircle.position };
pCircle.position = addVec2(pCircle.position, scaleVec2(pCircle.velocity, pDeltaTimeSeconds));
pCircle.force = vec2();
const lMomentOfInertia = getCircleMomentOfInertia(pCircle);
const lAngularAcceleration = pCircle.torque / lMomentOfInertia;
pCircle.rotationVelocity += lAngularAcceleration * pDeltaTimeSeconds;
pCircle.rotationRadians += pCircle.rotationVelocity * pDeltaTimeSeconds;
pCircle.torque = 0;
pCircle.model = rotateMatrix2d(translateMatrix(mat4(), pCircle.position.x, pCircle.position.y, 0), pCircle.rotationRadians);
}
function collision(pDeltaTimeSeconds) {
lineObjectList.forEach(function(lineObject) {
if (!lineCircleCollision2(circleObject, lineObject)) {
return;
}
var lSubdividedDeltaTime = pDeltaTimeSeconds,
lSubdividedCircle = undefined;
do {
lSubdividedCircle = JSON.parse(JSON.stringify(circleObject));
lSubdividedCircle.position = {...circleObject.prevPos};
lSubdividedCircle.velocity = {...circleObject.prevVelocity};
lSubdividedDeltaTime = lSubdividedDeltaTime / 2.0;
updateCircle(lSubdividedCircle, lSubdividedDeltaTime);
if (lSubdividedDeltaTime === 0) {
console.error('This should NOT be happening');
break;
}
} while (lineCircleCollision2(lSubdividedCircle, lineObject))
const lIntersectionResult = getLineCircleCollison2Data(lSubdividedCircle, lineObject),
lRelativeVelocity = lIntersectionResult.relativeVelocity,
lCollisionNormal = lIntersectionResult.collisionNormal,
lFirstPerp = getPerp2(lIntersectionResult.firstPointOfApplication),
lSecondPerp = getPerp2(lIntersectionResult.secondPointOfApplication);
const lNumerator = dot2(scaleVec2(lRelativeVelocity, -(1.0 + COF_OF_RESTITUITION)), lCollisionNormal);
const lLinearDenomPart = dot2(lCollisionNormal, (scaleVec2(lCollisionNormal, 1 / circleObject.mass)));
const lRotationalDenomPart = (Math.pow(dot2(lFirstPerp, lCollisionNormal), 2) / getCircleMomentOfInertia(circleObject));
const lImpulseMagnitude = lNumerator / (lLinearDenomPart + lRotationalDenomPart);
circleObject.position = lSubdividedCircle.position;
circleObject.velocity = addVec2(lSubdividedCircle.velocity, scaleVec2(lCollisionNormal, lImpulseMagnitude / circleObject.mass));
circleObject.rotationVelocity = lSubdividedCircle.rotationVelocity
+ dot2(lFirstPerp, scaleVec2(lCollisionNormal, lImpulseMagnitude)) / getCircleMomentOfInertia(circleObject);
updateCircle(circleObject, pDeltaTimeSeconds - lSubdividedDeltaTime);
return;
})
}
function applyForce(pCircle, pForceVector, pPointOfApplication) {
if (pPointOfApplication !== undefined) {
const lOriginToPointOfApp = subVec2(vec2(), pPointOfApplication),
lPerpVec = vec2(-lOriginToPointOfApp.y, lOriginToPointOfApp.x);
pCircle.torque += TORQUE_MULTIPLIER * dot2(lPerpVec, pForceVector);
}
pCircle.force = addVec2(pCircle.force, pForceVector);
}
function render() {
programContext.gl.clearColor(0.1, 0.15, 0.2, 1.0);
programContext.gl.clearDepth(1.0);
programContext.gl.enable(programContext.gl.DEPTH_TEST);
programContext.gl.depthFunc(programContext.gl.LEQUAL);
programContext.gl.clear(programContext.gl.COLOR_BUFFER_BIT | programContext.gl.DEPTH_BUFFER_BIT);
programContext.gl.useProgram(programInfo.program);
programContext.gl.uniformMatrix4fv(programInfo.uniformLocations.projection, false, programContext.perspective);
renderCircle(programContext.gl, programInfo, circleObject);
lineObjectList.forEach(function(lineObject) {
renderLine2(programContext.gl, programInfo, lineObject);
});
}
function cleanup() {
programContext.gl.deleteBuffer(circleObject.buffer);
lineObjectList.forEach(function(lineObject) {
programContext.gl.deleteBuffer(lineObject.buffer);
});
programContext.gl.deleteProgram(programInfo.program);
programContext.gl.clearColor(0.1, 0.15, 0.2, 1.0);
programContext.gl.clear(programContext.gl.COLOR_BUFFER_BIT);
}
function reset() {
exitRequestFunc();
programContext.reset();
}
$(document).ready(main);
})()