这篇博客灵感来源于https://www.voidgame.space/articles/Voidmatrix/boids-algorithm/
Boids算法常见应用领域
动画和图形学:在电影制作和游戏开发中,Boids算法可以用于模拟鱼群、鸟群、昆虫群等自然生物的群体行为,使得动画场景更加逼真。
交通流模拟:Boids算法可以用于模拟车辆、行人或飞行器等交通工具的行为,用于优化交通流、规划路径或测试交通规则。
虚拟现实:在虚拟现实环境中,Boids算法可以用于模拟人群行为,例如在模拟人群疏散、人群聚集等场景中应用。
群体智能研究:Boids算法提供了一种简单但有效的方法来研究群体行为和群体智能,可以用于研究生态系统、社会动态等领域。
Boids三规则

分离:个体之间相互排斥,避免成一团。
聚集:个体朝着大部队运动。
对齐:个体运动的方向是同伴的平均运动方向。
用EasyX模拟实现该算法
重载一个Vector2D容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| struct Vector2D { float x, y;
Vector2D() = default; Vector2D(float _x, float _y) : x(_x), y(_y) {}
Vector2D operator+(const Vector2D& other) const { return Vector2D(x + other.x, y + other.y); }
Vector2D operator-(const Vector2D& other) const { return Vector2D(x - other.x, y - other.y); }
Vector2D operator*(float scalar) const { return Vector2D(x * scalar, y * scalar); }
float length() const { return std::sqrt(x * x + y * y); }
void normalize() { float len = length(); x /= len; y /= len; } };
|
定义集群单位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
| struct Boid { COLORREF color; Vector2D position; Vector2D velocity;
Vector2D cohesion(const std::vector<Boid>& boids)/操作/位置 { Vector2D center_of_mass(0, 0); int total_neighbors = 0;
for (const Boid& b : boids) { float distance = (b.position - position).length();
if (distance > 0 && distance < neighbour_distance) { center_of_mass = center_of_mass + b.position; total_neighbors++; } }
if (total_neighbors > 0) { center_of_mass = center_of_mass * (1.0f / total_neighbors); return (center_of_mass - position); }
return Vector2D(0, 0); }
Vector2D separation(const std::vector<Boid>& boids) { Vector2D separation(0, 0);
for (const Boid& b : boids) { float distance = (b.position - position).length();
if (distance > 0 && distance < separation_distance) { Vector2D diff = position - b.position; separation = separation + diff * (1.0f / distance); } }
return separation; }
Vector2D alignment(const std::vector<Boid>& boids) { Vector2D avg_velocity(0, 0); int total_neighbors = 0;
for (const Boid& b : boids) { float distance = (b.position - position).length();
if (distance > 0 && distance < neighbour_distance) { avg_velocity = avg_velocity + b.velocity; total_neighbors++; } }
if (total_neighbors > 0) { avg_velocity = avg_velocity * (1.0f / total_neighbors); return avg_velocity - velocity; }
return Vector2D(0, 0); }
void update(const std::vector<Boid>& boids) { Vector2D v1 = cohesion(boids); Vector2D v2 = separation(boids); Vector2D v3 = alignment(boids);
v1 = v1 * cohesion_weight; v2 = v2 * separation_weight; v3 = v3 * align_weight;
velocity = velocity + v1 + v2 + v3;
float speed = velocity.length(); if (speed > max_speed) velocity = velocity * (max_speed / speed);
position = position + velocity;
if (position.x < 0) position.x = 0; if (position.x > 1280) position.x = 1280; if (position.y < 0) position.y = 0; if (position.y > 720) position.y = 720; }
float neighbour_distance = 100.0f; float separation_distance = 50.0f; float cohesion_weight = 1.0f; float separation_weight = 1.0f; float align_weight = 1.0f; float max_speed = 5.0f; };
|
在幕布上随机位置绘制随机颜色的boid
1 2 3 4 5 6 7
| std::vector<Boid> boids(500); for (Boid& b : boids) { b.position.x = (float)(rand() % 1280); b.position.y = (float)(rand() % 720); b.color = RGB(rand() % 255, rand() % 255, rand() % 255); }
|
主循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| int main() { initgraph(1280, 720, EW_SHOWCONSOLE); BeginBatchDraw();
std::vector<Boid> boids(500); for (Boid& b : boids) { b.position.x = (float)(rand() % 1280); b.position.y = (float)(rand() % 720); b.color = RGB(rand() % 255, rand() % 255, rand() % 255); }
while (true) { for (Boid& b : boids) b.update(boids);
cleardevice(); for (Boid& b : boids) { setfillcolor(b.color); fillcircle((int)b.position.x, (int)b.position.y, 10); } FlushBatchDraw();
Sleep(25); }
return 0; }
|
在某些图形库或绘图环境中,为了提高性能和减少屏幕闪烁,绘图操作可能被暂时存储在一个称为绘图缓冲区的内存区域中。当使用 FlushBatchDraw() 函数时,它会强制将这些存储的绘图操作立即应用到屏幕上,从而使用户能够看到更新后的图像