# A Pro VelocityLike Demo 推进文档

## 当前决策

新的表现 demo 建议先采用：

- 主后端：`AstarProRvoVelocityLikeAdapter`
- 计算维度：`XZ2D`
- 输入语义：业务层只输出 `preferredVelocity`
- 避障语义：adapter 内部把 `preferredVelocity` 映射成 A* Pro RVO 的近目标
- 保留对照：`Rvo2Adapter`、`AstarProRvoAdapter`、`NoAvoidanceAdapter`

这个选择不是因为 VelocityLike 已经解决了所有重叠问题，而是因为它把输入语义控制住了。后续如果要调表现，问题会更容易归因到参数、场景密度、鱼饵吸引力或 A Pro RVO 本身，而不是混在“远目标接法”里。

## 依据

Android 百元机复测中，A Pro 路线在 500 鱼以上已经表现出稳定性能优势：

- `BaitScramble / 500`：VelocityLike 相对 RVO2，FPS 约 `+13.0%`，simulation ms 约 `-25.4%`
- `BaitScramble / 800`：VelocityLike 相对 RVO2，FPS 约 `+14.1%`，simulation ms 约 `-20.7%`
- `CrossFlow / 500`：VelocityLike 相对 RVO2，FPS 约 `+42.0%`
- `DenseCircleStress / 800`：VelocityLike 相对 RVO2，simulation ms 约 `-34.3%`，重叠约 `-9.8%`

同时，避障质量还没有完全达标：

- `BaitScramble / 300-800` 中，VelocityLike 的重叠数量通常高于 RVO2
- `DenseCircleStress / 500` 是当前风险最高样本，VelocityLike 重叠约为 RVO2 的两倍
- VelocityLike 只能证明“输入语义更干净”，不能单独证明 A Pro 的参数已经合适

因此，后续目标应从“继续证明性能路线”切换为“在真实 demo 中调表现”。

## 新 Demo 接入边界

### 业务层只能依赖的概念

业务或玩法代码只应该依赖这些概念：

- 鱼当前位置
- 鱼目标方向
- 期望速度 `preferredVelocity`
- 最大速度
- 碰撞/拥挤半径
- 鱼群或鱼饵行为状态

业务层不应该直接调用：

- `SimulatorBurst`
- A Pro `IAgent.SetTarget`
- A Pro `CalculatedTargetPoint`
- A Pro `CalculatedSpeed`
- RVO2-CS simulator API

这些后端 API 必须继续封装在 adapter 里。

### 推荐接口形态

新 demo 可以沿用现有 benchmark 思路，保持类似边界：

```csharp
public interface IFishAvoidanceAdapter
{
    void Initialize(FishAvoidanceProfile profile);
    FishAvoidanceHandle CreateAgent(FishAgentSpawnInfo spawnInfo);
    void SetPreferredVelocity(FishAvoidanceHandle handle, Vector3 preferredVelocity);
    Vector3 TickAndGetResolvedVelocity(FishAvoidanceHandle handle, float deltaTime);
    void RemoveAgent(FishAvoidanceHandle handle);
}
```

如果 demo 已经有自己的鱼控制器，不一定要完全照搬这个接口，但要保持同样原则：业务给“期望速度”，adapter 给“避障后速度”。

## 第一阶段目标

第一阶段只做可用表现，不追求极限压测漂亮。

优先覆盖：

- 300 鱼：表现自然，不卡顿
- 500 鱼：百元机可接受，鱼饵争抢不明显穿模
- 800 鱼：可作为上限压力，但不要求所有场景完美

暂时不要让 `DenseCircleStress` 主导所有调参。它适合作为红线检查，不适合作为真实玩法的唯一目标。

## 参数调优顺序

每次只改一个变量，每次保留一组截图、视频或 CSV。

### 1. 先调场景输入

优先调这些，因为它们直接决定鱼是否被强行挤到一起：

- 鱼饵吸引力
- 鱼饵中心收缩半径
- 到达鱼饵后的减速曲线
- 鱼之间的目标方向扰动
- 最大速度和加速度上限

建议先让鱼饵争抢不要持续把所有鱼压进同一个点。可以改成：

- 靠近鱼饵后转为环绕
- 每条鱼有不同停靠半径
- 接近中心后降低 `preferredVelocity`
- 给鱼饵点周围加切向速度

