# 动画碰撞报告计数逐次递增问题分析与建议（归档）

更新时间：2025-09-02
状态：已定位问题根因，建议采取“生成侧生命周期控制（方案B）”；暂不改代码，仅归档待实施。

## 1. 问题概述

在“碰撞报告”中，“动画测试”的数字会随着每次动画运行不断增加，而其他（权威/静态）碰撞数字保持不变。这与用户观察一致：Clash Detective 的既有测试结果不变，唯独“动画相关”的计数递增。

## 2. 复现与现象

- 连续播放同一动画多次后，“碰撞报告”中“动画测试数量”与“动画相关碰撞汇总”呈单调递增。
- 打开 Clash Detective 面板，可看到多组名称包含“动画路径碰撞”或“动画碰撞”的测试，越跑越多。
- 若在一次或多次“停止（未完成）→再次开始→完成”的使用路径下，最终一次完成后计数更大。

## 3. 根因分析（直接原因）

1) 报告统计口径累积（历史所有动画测试合并统计）
   - 文件：src/Commands/ViewCollisionReportCommand.cs
   - 方法：CollectAllCollisionData()
   - 逻辑：把 DisplayName 包含“动画路径碰撞”的所有测试计入统计（历史全量），而不是仅统计“本次运行”。因此报告端数字随历史累加而递增。

2) 生成侧每次动画结束都会“新增”一批动画测试，未清理旧测试
   - 文件：src/Core/Collision/ClashDetectiveIntegration.cs
   - 方法：CreateAllAnimationCollisionTests(...)
   - 逻辑：为（去重后的）碰撞对逐一创建新测试，测试命名如“动画路径碰撞_{编号}_{时间}”。旧测试不清理，文档内逐轮叠加；报告端再合并统计，自然越来越多。

3) 辅助触发（条件）：停止不清缓存导致跨次累计
   - 文件：src/Core/Animation/PathAnimationManager.cs
   - StopAnimation()：只停定时器，不清 ClashDetectiveIntegration 的 _cachedResults 等运行期缓存。
   - FinishAnimation()：完成时才调用 CreateAllAnimationCollisionTests(...) 并最终 _cachedResults.Clear()。
   - 若多次“停止→重播→完成”，最后一次会把之前若干次积累的缓存一并写入测试，放大一次性计数。

4) 次要风险：动态碰撞事件重复订阅
   - 文件：src/Core/Animation/PathAnimationManager.cs
   - 方法：SetupDynamicClashDetection()
   - 每次 StartAnimation 都执行 `CollisionDetected += ...`，未见对称 `-=` 解绑。会造成事件回调倍增，放大 UI “发现N个碰撞”的提示频率与日志量（虽对最终权威计数影响有限，但体验上加剧“变多”的观感）。

## 4. 影响范围

- 仅影响“动画相关”的碰撞测试与报告统计；既有的固定/权威测试不受影响（名称筛选不同）。
- 主要是展示与统计口径问题，非算法错误；静态 Clash Detective 的数量维持不变。

## 5. 临时规避建议（无需改代码）

- 每次生成报告前，手动删除 Clash Detective 列表中名称包含“动画路径碰撞/动画碰撞”的历史测试，只保留本次运行生成的测试，再生成报告。

## 6. 解决思路（选择B：生成侧生命周期控制）

目标：每次动画“开始前”清理历史动画测试与运行期缓存，确保“碰撞报告”只统计“本次运行”生成的动画测试。

建议在不改变对外功能的前提下，最小增量实现：

A) 在 ClashDetectiveIntegration 中新增两个方法（仅归档待实现）

- RemoveAnimationGeneratedTests(params string[] nameKeywords)
  - 遍历 `_documentClash.TestsData.Tests`，删除 DisplayName 含任一关键字（如“动画路径碰撞”“动画碰撞”）的测试。
- ClearAnimationRuntimeCache()
  - 清空 `_cachedResults`、`_currentCollisions`、`_animationCollisionCount` 等“动画运行期”缓存（不动 `_documentClash/_dynamicClashTest` 等重对象）。

B) 在 PathAnimationManager.StartAnimation() 的最前面调用上述清理

- 开播前执行：
  - `ClashDetectiveIntegration.Instance.RemoveAnimationGeneratedTests("动画路径碰撞", "动画碰撞");`
  - `ClashDetectiveIntegration.Instance.ClearAnimationRuntimeCache();`
- 确保每次新一轮动画从“干净环境”起步。

C) 事件订阅去重与解绑（易实施，强烈建议纳入）

- 在 PathAnimationManager 中增加 `_isClashSubscribed` 标志，避免重复 `+=`；在 StopAnimation()/Dispose 中成对 `-=` 解绑。

D) 可选增强（非必须，后续考虑）

- 为本次运行引入 `runId` 或统一前缀（如“动画路径碰撞_ACTIVE”），以覆盖而非追加；或仅保留最近 N 轮测试，按需清理历史。

## 7. 验证清单（实施后建议回归）

- 连续完整播放同一动画两次，报告中的“动画测试数量/碰撞总数”应一致，不随历史递增。
- 执行一次“停止→再开始→完成”，最终结果不应包含停止阶段产生的历史缓存。
- 日志中在 StartAnimation 之前应出现“已清理历史动画测试/已清理动画运行期缓存”的记录。
- 检查回调是否重复：多次 Start/Stop 后，碰撞事件回调触发次数不应递增。

## 8. 风险与注意事项

- 清理逻辑只应作用于“动画生成的测试”，避免误删用户手工维护的权威测试。通过名称关键字白名单控制（例如：仅匹配“动画路径碰撞”“动画碰撞”前缀）。
- 如果项目需要保留历史动画测试用于比对，应在实现中提供开关或“保留最近N轮”的策略。
- 清缓存应仅限运行期缓存，不应重置文档级对象或用户手工结果。

## 9. 相关代码位置（便于后续实现/评审）

- 报告端统计：
  - src/Commands/ViewCollisionReportCommand.cs → CollectAllCollisionData()（基于 DisplayName 包含“动画路径碰撞”的测试统计）
- 生成端创建动画测试：
  - src/Core/Collision/ClashDetectiveIntegration.cs → CreateAllAnimationCollisionTests(...)
- 动画控制与订阅：
  - src/Core/Animation/PathAnimationManager.cs → StartAnimation()/StopAnimation()/SetupDynamicClashDetection()

## 10. 结论

问题本质是“统计口径=历史累积”叠加“生成侧每轮追加不清理”。采用方案B（生成侧生命周期控制），在每次开播前清理“动画生成的测试”和“运行期缓存”，并完善事件订阅的生命周期管理，可使“碰撞报告”的动画测试数字与本轮真实结果一致，不再随历史递增。
