Skip to content

Instantly share code, notes, and snippets.

@darbicus
Last active December 20, 2015 08:09
Show Gist options
  • Save darbicus/6098159 to your computer and use it in GitHub Desktop.
Save darbicus/6098159 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
</body>
</html>
var Vector = (function() {
function Vector(x, y) {
this.x = x;
this.y = y;
this.prevmag = 1
};
return Vector
})();
Vector.prototype = {
toString: function() {
return "[" + this.x + "," + this.y + "]"
},
mag: function() {
return Math.sqrt((this.x * this.x) + (this.y * this.y))
},
mult: function(k) {
this.x = this.x * k;
this.y = this.y * k;
return this.toString()
},
div: function(k) {
this.x = (this.x) / k;
this.y = (this.y) / k;
return this.toString()
},
norm: function() {
this.prevmag = this.mag();
this.div((this.mag()));
return this.toString()
},
add: function(vk) {
this.x = this.x + vk.x;
this.y = this.y + vk.y;
return this.toString()
},
sub: function(vk) {
this.x = this.x - vk.x;
this.y = this.y - vk.y;
return this.toString()
},
direction: function() {
return Math.atan2(this.y, this.x)
},
dot: function(v1) {
return (v1.x * this.x) + (v1.y * this.y)
}
};
var Position = (function() {
function Position(x, y) {
this.x = x;
this.y = y;
this.velocity = new Vector(0, 0);
this.xMax = 100;
this.yMax = 100;
this.radius = 10;
this.accel = new Vector(0, 0)
};
return Position
})(),
Spring = (function() {
function Spring(k, d, len) {
this.end1 = null;
this.end2 = null;
this.k = k;
this.d = d;
this.len = len
};
return Spring
})();
Spring.prototype = {
force: function() {
return new Vector(this.k * (this.end1.x - this.end2.x - this.len), this.k * (this.end1.y - this.end2.y - this.len))
},
damper: function() {
return (new Vector(this.d * (this.end1.velocity.x - this.end2.velocity.x), this.d * (this.end1.velocity.y - this.end2.velocity.y)))
},
calculate: function(end1, end2) {
this.end1 = end1;
this.end2 = end2;
var f1 = new Vector(end1.x - end2.x, end1.y - end2.y),
distan = f1.mag(),
x = end1.x - end2.x,
y = end1.y - end2.y;
end1.velocity.x += -(((x - (this.len / distan)) / this.k) + ((x - (this.len / distan)) / this.d)) / (2.0 * this.d);
end1.velocity.y += -(((y - (this.len / distan)) / this.k) + ((y - (this.len / distan)) / this.d)) / (2.0 * this.d);
end2.velocity.x += (((x - (this.len / distan)) / this.k) + ((x - (this.len / distan)) / this.d)) / (2.0 * this.d);
end2.velocity.y += (((y - (this.len / distan)) / this.k) + ((y - (this.len / distan)) / this.d)) / (2.0 * this.d);
end1.velocity.mult(0.95);
end2.velocity.mult(0.95);
return true
},
length: function() {
return Math.sqrt(this.end1.dist(this.end2))
}
};
Position.prototype = {
impact: function(point2) {
var point1 = this,
normal = point1.toPoint(point2),
normal2 = point2.toPoint(point1),
tangent = new Vector(-normal.y, normal.x),
tangent2 = new Vector(-normal2.y, normal2.x);
normal.norm();
normal2.norm();
tangent.norm();
tangent2.norm();
var midpoint = new Vector(((point1.x + point2.x) / 2.0), (point1.y + point2.y) / 2.0);
point1.x = midpoint.x - normal.x * (this.radius + 1);
point1.y = midpoint.y - normal.y * (this.radius + 1);
point2.x = midpoint.x - normal2.x * (point2.radius);
point2.y = midpoint.y - normal2.y * (point2.radius);
var v1n = normal.dot(point1.velocity),
v1t = tangent.dot(point1.velocity),
v2n = normal2.dot(point2.velocity),
v2t = tangent2.dot(point2.velocity);
normal.mult(v2n);
normal2.mult(v1n);
tangent.mult(v1t);
tangent2.mult(v2t);
var newv1 = new Vector(-(normal.x) + (tangent.x), -(normal.y) + (tangent.y)),
newv2 = new Vector(-(normal2.x) + (tangent2.x), -(normal2.y) + (tangent2.y));
point1.setvelocity(newv1);
point2.setvelocity(newv2)
},
getvelocity: function() {
if (this.type === "ball" || this.movableanchor === "false" || typeof this.anchor === 'undefined') {
return new Vector(this.velocity.x, this.velocity.y)
} else {
var t = this.anchor.getvelocity();
t.add(this.velocity);
return new Vector(t.x, t.y)
}
},
checkBounds: function() {
var maxx = this.xMax,
maxy = this.yMax;
if (this.x < 0) {
this.x = ((this.x) * -1) * 0.95;
this.velocity.x *= -1;
this.velocity.mult(0.95)
};
if (this.x > maxx) {
this.x = maxx - (this.x - maxx) * 0.95;
this.velocity.x *= -1;
this.velocity.mult(0.95)
};
if (this.y > maxy) {
this.y = maxy - (this.y - maxy) * 0.95;
this.velocity.y *= -1;
this.velocity.mult(0.95)
};
if (this.y < 0) {
this.y = ((this.y) * -1) * 0.95;
this.velocity.y *= -1;
this.velocity.mult(0.95)
}
},
display: function(c) {
var ctx = c,
p = this;
ctx.beginPath();
var x = p.x,
y = p.y,
rx = this.radius,
start = 0,
end = 2 * Math.PI,
anticlockwise = true;
if (this.spring !== null) {
ctx.moveTo(this.spring.end1.x, this.spring.end1.y);
ctx.lineTo(this.spring.end2.x, this.spring.end2.y)
} else ctx.arc(x, y, rx, start, end, anticlockwise);
ctx.strokeStyle = this.color;
ctx.stroke()
},
dist: function(p) {
return ((this.x - p.x) * (this.x - p.x) + (this.y - p.y) * (this.y - p.y))
},
step: function() {
this.x += this.velocity.x += this.accel.x;
this.y += this.velocity.y += this.accel.y
},
toString: function() {
return "[" + this.x + "," + this.y + "@" + this.velocity.toString + "]"
},
toPoint: function(v) {
return new Vector(-(this.x - v.x), -(this.y - v.y))
},
setvelocity: function(v) {
this.velocity.x = v.x;
this.velocity.y = v.y
}
}
function displayp(p, q) {
var ctx = can.getContext('2d');
ctx.beginPath();
var x = p.x,
y = p.y,
rx = 10,
start = 0,
end = 2 * Math.PI,
anticlockwise = true;
ctx.arc(x, y, rx, start, end, anticlockwise);
ctx.stroke();
ctx.moveTo(x, y);
ctx.lineTo(p.x + (p.velocity.x * 10.0), p.y + (p.velocity.y * 10.0));
ctx.stroke()
};
var bungiecount = 5,
can = document.createElement("canvas");
can.setAttribute("width", "400");
can.setAttribute("height", "400");
can.setAttribute("style", "transform: scale(0.70, 0.70);border-style:groove;border-width:4px;");
document.body.appendChild(can);
var balls = [];
for (var i = 0; i < bungiecount; i++) {
balls.push(new Position(50, 50));
balls[balls.length - 1].xMax = 400;
balls[balls.length - 1].yMax = 400;
balls[balls.length - 1].velocity = new Vector(Math.random() - 0.5, Math.random() - 0.5);
balls[balls.length - 1].velocity.mult(5.0);
balls[balls.length - 1].radius = 20;
balls[balls.length - 1].accel = new Vector(0, 1);
balls[balls.length - 1].type = "pend";
balls[balls.length - 1].spring = new Spring(i, 1.1, 1.0);
balls[balls.length - 1].color = "RGB(" + Math.round(Math.random() * 255) + "," + Math.round(Math.random() * 255) + "," + Math.round(Math.random() * 255) + ")";
if (i === 0) {
balls[i].type = "ball";
balls[i].spring = null
}
};
var ballcount = 900;
for (var i = 0; i < ballcount; i++) {
balls.push(new Position(can.width * Math.random(), can.height * Math.random()));
balls[balls.length - 1].xMax = 400;
balls[balls.length - 1].yMax = 400;
balls[balls.length - 1].velocity = new Vector(2 * Math.random() - 1, 2 * Math.random() - 1);
balls[balls.length - 1].velocity.mult(5.0);
balls[balls.length - 1].radius = 4;
balls[balls.length - 1].accel = new Vector(0, 1);
balls[balls.length - 1].type = "ball";
balls[balls.length - 1].spring = null
}
function repeater() {
var c = can.getContext('2d');
c.clearRect(0, 0, can.width, can.height);
for (var k = 0; k < balls.length; k++) {
if (balls[k].spring !== null) balls[k].spring.calculate(balls[k], balls[k - 1]);
balls[k].step()
};
for (var k = 0; k < balls.length; k++) if (balls[k].type == "ball") for (var j = 0; j < ballcount; j++) if (balls[j].type == "ball") if (k != j) if (balls[k].dist(balls[j]) < (balls[k].radius + balls[j].radius) * (balls[k].radius + balls[j].radius)) balls[k].impact(balls[j]);
for (var i = 0; i < balls.length; i++) {
balls[i].display(c);
balls[i].checkBounds();
balls[bungiecount - 1].x = mx;
balls[bungiecount - 1].y = my
}
};
var mx = 200,
my = 200;
window.setInterval(repeater, 33);
document.body.onmousemove = function mousemover(evt) {
mx = evt.pageX;
my = evt.pageY
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment