topical media & game development
student-canvas-CD04.txt / txt
<html>
<head>
<script type="text/javascript" src="student-canvas-article.js"></script>
<script type="text/javascript">
var env;
var ctx;
var shapeA, shapeB;
var skeletonA, skeletonB;
var collision = 0;
var dt = 0.05;
var width, height;
var tempVector;
var selectPointmass;
var zeroForce = new Vector(0.0, 0.0);
var keyboardForce = new Vector(0.0, 0.0);
var gravity = new Vector(0.0, 1.0);
var savedMouseCoords = null;
var switchedA = 0;
var switchedB = 0;
var firefox = 0;
var collissionAdjustment = -0.04;
function dotproduct(a,b) {
var n = a[0] * b[0] + a[1] * b[1];
return n;
}
function timeout() {
var v, w, x, y, z;
var a, b, c;
var axis = new Array();
var point = new Array();
var collisionA = 1;
var collisionB = 1;
var insideEdge = 0;
var edgeReaction = 0;
var distanceA = 0;
var distanceB = 0;
var distanceShortest = 1;
if(selectPointmass != null && savedMouseCoords != null)
selectPointmass.setPos(savedMouseCoords.x, savedMouseCoords.y);
// === Apply forces on the shapes ===
for(x in shapeA) {
shapeA[x].addForce(gravity);
shapeA[x].move(dt);
shapeA[x].setForce(zeroForce);
if(env.collision(shapeA[x].getPos(), shapeA[x].getPrevPos()) == true) {
shapeA[x].setFriction(2);
} else {
shapeA[x].setFriction(0.01);
}
}
for(x in shapeB) {
shapeB[x].addForce(gravity);
shapeB[x].move(dt);
shapeB[x].setForce(zeroForce);
if(env.collision(shapeB[x].getPos(), shapeB[x].getPrevPos()) == true) {
shapeB[x].setFriction(0.9999);
} else {
shapeB[x].setFriction(0.01);
}
}
for(x in skeletonA) {
skeletonA[x].sc();
}
for(x in skeletonB) {
skeletonB[x].sc();
}
ctx.clearRect(0, 0, width, height);
env.draw(ctx, width);
// === Draw shapes ===
for(x in skeletonA) {
skeletonA[x].draw(ctx, width);
}
for(x in skeletonB) {
skeletonB[x].draw(ctx, width);
}
for(x in shapeA) {
shapeA[x].draw(ctx, width);
}
for(x in shapeB) {
shapeB[x].draw(ctx, width);
}
// === Determine Collission Detection ===
for(x in shapeA) {
z = parseInt(x) + 1;
if(z > shapeA.length - 1) {
z = 0;
}
axis[1] = shapeA[z].getXPos() - shapeA[x].getXPos();
axis[0] = -1 * (shapeA[z].getYPos() - shapeA[x].getYPos());
for(y in shapeB) {
point[0] = shapeB[y].getXPos() - shapeA[x].getXPos();
point[1] = shapeB[y].getYPos() - shapeA[x].getYPos();
if(dotproduct(axis, point) < 0) {
insideEdge = 1;
}
}
if(insideEdge == 0) {
collisionA = 0;
break;
}
insideEdge = 0;
}
for(x in shapeB) {
z = parseInt(x) + 1;
if(z > shapeB.length - 1) {
z = 0;
}
axis[1] = shapeB[z].getXPos() - shapeB[x].getXPos();
axis[0] = -1 * (shapeB[z].getYPos() - shapeB[x].getYPos());
for(y in shapeA) {
point[0] = shapeA[y].getXPos() - shapeB[x].getXPos();
point[1] = shapeA[y].getYPos() - shapeB[x].getYPos();
if(dotproduct(axis, point) < 0) {
insideEdge = 1;
}
}
if(insideEdge == 0) {
collisionB = 0;
break;
}
insideEdge = 0;
}
// === Determine whether the shapes are inside-out or not ===
a = Math.sqrt((shapeA[2].getXPos() - shapeA[0].getXPos()) * (shapeA[2].getXPos() - shapeA[0].getXPos()) + (shapeA[2].getYPos() - shapeA[0].getYPos()) * (shapeA[2].getYPos() - shapeA[0].getYPos()));
b = Math.sqrt((shapeA[0].getXPos() - shapeA[1].getXPos()) * (shapeA[0].getXPos() - shapeA[1].getXPos()) + (shapeA[0].getYPos() - shapeA[1].getYPos()) * (shapeA[0].getYPos() - shapeA[1].getYPos()));
c = Math.sqrt((shapeA[1].getXPos() - shapeA[2].getXPos()) * (shapeA[1].getXPos() - shapeA[2].getXPos()) + (shapeA[1].getYPos() - shapeA[2].getYPos()) * (shapeA[1].getYPos() - shapeA[2].getYPos()));
if (switchedA <= 0) {
switchedA = 0;
if(b - a - c > -0.01 || a - b - c > -0.01 || c - a - b > -0.01) {
if(b - a - c == 0 || a - b - c == 0 || c - a - b == 0) {
switchedA = 0;
} else {
switchedA = 1;
shapeA.reverse();
}
}
} else {
switchedA -= 0.5;
}
a = Math.sqrt((shapeB[2].getXPos() - shapeB[0].getXPos()) * (shapeB[2].getXPos() - shapeB[0].getXPos()) + (shapeB[2].getYPos() - shapeB[0].getYPos()) * (shapeB[2].getYPos() - shapeB[0].getYPos()));
b = Math.sqrt((shapeB[0].getXPos() - shapeB[1].getXPos()) * (shapeB[0].getXPos() - shapeB[1].getXPos()) + (shapeB[0].getYPos() - shapeB[1].getYPos()) * (shapeB[0].getYPos() - shapeB[1].getYPos()));
c = Math.sqrt((shapeB[1].getXPos() - shapeB[2].getXPos()) * (shapeB[1].getXPos() - shapeB[2].getXPos()) + (shapeB[1].getYPos() - shapeB[2].getYPos()) * (shapeB[1].getYPos() - shapeB[2].getYPos()));
if (switchedB <= 0) {
switchedB = 0;
if(b - a - c > -0.01 || a - b - c > -0.01 || c - a - b > -0.01) {
if(b - a - c == 0 || a - b - c == 0 || c - a - b == 0) {
switchedB = 0;
} else {
switchedB = 1;
shapeB.reverse();
}
}
} else {
switchedB -= 0.5;
}
// === Collission Reaction ===
if(collisionA + collisionB == 2) {
var vector1 = new Vector();
for(x in shapeA) {
for(y in shapeB) {
z = (parseInt(y) + 1) % shapeB.length;
if(shapeB[y].getPos().dist(shapeB[z].getPos()) - shapeB[y].getPos().dist(shapeA[x].getPos()) - shapeA[x].getPos().dist(shapeB[z].getPos()) > -0.01) {
//vector1 is set as the normal of the edge (shapeB[y], shapeB[z])
vector1.setX(shapeB[z].getXPos());
vector1.setY(shapeB[z].getYPos());
vector1.sub(shapeB[y].getPos());
if(shapeA[x].getPos().dist(shapeB[y].getPos()) > 0.15 && shapeA[x].getPos().dist(shapeB[z].getPos()) > 0.15) {
shapeA[x].addXPos(collissionAdjustment * vector1.getY());
shapeA[x].addYPos(-1 * collissionAdjustment * vector1.getX());
shapeA[x].setPrevPos(shapeA[x].getXPos(),shapeA[x].getYPos());
stickReaction = shapeA[x].getPos().dist(shapeB[z].getPos()) / shapeB[y].getPos().dist(shapeB[z].getPos());
shapeB[y].addXPos(-1 * stickReaction * collissionAdjustment * vector1.getY());
shapeB[y].addYPos(stickReaction * collissionAdjustment * vector1.getX());
shapeB[y].setPrevPos(shapeB[y].getXPos(),shapeB[y].getYPos());
stickReaction = shapeB[y].getPos().dist(shapeA[x].getPos()) / shapeB[y].getPos().dist(shapeB[z].getPos());
shapeB[z].addXPos(-1 * stickReaction * collissionAdjustment * vector1.getY());
shapeB[z].addYPos(stickReaction * collissionAdjustment * vector1.getX());
shapeB[z].setPrevPos(shapeB[z].getXPos(),shapeB[z].getYPos());
} else {
for(w in shapeB) {
v = (parseInt(w) + 1) % shapeB.length;
distanceA = Math.abs((shapeA[x].getXPos() - shapeB[y].getXPos()) * (shapeB[z].getYPos() - shapeB[y].getYPos()) - (shapeB[z].getXPos() - shapeB[y].getXPos()) * (shapeA[x].getYPos() - shapeB[y].getYPos())) /
Math.sqrt(Math.pow((shapeB[z].getXPos() - shapeB[y].getXPos()),2) + Math.pow((shapeB[z].getYPos() - shapeB[y].getYPos()),2));
distanceB = Math.abs((shapeA[x].getXPos() - shapeB[w].getXPos()) * (shapeB[v].getYPos() - shapeB[w].getYPos()) - (shapeB[v].getXPos() - shapeB[w].getXPos()) * (shapeA[x].getYPos() - shapeB[w].getYPos())) /
Math.sqrt(Math.pow((shapeB[v].getXPos() - shapeB[w].getXPos()),2) + Math.pow((shapeB[v].getYPos() - shapeB[w].getYPos()),2));
// if this edge is not closest to shapeA[x], do nothing
if(distanceA > distanceB) {
distanceShortest = 0;
}
// The following line takes care of a nasty bug that arises when one edge of shapeA
// think that they're on one line with shapeB[y] or shapeB[z], which happens when both triangles are aligned in a certain way.
if(dotproduct([-1 * (shapeB[z].getYPos() - shapeB[y].getYPos()),shapeB[z].getXPos() - shapeB[y].getXPos()], [shapeA[x].getXPos() - shapeB[y].getXPos(),shapeA[x].getYPos() - shapeB[y].getYPos()]) > 0) {
distanceShortest = 0;
}
}
if(distanceShortest == 1) {
shapeA[x].addXPos(collissionAdjustment * vector1.getY());
shapeA[x].addYPos(-1 * collissionAdjustment * vector1.getX());
shapeA[x].setPrevPos(shapeA[x].getXPos(),shapeA[x].getYPos());
stickReaction = shapeA[x].getPos().dist(shapeB[z].getPos()) / shapeB[y].getPos().dist(shapeB[z].getPos());
shapeB[y].addXPos(-1 * stickReaction * collissionAdjustment * vector1.getY());
shapeB[y].addYPos(stickReaction * collissionAdjustment * vector1.getX());
shapeB[y].setPrevPos(shapeB[y].getXPos(),shapeB[y].getYPos());
stickReaction = shapeB[y].getPos().dist(shapeA[x].getPos()) / shapeB[y].getPos().dist(shapeB[z].getPos());
shapeB[z].addXPos(-1 * stickReaction * collissionAdjustment * vector1.getY());
shapeB[z].addYPos(stickReaction * collissionAdjustment * vector1.getX());
shapeB[z].setPrevPos(shapeB[z].getXPos(),shapeB[z].getYPos());
}
distanceShortest = 1;
}
}
}
}
for(x in shapeB) {
for(y in shapeA) {
// z is y's successor, unless it's the last of the array
z = (parseInt(y) + 1) % shapeA.length;
if(shapeA[y].getPos().dist(shapeA[z].getPos()) - shapeA[y].getPos().dist(shapeB[x].getPos()) - shapeB[x].getPos().dist(shapeA[z].getPos()) > -0.01) {
//vector1 is set as the normal of the edge (shapeA[y], shapeA[z])
vector1.setX(shapeA[z].getXPos());
vector1.setY(shapeA[z].getYPos());
vector1.sub(shapeA[y].getPos());
if(shapeA[y].getPos().dist(shapeB[x].getPos()) > 0.15 && shapeA[z].getPos().dist(shapeB[x].getPos()) > 0.15) {
shapeB[x].addXPos(collissionAdjustment * vector1.getY());
shapeB[x].addYPos(-1 * collissionAdjustment * vector1.getX());
shapeB[x].setPrevPos(shapeB[x].getXPos(),shapeB[x].getYPos());
stickReaction = shapeA[y].getPos().dist(shapeB[x].getPos()) / shapeA[y].getPos().dist(shapeA[z].getPos());
shapeA[y].addXPos(-1 * stickReaction * collissionAdjustment * vector1.getY());
shapeA[y].addYPos(stickReaction * collissionAdjustment * vector1.getX());
shapeA[y].setPrevPos(shapeA[y].getXPos(),shapeA[y].getYPos());
stickReaction = shapeB[x].getPos().dist(shapeA[z].getPos()) / shapeA[y].getPos().dist(shapeA[z].getPos());
shapeA[z].addXPos(-1 * stickReaction * collissionAdjustment * vector1.getY());
shapeA[z].addYPos(stickReaction * collissionAdjustment * vector1.getX());
shapeA[z].setPrevPos(shapeA[z].getXPos(),shapeA[z].getYPos());
} else {
for(w in shapeA) {
v = (parseInt(w) + 1) % shapeA.length;
distanceA = Math.abs((shapeB[x].getXPos() - shapeA[y].getXPos()) * (shapeA[z].getYPos() - shapeA[y].getYPos()) - (shapeA[z].getXPos() - shapeA[y].getXPos()) * (shapeB[x].getYPos() - shapeA[y].getYPos())) /
Math.sqrt(Math.pow((shapeA[z].getXPos() - shapeA[y].getXPos()),2) + Math.pow((shapeA[z].getYPos() - shapeA[y].getYPos()),2));
distanceB = Math.abs((shapeB[x].getXPos() - shapeA[w].getXPos()) * (shapeA[v].getYPos() - shapeA[w].getYPos()) - (shapeA[v].getXPos() - shapeA[w].getXPos()) * (shapeB[x].getYPos() - shapeA[w].getYPos())) /
Math.sqrt(Math.pow((shapeA[v].getXPos() - shapeA[w].getXPos()),2) + Math.pow((shapeA[v].getYPos() - shapeA[w].getYPos()),2));
// if this edge is not closest to shapeA[x], do nothing
if(distanceA > distanceB) {
distanceShortest = 0;
}
// The following line takes care of a nasty bug that arises when one edge of shapeA
// think that they're on one line with shapeB[y] or shapeB[z], which happens when both triangles are aligned in a certain way.
if(dotproduct([-1 * (shapeA[z].getYPos() - shapeA[y].getYPos()),shapeA[z].getXPos() - shapeA[y].getXPos()], [shapeB[x].getXPos() - shapeA[y].getXPos(),shapeB[x].getYPos() - shapeA[y].getYPos()]) > 0) {
distanceShortest = 0;
}
}
if(distanceShortest == 1) {
shapeB[x].addXPos(collissionAdjustment * vector1.getY());
shapeB[x].addYPos(-1 * collissionAdjustment * vector1.getX());
shapeB[x].setPrevPos(shapeB[x].getXPos(),shapeB[x].getYPos());
stickReaction = shapeA[y].getPos().dist(shapeB[x].getPos()) / shapeA[y].getPos().dist(shapeA[z].getPos());
shapeA[y].addXPos(-1 * stickReaction * collissionAdjustment * vector1.getY());
shapeA[y].addYPos(stickReaction * collissionAdjustment * vector1.getX());
shapeA[y].setPrevPos(shapeA[y].getXPos(),shapeA[y].getYPos());
stickReaction = shapeB[x].getPos().dist(shapeA[z].getPos()) / shapeA[y].getPos().dist(shapeA[z].getPos());
shapeA[z].addXPos(-1 * stickReaction * collissionAdjustment * vector1.getY());
shapeA[z].addYPos(stickReaction * collissionAdjustment * vector1.getX());
shapeA[z].setPrevPos(shapeA[z].getXPos(),shapeA[z].getYPos());
}
distanceShortest = 1;
}
}
}
}
}
// === Display whether or not a collission has occurred on the screen ===
ctx.fillStyle = "Black";
if(firefox == 1) {
ctx.translate(10, 10);
ctx.fillStyle = "Black";
ctx.mozTextStyle = "14px Courier New";
if(collisionA + collisionB < 2) {
ctx.mozDrawText("No collision");
collision = 0;
} else {
ctx.mozDrawText("A collision");
collision = 1;
}
ctx.translate(-10, -10);
} else {
ctx.font = "14px Courier New";
if(collisionA + collisionB < 2) {
ctx.fillText("No collision", 5, 30);
collision = 0;
} else {
ctx.fillText("A collision", 5, 30);
collision = 1;
}
}
setTimeout('timeout()', 30);
}
function initCD04(aWidth, aHeight) {
var canvas = document.getElementById('CD04');
var x;
ctx = canvas.getContext('2d');
var browserName = "";
var ua = navigator.userAgent.toLowerCase();
if ( ua.indexOf( "opera" ) != -1 ) {
browserName = "opera";
} else if ( ua.indexOf( "msie" ) != -1 ) {
browserName = "msie";
} else if ( ua.indexOf( "safari" ) != -1 ) {
browserName = "safari";
} else if ( ua.indexOf( "mozilla" ) != -1 ) {
if ( ua.indexOf( "firefox" ) != -1 ) {
browserName = "firefox";
} else {
browserName = "mozilla";
}
}
if(browserName == "mozilla" || browserName == "firefox") {
firefox = 1;
} else {
firefox = 0;
}
width = aWidth;
height = aHeight;
tempVector = new Vector(0.0, 0.0);
selectPointmass = null;
env = new Environment(0.15, 0.15, 0.70, 0.70);
shapeA = new Array();
shapeB = new Array();
skeletonA = new Array();
skeletonB = new Array();
shapeA[0] = new PointMass(0.3, 0.1, 1.0);
shapeA[1] = new PointMass(0.3, 0.3, 1.0);
shapeA[2] = new PointMass(0.4, 0.2, 1.0);
shapeB[0] = new PointMass(0.5, 0.4, 1.0);
shapeB[1] = new PointMass(0.3, 0.5, 1.0);
shapeB[2] = new PointMass(0.7, 0.6, 1.0);
skeletonA[0] = new Joint(shapeA[0], shapeA[1], 1.0, 1.0);
skeletonA[1] = new Joint(shapeA[1], shapeA[2], 1.0, 1.0);
skeletonA[2] = new Joint(shapeA[2], shapeA[0], 1.0, 1.0);
skeletonB[0] = new Joint(shapeB[0], shapeB[1], 1.0, 1.0);
skeletonB[1] = new Joint(shapeB[1], shapeB[2], 1.0, 1.0);
skeletonB[2] = new Joint(shapeB[2], shapeB[0], 1.0, 1.0);
function getMouseCoords(event) {
if(event == null)
event = window.event;
if(event == null)
return null;
if(event.pageX || event.pageY)
return {x:event.pageX / width, y:event.pageY / width};
return null;
}
document.onmousedown = function(event) {
var mouseCoords;
mouseCoords = getMouseCoords(event);
savedMouseCoords = mouseCoords;
if(mouseCoords == null)
return;
tempVector.setX(mouseCoords.x);
tempVector.setY(mouseCoords.y);
for(x in shapeA) {
if(tempVector.dist(shapeA[x].getPos()) < 0.1) {
selectPointmass = shapeA[x];
}
}
for(x in shapeB) {
if(tempVector.dist(shapeB[x].getPos()) < 0.1) {
selectPointmass = shapeB[x];
}
}
}
document.onmouseup = function(event) {
selectPointmass = null;
}
document.onmousemove = function(event) {
var mouseCoords;
mouseCoords = getMouseCoords(event);
savedMouseCoords = mouseCoords;
}
timeout();
}
</script>
</head>
<body onLoad="initCD04(500, 500)">
<canvas id="CD04" width="500" height="500"></canvas>
<br>
<br>
Use mouse to move individual pointmasses.<br>
This example gives a demonstration of how you can check whether the two triangles collide with each other or not.<br>
</body>
</html>
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.