# 采样避障学习版核心原理

## 一句话结论

采样避障学习版的核心是 **不直接求解析最优解，而是在一批候选速度中打分选择当前最合适的速度**。它是项目内自写的学习基线，目标是可读、可改、可调参，而不是证明无碰撞。

实现位置：

```text
Assets/Scripts/Benchmark/FrameworkAdapters/SamplingLocalAvoidanceAdapter.cs
```

## 为什么写这个版本

RVO2/ORCA 很成熟，但内部数学和约束求解不容易快速改。

NavMeshAgent 工程成熟，但它是完整导航系统，不是纯局部避障算法。

学习版采样避障的目的不同：

- 给你一个完全可控的 baseline。
- 让每个评分项都能看懂、能改权重。
- 方便测试“如果我改变风险函数，会发生什么”。
- 为后续写更好的自研算法提供实验平台。

## 基本思路

每帧对每个 agent 做三步：

```text
1. 找附近邻居
2. 生成候选速度
3. 给候选速度打分，选择分数最低的速度
```

它不是像 RVO2 那样构造半平面约束，而是把避障变成一个启发式评分问题。

## 空间哈希找邻居

如果每个 agent 都和所有其他 agent 比较，复杂度是：

```text
O(n²)
```

5000 条鱼时会非常贵。

所以学习版先把 agent 放进空间哈希格子：

```text
世界坐标 x/z
  -> 根据 cellSize 计算格子坐标
  -> 每个格子保存一批 agent
  -> 查询时只看自己附近几个格子
```

这样大多数情况下只需要检查附近 agent，而不是全量扫描。

## 候选速度

候选速度主要来自：

- 当前期望速度。
- 零速度。
- 以期望方向为基准旋转出的多个方向。
- 不同速度倍率，例如全速和半速。

可以理解为：

```text
我想往目标方向走，
但也试试稍微偏左、偏右、减速、停下，
看哪个风险最低。
```

当前版本每帧采样固定数量方向，优先保持实现简单和可读。

## 评分函数

每个候选速度都会计算一个分数：

```text
总分 =
  目标偏差惩罚
  + 速度平滑惩罚
  + 预测碰撞惩罚
  + 当前重叠惩罚
  + 边界惩罚
```

分数越低，速度越适合当前帧。

## 目标偏差惩罚

agent 不能为了避障完全忘记目标。

如果候选速度和期望速度差得很远，就加惩罚：

```text
goalPenalty = |candidate - preferred|²
```

这个项越大，agent 越倾向继续朝目标走。

## 速度平滑惩罚

如果每帧都选一个差异很大的速度，视觉上会抖。

所以学习版会惩罚候选速度和上一帧速度的差异：

```text
smoothPenalty = |candidate - lastVelocity|²
```

这个项越大，运动越平滑，但反应也可能变慢。

## 当前重叠惩罚

如果两个 agent 当前已经重叠，必须强烈惩罚继续贴近的速度。

学习版会计算：

```text
当前距离 - 两者半径和
```

如果小于 0，说明已经重叠。重叠越深，惩罚越高。

这个项主要用来处理初始生成过密、或上一帧已经挤在一起的情况。

## 预测碰撞惩罚

只看当前距离不够。两个 agent 现在很远，但如果高速对冲，很快也会撞。

学习版会估算候选速度下的最近接近时刻：

```text
relativePosition = otherPosition - selfPosition
relativeVelocity = candidateVelocity - otherVelocity
closestTime = clamp(-dot(relativePosition, relativeVelocity) / |relativeVelocity|², 0, timeHorizon)
```

然后计算在 `closestTime` 时两者距离是否小于安全半径。

如果预测未来会撞，就加惩罚；越快撞、越深撞，惩罚越高。

这一步是学习版最接近 RVO 思想的地方：它不只问“现在近不近”，而是问“这个速度会不会导致未来碰撞”。

## 边界惩罚

benchmark 有 arena 半径。候选速度如果把 agent 推向边界外，就加惩罚。

这能减少 agent 因避障一路逃出场地边缘，然后被 `BenchmarkAgent.Integrate` 夹回边界导致的异常运动。

## 每帧流程

学习版每帧流程是：

1. adapter 收集每个 agent 的期望速度。
2. 构建空间哈希。
3. 对每个 agent 生成候选速度。
4. 对候选速度逐个打分。
5. 选择最低分速度。
6. 写回 `BenchmarkAgent.ApplyVelocity`。
7. benchmark 统一积分移动。

## 优点

- 完全自写，许可证清晰。
- 很容易读懂和调参。
- 可以快速增加新的评分项。
- 可以观察每个启发式对结果的影响。
- 适合作为自研算法实验起点。

## 局限

- 不保证无碰撞。
- 候选速度数量有限，可能错过真正好速度。
- 权重依赖场景，换场景可能需要重新调。
- 高密度时仍可能局部最优或互相卡住。
- 当前实现是 CPU 主线程版本，还没有 Job/Burst 优化。
- 它是启发式算法，不是完整 ORCA。

## 和 RVO2 的区别

| 维度 | RVO2 / ORCA | 采样避障学习版 |
| --- | --- | --- |
| 核心方法 | 速度空间半平面约束求解 | 候选速度打分 |
| 理论性 | 更强 | 较弱 |
| 可解释性 | 数学清晰，但实现复杂 | 每个评分项直接可读 |
| 可调性 | 参数较少但影响大 | 权重和候选集都可改 |
| 无碰撞保证 | 更接近可证明安全 | 不保证 |
| 学习价值 | 学习速度障碍理论 | 学习工程化评分和调参 |

## 和 NavMesh 的区别

| 维度 | Unity NavMeshAgent | 采样避障学习版 |
| --- | --- | --- |
| 主要目标 | 地图导航和路径跟随 | 局部动态避障 |
| 地图理解 | 有 NavMesh 可达性 | 没有地图理解 |
| 动态群体 | 可做但不是最专门 | 专门面向局部邻居 |
| 3D 体积 | 主要平面 | 当前也主要平面，可扩展 |
| 可改性 | 内部黑盒较多 | 完全可改 |

## 后续改进方向

这个学习版后续可以逐步升级：

- 增加候选速度自适应采样，而不是固定 16 方向。
- 把邻居风险按距离、相对速度、角色类型加权。
- 引入最大加速度和最大转向角约束。
- 增加“右侧通行/左侧通行”偏置，减少对称死锁。
- 增加队形或鱼群凝聚项。
- 使用 Job System / Burst 优化空间哈希和评分。
- 把评分函数输出到调试 HUD，观察每项惩罚占比。
- 借鉴 RVO2，把明显危险的速度直接剔除，再对剩余速度打分。

## 对自研算法的启发

如果要写更好的 FishROV 避障算法，可以把学习版当成骨架：

```text
目标速度
  -> 候选速度生成
  -> 风险预测
  -> 多目标评分
  -> 速度平滑和运动约束
```

后续真正要优化的，是三个核心点：

- 更准确的风险函数。
- 更聪明的候选速度生成。
- 更稳定的冲突解除策略。
