class Boid {
constructor(Boids, opts){
Object.assign(this, Boids);
Object.assign(this, opts);
this.ang = this.ang || 2 * Math.random() * Math.PI;
this.pos = this.pos || [
Math.random() * this._width,
Math.random() * this._height
];
this.speed = this.speed || 1;
const obj = {
pos: this.pos,
ang: this.ang,
speed: this.speed,
vel: vecmath.sub(
vecmath.trans(this.pos, this.ang, this.speed),
this.pos
),
acc: [0, 0],
id: this.flock.length
};
Object.assign(this, obj);
}
update(){
const prev = { ...this };
let alignment = [0, 0],
cohesion = [0, 0],
separation = [0, 0],
n = 0,
candidates = this.flock;
if (this._quadtree){
candidates = this.tree.search({
minX: this.pos[0] - this._perception,
minY: this.pos[1] - this._perception,
maxX: this.pos[0] + this._perception,
maxY: this.pos[1] + this._perception,
});
}
for (let i = 0, l = candidates.length; i < l; i ++){
const that = candidates[i],
dist = vecmath.dist(this.pos, that.pos);
if (this.id !== that.id && dist < this._perception){
alignment = vecmath.add(alignment, that.vel);
cohesion = vecmath.add(cohesion, that.pos);
const diff = vecmath.div(
vecmath.sub(this.pos, that.pos),
Math.max(dist, epsilon)
);
separation = vecmath.add(separation, diff);
n++;
}
}
if (n > 0){
alignment = vecmath.div(alignment, n);
alignment = vecmath.setMag(alignment, this._maxSpeed);
alignment = vecmath.sub(alignment, this.vel);
alignment = vecmath.limit(alignment, this.maxForce);
cohesion = vecmath.div(cohesion, n);
cohesion = vecmath.sub(cohesion, this.pos);
cohesion = vecmath.setMag(cohesion, this._maxSpeed);
cohesion = vecmath.sub(cohesion, this.vel);
cohesion = vecmath.limit(cohesion, this.maxForce);
separation = vecmath.div(separation, n);
separation = vecmath.setMag(separation, this._maxSpeed);
separation = vecmath.sub(separation, this.vel);
separation = vecmath.limit(separation, this.maxForce);
}
alignment = vecmath.mult(alignment, this._alignment);
cohesion = vecmath.mult(cohesion, this._cohesion);
separation = vecmath.mult(separation, this._separation);
this.acc = vecmath.add(this.acc, alignment);
this.acc = vecmath.add(this.acc, cohesion);
this.acc = vecmath.add(this.acc, separation);
this.pos = vecmath.add(this.pos, this.vel);
this.vel = vecmath.add(this.vel, this.acc);
this.vel = vecmath.limit(this.vel, this._maxSpeed);
if (this.pos[0] > this._width) this.pos[0] = 0;
if (this.pos[0] < 0) this.pos[0] = this._width;
if (this.pos[1] > this._height) this.pos[1] = 0;
if (this.pos[1] < 0) this.pos[1] = this._height;
this.ang = vecmath.ang(prev.pos, this.pos);
this.speed = vecmath.dist(prev.pos, this.pos);
this.acc = vecmath.mult(this.acc, 0);
}
}