xxxxxxxxxx
206
class Particle {
constructor(m, x, y, r) {
this.locked = false;
this.acceleration = createVector(0, 0);
this.velocity = createVector(0, 0);
this.position = createVector(x, y);
this.mass = m;
this.r = r;
this.a = 0;
this.aV = 0;
this.dt = 0.25;
}
applyForce(force) {
let f = force.copy();
f.div(this.mass);
this.acceleration.add(f);
}
applyGravity(g) {
let gravity = createVector(0, g * this.mass);
this.applyForce(gravity);
}
applyNormalAndFriction(fricC=0, a=0) {
let N = this.acceleration.copy().mult(this.dt);
N.add(this.velocity);
N.rotate(-a);
N.x = 0;
N.rotate(a);
N.mult(-this.mass/this.dt);
this.applyForce(N);
let fricMag = N.mag() * fricC * this.velocity.mag();
let fric = this.velocity.copy();
fric.rotate(-a);
fric.y = 0;
fric.rotate(a);
fric.setMag(-fricMag);
this.applyForce(fric);
}
applyDrag(dragC) {
let drag = this.velocity.copy();
let spSq = drag.magSq();
let dragMag = spSq * dragC;
drag.setMag(-dragMag);
this.applyForce(drag);
}
applyBounce(restitution=1, angle=0) {
let vel_i = this.velocity.copy();
let vel_f = vel_i.copy();
vel_f.rotate(-angle);
vel_f.y *= -restitution;
vel_f.rotate(angle);
let vel_paral = vel_i.copy();
vel_paral.rotate(-angle);
vel_paral.y = 0;
vel_paral.rotate(angle);
let acc = p5.Vector.sub(vel_f, vel_paral).div(this.dt);
let force = acc.copy();
force.mult(this.mass);
this.applyForce(force);
}
update() {
if (!this.locked) {
this.velocity.add(this.acceleration.copy().mult(this.dt));
this.position.add(this.velocity.copy().mult(this.dt));
this.aV = this.velocity.x / this.r;
this.a += this.aV * this.dt;
this.acceleration.mult(0);
}
}
collide(other) {
let axis = p5.Vector.sub(other.position, this.position);
let d = axis.mag();
let off = this.r + other.r - d;
if (off > 0) {
if (!this.locked && !other.locked) {
axis.setMag(off / 2);
other.position.add(axis);
axis.mult(-1);
this.position.add(axis);
} else if (!this.locked && other.locked) {
axis.setMag(off);
axis.mult(-1);
this.position.add(axis);
} else if (this.locked && !other.locked) {
axis.setMag(off);
other.position.add(axis);
}
}
}
connect(other, len, mutual = false) {
let axis = p5.Vector.sub(other.position, this.position);
let d = axis.mag();
let off = len - d;
if (mutual) {
axis.setMag(off / 2);
other.position.add(axis);
axis.mult(-1);
this.position.add(axis);
} else {
axis.setMag(off);
other.position.add(axis);
}
}
show(img) {
push();
translate(this.position.x, this.position.y);
rotate(this.a);
//ellipse(0, 0, this.r * 2);
//line(0, 0, this.r, 0);
imageMode(CENTER);
image(img, 0, 0, this.r * 2, this.r * 2);
pop();
}
collidePt(p) {
let d = p5.Vector.dist(this.position, p);
return d <= this.r;
}
collideSeg(p1, p2) {
let vecAB = p5.Vector.sub(p2, p1);
let vecAC = p5.Vector.sub(this.position, p1);
let a = vecAB.angleBetween(vecAC);
let lAC = vecAC.mag();
let lAB = vecAB.mag();
let closestD = abs(lAC * sin(a));
let lProjAC = lAC * cos(a);
return (
(closestD <= this.r && lProjAC >= 0 && lProjAC <= lAB) ||
this.collidePt(p1) ||
this.collidePt(p2)
);
}
getSegCollisionOff(p1, p2, mode) {
let vecAB = p5.Vector.sub(p2, p1);
let vecAC = p5.Vector.sub(this.position, p1);
let a = vecAB.angleBetween(vecAC);
let lAC = vecAC.mag();
let lAB = vecAB.mag();
let closestD;
if (mode == "polygon") {
closestD = -lAC * sin(a);
} else {
closestD = abs(lAC * sin(a));
}
let lProjAC = lAC * cos(a);
if (closestD <= this.r && lProjAC >= 0 && lProjAC <= lAB) {
return this.r - closestD;
} else if (this.collidePt(p1)) {
return this.r - p5.Vector.dist(this.position, p1);
} else if (this.collidePt(p2)) {
return this.r - p5.Vector.dist(this.position, p2);
}
}
collideChain(arr, insideChain=false) {
if (!insideChain) {
for (let i = 0; i < arr.length - 1; i++) {
if (this.collideSeg(arr[i], arr[i + 1])) {
return true;
}
}
} else {
return collideCirclePoly(this.position.x,this.position.y,this.r * 2,arr,true);
}
}
getChainCollisionAngle(arr) {
let recOff = 0;
for (let i = 0; i < arr.length - 1; i++) {
if (this.collideSeg(arr[i], arr[i + 1])) {
let off = this.getSegCollisionOff(arr[i], arr[i + 1], "polygon");
if (off > recOff) {
recOff = off;
return p5.Vector.sub(arr[i + 1], arr[i]).heading();
}
}
}
if (this.collideChain(arr,true) && !this.collideChain(arr)) {
//this.velocity.mult(0);
return 0;
}
}
getChainCollisionOff(arr) {
let recOff = 0;
for (let i = 0; i < arr.length - 1; i++) {
if (this.collideSeg(arr[i], arr[i + 1])) {
let off = this.getSegCollisionOff(arr[i], arr[i + 1], "polygon");
if (off > recOff) {
recOff = off;
return recOff;
}
}
}
if (this.collideChain(arr,true) && !this.collideChain(arr)) {
//this.velocity.mult(0);
return (this.r*2);
}
}
}