📺 Demo 视频(Bilibili) (旧版)
基于 Unity DOTS(ECS + Jobs + Burst)的大规模 RTS 群体模拟系统。以 RTS 高密度单位移动作为实际压力测试场景,自下而上实现从玩法指令到物理求解的完整管线:
玩法指令 → 流场寻路 → 预测接触分类 → 软避让 → XPBD 约束求解 → ECS 写回
以共享网格流场替代逐单位 A* 查询,当前采用确定性的 8 邻域 BFS:
- Physics
CollisionWorld并行采样网格,生成障碍 / 可行走二值 Cost Field - 队列 BFS 从目标格向外生成 Integration Field,再并行选取最低积分邻格,形成 8 方向 Vector Field
- 单位通过连续数组 O(1) 查询当前格方向,并由 Burst
IJobEntity并行生成移动意图 - 接近目标后切换到单位专属槽位的直接驶入,结合减速距离与到达状态滞回,避免终点附近反复抖动
Grid / PendingGrid双缓冲异步烘焙;目标变化只刷新 Integration / Vector,障碍变化时才重新采样 Cost,发布前单位继续读取上一份完整快照
5k 单位移动模拟:展示 5,000 个单位在障碍场景中的流场寻路、群体避让与接触求解效果。
针对 RTS 场景中相邻帧接触拓扑高度相干的特点,维护跨帧持久候选状态,只对变化的"脏 body"进行增量修补。
持久拓扑:
StableEntityPairKey驱动实体对生命周期:Dormant → Approaching → Predictive → Actual → Separating → ExpiredPersistentSweptProxy以 Guard Bounds 证明候选集拓扑完备性NativeHashMap<StableEntityPairKey, PersistentPredictiveContact>提供 O(1) 持久接触查找,消除 sort + binary search 热路径
增量修补决策:
- 每帧验证代理有效 → 标记脏体(拓扑脏 / 几何脏 / 逃逸)
dirtyRatio > 35%全量回退,否则增量修补脏 body 的邻居对- 软避让输出强制钳位在已证明的 Interaction Envelope 内;逃逸时二分搜索最大安全缩放因子
独立验证:
- O(N²) Oracle 持续检测增量管线的漏报(False Negative),
RTS_CONTACT_DIAGNOSTICS模式下漏报计数必须为零
1k 单位 — Substep 缓存关闭 / 开启对比:
实测结果: 在 1,000 单位开阔往返的高密度持续接触场景中(4 Substeps × 4 Iterations,跨帧缓存关闭),每种配置独立采样 2 次、每次 1,200 帧。仅启用 Substep 接触集缓存后:
指标(每帧均值) 缓存关闭 缓存开启 改善 整体求解管线 43.35 ms 16.19 ms -62.7%(2.68×) 接触 Pair 管线 35.37 ms 9.59 ms -72.9%(3.69×) 全量候选扫描 24.94 ms 6.98 ms -72.0%(3.57×) XPBD 迭代投影 3.94 ms 3.15 ms -19.9%(1.25×) 性能提升并非通过减少接触约束换取:平均接触 Pair 从 596 增至 721,平均活跃 Pair 从 543 增至 672。在处理更多持续接触的同时,求解总耗时仍降低 62.7%,并改善了高密度拥挤时的碰撞连续性与稳定性。
| Substep 缓存关闭 | Substep 缓存开启 |
|---|---|
![]() |
![]() |
EnableTimestepContactSetCache 开启后,首个子步完成接触分类并缓存完整 TimestepContactPairs 视图;后续子步直接复用,避免每子步重跑 Swept Disc BroadPhase + 分类。
当单位轨迹偏出 Guard Envelope(包络逃逸)时,Certifier 对受影响 body 执行增量修复(Incremental Repair):仅重分类脏 body 的邻居对,未受影响的接触对保持不变。脏比例超阈值或修复失败时回退全量重建。
EnablePersistentContactCache 进一步跨 timestep 保留接触生命周期与激活时序,使 Dormant 接触在预计到达子步时直接激活,无需每帧从零分类。
- 软分离(Soft Avoidance): 支持 Surface Velocity Buffer 与 RVO 两种模式,消耗紧凑 Soft 视图(非全量邻居)
- 硬约束投影(Hard Constraint): XPBD 位置投影修正穿透,含 Compliance 柔度控制,支持 Regular 与 Predictive 两种接触模式
- 墙壁约束: 基于流场格阻挡的静态墙壁投影,防止单位穿入障碍格
- 零快照: 仅录制关键输入指令(Command Buffer),不存储每帧 Transform
- 瞬间重置: 利用 ECS 结构特性,毫秒级状态回滚与指令重演
- 按
L开始录制,按R开始回放
- 基于 Unity NetCode for Entities,服务端权威 + 客户端预测
NetCodeUnitFlowMovementSystem(联网)与LocalUnitFlowMovementSystem(本地)共享同一BaseFlowMovementSystem调度逻辑
Runtime/ContactPipeline/
├── Contracts/
│ ├── Body/ # 单 timestep body 数据产品
│ ├── Certification/ # InteractionCertificate、违规类型
│ ├── Execution/ # ContactPipelineConfiguration(不可变快照)
│ └── Interaction/ # BodyPair, ContactConstraint, 代理/调度条目
├── State/
│ ├── Persistent/ # 跨帧候选所有者(InteractionCandidateStore)
│ └── Frame/ # 帧生命周期资源所有者
├── Kernels/ # 无容器共享 Burst 算法(分类器、调度器、数学)
├── Scheduling/
│ ├── CrowdContactPipelineScheduler.cs
│ └── Parallel/
│ ├── ParallelContactPipelineScheduler.cs
│ └── Jobs/ # 可执行并行 Job(Jacobi / 逃逸计数 / Scatter / Gather)
├── Stages/
│ ├── Certification/ # BroadPhase / Persistent / Prediction / Validation
│ ├── Lifecycle/
│ ├── SoftAvoidance/
│ ├── Motion/
│ └── Solver/ # XPBD(Gauss-Seidel / Jacobi)、墙壁、CSR Incident Index
│ └── Observability/ # 编译期诊断捕获(RTS_CONTACT_DIAGNOSTICS)
└── Observability/
└── Contracts/ # 观测数据 ABI,不参与正确性
玩法指令(UnitMoveInputSystem)
│ 框选 → MoveOrder
▼
RtsCommandSystem — 编队槽位分配 → UnitMoveDestination
│
▼
FlowFieldBakeSystem — Cost → Integration → Vector(按需重烘焙)
│
▼
BaseFlowMovementSystem(每帧)
├─ [初始化] CalculateIndependentFlowForceJob
├─ [认证] IncrementalPredictiveContactPipeline
│ ↳ 持久拓扑验证 / 增量修补 / 全量回退
│ ↳ InteractionCertificate 签发,下游消费受证书守护
└─ for each substep
├─ [SoftAvoidance] RVO / 速度缓冲
├─ [Motion] 速度整合 → 预测位置
└─ for each iteration
├─ [Wall] 墙壁约束投影
└─ [Contact] XPBD pair 评估 → body gather
└─ ApplyFlowMovementJob — Transform + Velocity 写回 ECS
架构约束(CI 强制执行):
BaseFlowMovementSystem是唯一组合根,不实现分类、证书、求解器或诊断算法- 持久候选状态仅 Certifier 可写;SoftAvoidance / Motion / Solver 只消费已签发的认证视图
RTS_CONTACT_DIAGNOSTICS关闭时零额外 NativeContainer、零额外 Job、零 Profiler 读取- Oracle 可观测但不可改变候选状态或签发证书
5k 单位同屏运行:
| 工具 | 入口 | 功能 |
|---|---|---|
| SimulationDebuggerPanel | F8 开关 |
IMGUI 面板:概况 / 接触分类 / 增量统计 / 运行时参数覆盖 |
| CSV 录制 | F6 开始/停止,F7 重置录制 |
按帧输出接触统计 CSV,用于参数调优分析 |
| Validate Incremental Predictive Contact Pipeline | RTS/Diagnostics/Validate… |
运行增量管线合规验证 |
| Incremental Contact Benchmark Tuner | RTS/Diagnostics/Incremental Contact Benchmark Tuner |
自动参数搜索 + CSV 结果对比 |
| Incremental Contact Pipeline | RTS/Diagnostics/Incremental Contact Pipeline |
增量管线指标实时监控 |
| Select Build Settings | RTS/Diagnostics/Select Build Settings |
切换 RTS_CONTACT_DIAGNOSTICS 编译开关 |
| Local Gameplay Mode Validation | RTS/Validation/Local Gameplay Mode |
本地模式功能验证 |
RTS_CONTACT_DIAGNOSTICS 关闭时,所有诊断路径由预处理器移除;仿真正确性(证书、逃逸修复、全量回退)不受影响。
.github/workflows/ 四条 Python 脚本在每次 push 时静态检查:
| 脚本 | 检查内容 |
|---|---|
validate_contact_architecture.py |
层所有权;禁止历史 Jobs/ContactPipeline 布局回归 |
validate_contact_diagnostics.py |
诊断关闭合约;零额外 container / job / profiler |
validate_contact_pipeline_audit.py |
禁止 aggregate bag;调度器不可实现算法 |
validate_contact_static_contracts.py |
调度步骤身份不可从缓存 generation 派生;Oracle 不写游戏状态 |
CI 不替代 Unity Editor 编译、Burst 编译、Collections Safety 和运行时性能验证。
- Contact Island 休眠未实现——持续活跃接触始终参与求解
- Gauss-Seidel 无并行路径(需图着色或冲突无关批次)
- 持久 Spatial Membership 依赖容量上限,超限回退全量扫描
- 流场为全局烘焙,未支持动态障碍局部增量更新



