class Boid {
constructor([x, y, z], scene) {
this.position = new THREE.Vector3(x, y, z);
this.acceleration = new THREE.Vector3(0, 0, 0);
const angle = randomAngle();
this.velocity = new THREE.Vector3(
Math.cos(angle),
Math.sin(angle),
Math.sin(angle)
);
this.init(scene);
}
init(scene) {
const { position } = this;
const r = boidValues[0][1];
const geometry = new THREE.BoxBufferGeometry(r, r, r);
const material = new THREE.MeshPhongMaterial({
color: `rgba(150,150,150, 1)`
});
const cube = new THREE.Mesh(geometry, material);
cube.position.set(...position.toArray());
scene.add(cube);
this.mesh = cube;
}
run(boids, scene, counter) {
this.flock(boids);
this.update(counter);
this.borders();
}
applyForce(force) {
const mass = boidValues[0][4];
this.acceleration.add(force.divideScalar(mass));
}
flock(boids, scene) {
const sep = this.separate(boids);
const ali = this.align(boids, scene);
const coh = this.cohesion(boids);
sep.multiplyScalar(behaviorValues[0][0]);
ali.multiplyScalar(behaviorValues[0][1]);
coh.multiplyScalar(behaviorValues[0][2]);
this.applyForce(sep);
this.applyForce(ali);
this.applyForce(coh);
}
separate(boids) {
const { position, velocity } = this;
const steer = new THREE.Vector3(0, 0, 0);
let count = 0;
for (let boid of boids) {
const d = position.distanceTo(boid.position);
const neighborDistSeperate = behaviorValues[0][3];
if (d > 0 && d < neighborDistSeperate) {
const diff = new THREE.Vector3().subVectors(position, boid.position);
diff.normalize();
diff.divideScalar(d);
steer.add(diff);
count += 1;
}
}
if (count > 0) {
steer.divideScalar(count);
}
if (steer.length() > 0) {
const maxSpeed = boidValues[0][2];
const maxForce = boidValues[0][3];
steer.setLength(maxSpeed);
steer.sub(velocity);
steer.clampLength(0, maxForce);
}
return steer;
}
align(boids) {
const { position, velocity } = this;
const sum = new THREE.Vector3(0, 0, 0);
let count = 0;
for (let boid of boids) {
const d = position.distanceTo(boid.position);
const neighborDistAlign = behaviorValues[0][4];
if (d > 0 && d < neighborDistAlign) {
sum.add(boid.velocity);
count += 1;
}
}
if (count > 0) {
const maxSpeed = boidValues[0][2];
const maxForce = boidValues[0][3];
sum.divideScalar(count);
sum.setLength(maxSpeed);
const steer = new THREE.Vector3().subVectors(sum, velocity);
steer.clampLength(0, maxForce);
return steer;
}
return new THREE.Vector3(0, 0, 0);
}
cohesion(boids) {
const { position } = this;
const sum = new THREE.Vector3(0, 0, 0);
let count = 0;
for (let boid of boids) {
const d = position.distanceTo(boid.position);
const neighborDistCohesion = behaviorValues[0][5];
if (d > 0 && d < neighborDistCohesion) {
sum.add(boid.position);
count += 1;
}
}
if (count > 0) {
sum.divideScalar(count);
return this.seek(sum);
}
return new THREE.Vector3(0, 0, 0);
}
seek(target) {
const { position, velocity } = this;
const maxSpeed = boidValues[0][2];
const maxForce = boidValues[0][3];
const desired = new THREE.Vector3().subVectors(target, position);
desired.setLength(maxSpeed);
const steer = new THREE.Vector3().subVectors(desired, velocity);
steer.clampLength(0, maxForce);
return steer;
}
borders() {
const { position } = this;
const area = areaValues[0][0];
const r = boidValues[0][1];
if (position.x < -r) position.x = area + r;
if (position.y < -r) position.y = area + r;
if (position.z < -r) position.z = area + r;
if (position.x > area + r) position.x = -r;
if (position.y > area + r) position.y = -r;
if (position.z > area + r) position.z = -r;
}
update(counter) {
const { position, velocity, acceleration, mesh, color } = this;
const maxSpeed = boidValues[0][2];
velocity.add(acceleration);
velocity.clampLength(0, maxSpeed);
position.add(velocity);
acceleration.multiplyScalar(0);
mesh.position.set(...position.toArray());
}
}