Boids 是 Craig Reynolds 于 1987 年提出的经典鸟群模拟算法。它展示了涌现行为(emergent behavior)——每个个体(boid)只遵循三条简单的局部规则,但整体却呈现出逼真的鸟群飞行、鱼群游动等协调集体行为。
核心思想:没有中央控制者。群体中不存在 "领头鸟" 或全局路径规划。鸟群的同步转向、分群与合群完全来自个体之间的局部交互。
每个 boid 试图与其邻近同伴保持距离,避免碰撞和拥挤。
其中 \(N\) 是感知半径内的所有邻居。排斥力指向远离每个近邻的方向,近距离邻居的排斥权重更大。模拟器中对感知半径 40% 以内的近邻施加增强排斥。
每个 boid 试图与邻近同伴的平均飞行方向保持一致。
即邻居的平均速度与自身速度之差。这个规则使得鸟群形成统一的运动方向。
每个 boid 试图向邻近同伴的质心移动。
即邻居的平均位置与自身位置之差对应的速度向量。这个规则使得鸟群保持聚集,不会散开。
每个 boid 的运动由上述三个力的加权和驱动:
力被限制在最大转向力 \(F_{\text{max}}\) 以内(防止瞬间急转),速度被限制在 \(v_{\text{max}}\) 以内(防止无限加速)。
当 boid 靠近画布边缘时,施加一个指向画布中心的力:
其中 \(d_{\text{edge}}\) 是 boid 到最近边缘的距离,\(d_{\text{margin}}\) 是可调的边缘回避距离。
当启用捕食者模式时,鼠标指针充当 "捕食者"。距离捕食者 150 像素以内的 boid 会受到强烈的排斥力,方向远离捕食者。这使得鸟群在用户移动鼠标时呈现出紧急规避行为。
| 功能 | 操作 | 说明 |
|---|---|---|
| 添加 boid | 点击画布空白处 | 在点击位置创建新个体 |
| 暂停/继续 | 按钮或空格键 | 冻结群体运动,便于分析当前状态 |
| 重置 | 按钮 | 清空并重新生成鸟群 |
| 捕食者模式 | 按钮切换 | 鼠标变为"捕食者",靠近的 boid 会紧急逃散 |
| 显示感知半径 | 按钮切换 | 显示每个 boid 的感知范围圆,理解局部交互 |
| 参数 | 效果 |
|---|---|
| 分离权重 \(w_s\) | 个体间保持距离的倾向。增大则间距扩大,减小则更拥挤 |
| 对齐权重 \(w_a\) | 与同伴方向保持一致的倾向。增大则飞行方向更统一 |
| 凝聚权重 \(w_c\) | 向群体中心靠拢的倾向。增大则群体更紧密 |
| 感知半径 | 每个 boid "看到"同伴的距离。增大则形成更大群体 |
| 最大速度 | 个体飞行的速度上限 |
| 转向力 | 个体转向的敏捷程度 |
每个 boid 每帧都需要查找感知半径内的所有同伴。朴素实现是 O(N²):对每个 boid 遍历所有其他 boid。由于本模拟器的 boid 数量通常在 100 以内,这个复杂度是完全可接受的。
对于大规模模拟(成千上万 boid),可采用空间哈希或四叉树优化邻居查找至近似 O(N)。
每帧计算出的总力向量被限制在 maxForce 以内。这个机制模拟了生物的运动惯性——即使是鸟类也不能瞬间改变飞行方向。
画布每帧不彻底清空,而是覆盖一层半透明黑色(alpha ≈ 0.25),产生运动拖尾效果。向前运动的 boid 留下逐渐淡出的痕迹,视觉上增强了速度感和群体流向。
| 参数 | 效果 | 极端值表现 |
|---|---|---|
| 分离权重 \(w_s\) ↑ | 个体间距增大 | 鸟群炸开,难以聚合 |
| 分离权重 \(w_s\) ↓ | 个体靠得更近 | 鸟群挤成一团,缺乏层次 |
| 对齐权重 \(w_a\) ↑ | 飞行方向更加一致 | 鸟群像军队一样整齐划一 |
| 凝聚权重 \(w_c\) ↑ | 鸟群更加紧密 | 所有鸟飞向同一点,来回震荡 |
| 感知半径 ↑ | 个体能 "看到" 更远的同伴 | 整个群体形成一个整体;半径过小则分散为小团 |
| 最大速度 ↑ | 鸟群移动更快 | 运动不稳定,频繁冲撞边缘 |
| 转向力 ↑ | 转向更敏捷 | 运动变得抖动、不自然 |
Boids 是涌现(emergence)的经典案例:
这些行为没有在任何代码中显式编程——它们自然涌现于三条简单规则的相互作用。