### 2. 再调 A Pro RVO 参数

推荐按这个顺序试：

| 参数 | 当前倾向 | 试验值 |
| --- | --- | --- |
| `MaxNeighbours` | 8 | 12 / 16 |
| `AgentTimeHorizon` | 2.5 | 3.5 / 4.5 |
| `ObstacleTimeHorizon` | 2.5 | 3.5 / 4.5 |
| agent radius | 当前鱼半径 | 视觉半径的 0.8 / 1.0 / 1.2 |
| priority | 0.2 | 按鱼状态分层 |

注意：`MaxNeighbours` 和 `TimeHorizon` 可能改善质量，也可能增加 CPU 成本。每次调整都要上百元机确认。

### 3. 最后调视觉后处理

避障速度算出来之后，可以再加表现层平滑：

- 转向平滑
- 加速度限制
- 动画朝向插值
- 短距离分离修正
- 模型之间的视觉避让偏移

这层只解决“看起来舒服”，不要用它掩盖严重重叠。

## 建议的 Demo 调试样本

不要再全量扫所有组合。真实 demo 推进时固定这几组：

| 场景 | 鱼数 | 用途 |
| --- | ---: | --- |
| 鱼饵争抢 | 300 | 基础表现 |
| 鱼饵争抢 | 500 | 主要目标 |
| 鱼饵争抢 | 800 | 高压上限 |
| 对向穿流 | 500 | 正面对冲检查 |
| 圆阵高压 | 500 | 红线检查 |

每组建议至少跑 20 秒，排除 `timeSeconds=0` 的启动样本。

## 验收标准

第一版 demo 可以按这个标准判断是否可继续：

- 百元机 500 鱼：平均 FPS 不低于 RVO2，simulation ms 明显低于 RVO2
- 百元机 500 鱼：鱼饵争抢没有大面积持续穿模
- 300 鱼：鱼群运动自然，不出现明显卡顿、抽搐、急停
- 800 鱼：允许轻微拥挤，但不能长时间塌缩成一个点
- 圆阵高压 500：作为红线，如果重叠特别高，需要记录但不一定阻止 demo 推进

如果真实玩法主要是鱼饵争抢，`BaitScramble / 500` 的表现权重应高于 `DenseCircleStress`。

## 回退与替换成本

只要继续保持 adapter 隔离，后续更换成本不高。

低成本回退：

- 切回 `Rvo2Adapter`
- 切回旧 `AstarProRvoAdapter`
- 新增另一个 A Pro adapter
- 保留 VelocityLike 但换参数 profile

中等成本替换：

- 换另一个本地避障库
- 自己实现一个新的 CPU 求解器
- 引入 ECS/Job 化的自研求解器

高成本替换：

- 业务层直接依赖 A Pro API
- 场景逻辑专门迎合 A Pro 远目标行为
- 鱼控制器和避障求解器写死在一起
- 动画、目标、避障、碰撞统计共用同一套不可拆逻辑

因此，后续 demo 中最重要的工程原则是：不要让 A Pro API 泄漏到玩法层。

## 推荐落地步骤

1. 在新 demo 中接入 `AstarProRvoVelocityLikeAdapter` 或同语义 adapter。
2. 建一个 `FishAvoidanceProfile`，集中放 `MaxNeighbours`、`TimeHorizon`、半径、优先级等参数。
3. 让鱼控制器只输出 `preferredVelocity`，不要直接设置 A Pro target。
4. 先跑 300 鱼，确认视觉自然。
5. 再跑 500 鱼鱼饵争抢，把鱼饵吸引力和停靠半径调到不塌缩。
6. 上百元机跑 500 鱼，记录 FPS、simulation ms、重叠和视频表现。
7. 只在真实表现仍不行时，再调 `MaxNeighbours` 和 `TimeHorizon`。
8. 保留 RVO2 一键切换，作为长期回归对照。

## 当前结论

可以开始在另一个 demo 里推进具体表现了。

建议主线是：

```text
A Pro VelocityLike + XZ2D + adapter 隔离 + profile 参数化
```

不要继续把时间花在证明 A Pro 是否有性能优势上。现在更有价值的是把真实玩法中的鱼饵吸引、停靠半径、速度曲线和 RVO 参数一起调到“看起来对”。
