Boids
Simulation
Code
= {
chart const width = fullWidth,
= fullHeight;
height
const window = d3.create("svg")
.attr("width", "100%")
.attr("height", "100%")
.attr("viewBox", `0 0 ${fullWidth} ${fullHeight}`)
.attr("preserveAspectRatio", "xMidYMid meet");
const svg = window.append("g")
.attr("class", "boids");
let cohesionCoeff = defaults.cohesionCoeff,
= defaults.alignmentCoeff,
alignmentCoeff = defaults.separationCoeff;
separationCoeff
const n = 500,
= 30,
separationDistance = 60,
neighborDistance = 2,
maxVelocity = 0.02;
maxAcceleration
const line = d3.line();
const color = d3.scaleSequential(d3.interpolateYlGnBu)
.domain([0, maxVelocity]);
const randomX = d3.randomUniform(0, width),
= d3.randomUniform(0, height),
randomY = d3.randomUniform(0, maxVelocity),
randomVx = d3.randomNormal(0, maxVelocity / 4);
randomVy
let boids = d3.range(n).map(() => ({
pos: new Vec(randomX(), randomY()),
vel: new Vec(randomVx(), randomVy()),
acc: new Vec()
;
}))
function tick(t) {
= boids.filter(b =>
boids .pos.x > 0) & (b.pos.x < width) &
(b.pos.y > 0) & (b.pos.y < height));
(b
.push({
boidspos: new Vec(0, randomY()),
vel: new Vec(randomVx(), randomVy()),
acc: new Vec()
;
})
.forEach(b1 => {
boidsconst cohesionForce = new Vec(),
= new Vec(),
alignmentForce = new Vec();
separationForce
.forEach(b2 => {
boidsif (b1 === b2) {
return;
}
const separation = b2.pos.clone().minus(b1.pos),
= separation.length();
distance
if (distance < separationDistance) {
.minus(separation);
separationForceelse if (distance < neighborDistance) {
} .plus(separation);
cohesionForce.plus(b2.vel.clone().minus(b1.vel));
alignmentForce
};
})
.normalize(cohesionCoeff);
cohesionForce.normalize(alignmentCoeff);
alignmentForce.normalize(separationCoeff);
separationForce
.acc = new Vec()
b1.plus(cohesionForce)
.plus(alignmentForce)
.plus(separationForce)
.truncate(maxAcceleration);
.vel
b1.plus(b1.acc)
.truncate(maxVelocity);
.pos
b1.plus(b1.vel);
;
})
.selectAll(".boid")
svg.data(boids)
.join("path")
.attr("class", "boid")
.style("stroke-width", 2)
.style("stroke", b => color(b.vel.length()))
.attr("d", b => {
const v = b.vel.clone().normalize(20);
return line([
.pos.x - v.x / 2, b.pos.y - v.y / 2],
[b.pos.x + v.x / 2, b.pos.y + v.y / 2]
[b;
]);
})
}
const timer = d3.interval(tick, 20);
.then(() => {
invalidation.stop();
timer;
})
return Object.assign(window.node(), {
update(values) {
= values.cohesionCoeff;
cohesionCoeff = values.alignmentCoeff;
alignmentCoeff = values.separationCoeff;
separationCoeff ,
};
}) }
The Boids model can be used to simulate the flocking behavior of birds.