引言
游戏 AI 的核心任务通常是:我知道我在哪,我要去哪,怎么去? 这涉及两个层面: 1. 宏观寻路: 规划一条从 A 到 B 的路径(A* 算法)。 2. 微观移动: 如何控制速度和方向来沿着路径移动,并避开障碍(操纵行为)。
1. 寻路 (Pathfinding) - A*
A* (A-Star) 是最著名的寻路算法。它结合了 Dijkstra 的广度优先搜索和贪婪最佳优先搜索。 核心公式: \[ F = G + H \]
- G (Cost): 从起点走到当前格子的实际代价。
- H (Heuristic): 从当前格子到终点的估算代价(通常用曼哈顿距离或欧几里得距离)。
- F: 总评分。每次都选择 F 值最小的格子继续探索。
2. 操纵行为 (Steering Behaviors)
一旦有了路径,或者在开放空间中移动,我们需要计算每一帧的力。 Craig Reynolds 在 1986 年提出了著名的 Boids 模型来模拟鸟群。
基本公式: \[ \vec{Steering} = \vec{Desired} - \vec{Velocity} \] \[ \vec{Force} = \text{clamp}(\vec{Steering}, \text{maxForce}) \]
2.1 分离 (Separation)
“别挤我!” 检查周围邻居,计算一个背离它们的向量平均值。距离越近,斥力越大。
2.2 对齐 (Alignment)
“随大流。” 计算周围邻居的平均速度方向(Heading),并尝试转向该方向。
2.3 内聚 (Cohesion)
“别掉队。” 计算周围邻居的平均位置(Center of Mass),并尝试向该点移动。
代码实现 (Seek 行为): 这是所有操纵行为的基础。
Vector3 Seek(Vector3 target) {
Vector3 desired = (target - position).normalized * maxSpeed;
Vector3 steering = desired - velocity;
return Vector3.ClampMagnitude(steering, maxForce);
}
// 在 Update 中应用
void Update() {
Vector3 force = Seek(targetPosition);
// 可以叠加其他力:Separation, Alignment...
velocity += force * Time.deltaTime;
velocity = Vector3.ClampMagnitude(velocity, maxSpeed);
position += velocity * Time.deltaTime;
// 朝向速度方向
if (velocity != Vector3.zero)
transform.forward = velocity;
}3. 组合行为
将上述力加权求和: \[ \vec{F}_{total} = w_1 \vec{F}_{sep} + w_2 \vec{F}_{align} + w_3 \vec{F}_{coh} + w_4 \vec{F}_{path} \] 通过调整权重,可以模拟出鱼群、鸟群甚至僵尸潮的运动模式。
总结
- A* 解决了”怎么走迷宫”的问题。
- Steering Behaviors 解决了”怎么走得自然”的问题。
- 简单的向量加减法就能涌现出复杂的群体智能。