xxxxxxxxxx
184
let pos, vels;
let a, aStart, as;
let solidLines = [];
let movingLine;
let logging;
function setup() {
theCanvas = createCanvas(400, 400);
solidLines.push(new SolidLine(0, 100, 400, 100));
solidLines.push(new SolidLine(0, 100, 400, 400));
solidLines.push(new SolidLine(300, 0, 300, 400));
movingLine = new MovingLine(200, 200, 220, 220);
}
function draw() {
movingLine = new MovingLine(200, 200, mouseX, mouseY);
background(220);
let pos, vel, lineArgs, roughLines, reflectLines;
for (let i = 0; i < 5; i++) {
pos = movingLine.vecs.slice(0, movingLine.vecs.length-1).reduce(
(x,y) => p5.Vector.add(x,y), movingLine.start);
vel = movingLine.vecs.last();
lineArgs = [pos.x, pos.y, vel.x, vel.y];
reflectLines = solidLines.filter(l =>
vectorCollision(lineArgs,
startEndArgs(l)
));
if (reflectLines.length > 1) {reflectLines.sort((a, b) =>
vectorCollisionFrac(lineArgs,
startEndArgs(a))
-
vectorCollisionFrac(lineArgs,
startEndArgs(b)));}
if (reflectLines.length > 0) {
movingLine.reflectLastVelocityOn(reflectLines[0]);
}
else {
break;
}
}
solidLines.forEach(l => l.draw());
if (logging) {console.log(movingLine.vecs)}
movingLine.draw();
}
if (!Array.prototype.last) {
Array.prototype.last = function() {
return this[this.length - 1];
}
}
function mousePressed() {
logging = true;
}
function mouseReleased() {
logging = false;
}
function vectorCollision(ax, ay, bx, by, cx, cy, dx, dy) {
// Given two lines r_1 = a + hb & r_2 = c + kd, returns true if the lines intersect and false if they do not (note lines are finite with 0 < h, k < 1
let det, h, k;
det = bx*dy - by*dx;
if (det == 0) {
return false;
}
else {
h = +(+dy*(cx-ax)-dx*(cy-ay)) / det;
k = -(-by*(cx-ax)+bx*(cy-ay)) / det;
return ((0 < h && h < 1) && (0 < k && k < 1));
}
}
function vectorCollisionFrac(ax, ay, bx, by, cx, cy, dx, dy) {
// Given two lines r_1 = a + hb & r_2 = c + kd, returns the fraction along r_1 that the lines intersect, given that they do intersect
let det = bx*dy - by*dx;
let h = +(+dy*(cx-ax)-dx*(cy-ay)) / det;
if (!(0 < h && h < 1)) {
throw "vectorCollisionFrac was called with an invalid collision!";
}
return +(+dy*(cx-ax)-dx*(cy-ay)) / det;
}
function roughCollision(ax, ay, bx, by, cx, cy, dx, dy) {
return (Math.abs(ax-cx) < Math.abs(bx) + Math.abs(dx) && Math.abs(ay-cy) < Math.abs(by) + Math.abs(dy));
}
function startEndArgs(l) {
return [l.x1, l.y1, l.vec.x, l.vec.y];
}
function reflectVector(apos, adir, bpos, bdir) {
let frac = vectorCollisionFrac(apos.x, apos.y, adir.x, adir.y,
bpos.x, bpos.y, bdir.x, bdir.y);
let first = p5.Vector.mult(adir, frac);
let aParallel = projectVector(adir, bdir);
let aPerpendic = p5.Vector.sub(adir, aParallel);
let aReflected = p5.Vector.add(aParallel, p5.Vector.mult(aPerpendic, -1));
let second = p5.Vector.mult(aReflected, 1 - frac);
return [first, second];
// return [adir, second];
}
function projectVector(a, b) {
return p5.Vector.mult(b, p5.Vector.dot(a,b) / b.magSq());
}
class SolidLine {
constructor(x1, y1, x2, y2, color="blue") {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.start = createVector(x1, y1);
this.end = createVector(x2, y2);
this.vec = createVector(x2-x1, y2-y1);
this.color = color;
}
draw() {
push();
stroke(this.color);
line(this.x1, this.y1, this.x2, this.y2);
pop();
}
}
class MovingLine {
constructor(x1, y1, x2, y2, color="red") {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.start = createVector(this.x1, this.y1);
this.end = createVector(this.x2, this.y2);
this.vecs = [createVector(this.x2-this.x1, this.y2-this.y1)];
this.color = color;
}
draw() {
push();
stroke(this.color);
let initial = this.start;
this.vecs.forEach(function(vec, i, vecs) {
let start = vecs.slice(0,i)
.reduce((x,y) => p5.Vector.add(x,y), initial);
let end = p5.Vector.add(start, vec);
line(start.x, start.y, end.x, end.y);
});
pop();
}
reflectLastVelocityOn(l) {
let pos = this.vecs.slice(0, this.vecs.length-1).reduce(
(x,y) => p5.Vector.add(x,y), this.start);
let vel = this.vecs.last();
let reflector = reflectVector(pos, vel, l.start, l.vec);
this.vecs = this.vecs.slice(0, this.vecs.length-1).concat(reflector);
}
}