第6章 计算子系统设计
本章描述三条主计算链路在脉冲内的组织方式。各链路所用的具体物理模型与公式详见分析报告第 4、5 章,此处只讨论其调用结构与数据流。
三条链路(探测、交战、毁伤)共享同一设计哲学:把高代价计算后置,用低代价判据先行排除 ,并遵循实体与模型分离的原则------编排与状态在实体侧,物理求解在无状态静态模型类中。6.4 节将给出表现层与计算层的一致性约束,6.5 节则对全章进行统一小结,帮助读者在进入细节前先建立整体框架。
TL;DR :三条链路(探测、交战、毁伤)共享同一设计哲学------高代价计算后置,用低代价判据先行排除 ,并遵循实体与模型分离 、表现层与计算层一致性两大原则。6.1 探测链路用五级门限压缩候选集;6.2 交战链路用包线校验过滤目标;6.3 毁伤链路用半径扫描限定作用域;6.4 给出表现层复用计算层函数的一致性约束;6.5 对全章进行统一小结。
6.1 探测链路
探测链路的组织原则是分级快速排除:把计算代价由低到高的判据依次前置,使绝大多数"传感器---目标"组合在进入昂贵的物理求解之前即被淘汰(B 级)。
对每个 (Sensor, Target) 组合,按代价递增顺序判定:
#mermaid-svg-0CjnHVHy1pofBTDj{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0CjnHVHy1pofBTDj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0CjnHVHy1pofBTDj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0CjnHVHy1pofBTDj .error-icon{fill:#552222;}#mermaid-svg-0CjnHVHy1pofBTDj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0CjnHVHy1pofBTDj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0CjnHVHy1pofBTDj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0CjnHVHy1pofBTDj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0CjnHVHy1pofBTDj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0CjnHVHy1pofBTDj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0CjnHVHy1pofBTDj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0CjnHVHy1pofBTDj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0CjnHVHy1pofBTDj .marker.cross{stroke:#333333;}#mermaid-svg-0CjnHVHy1pofBTDj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0CjnHVHy1pofBTDj p{margin:0;}#mermaid-svg-0CjnHVHy1pofBTDj .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-0CjnHVHy1pofBTDj .cluster-label text{fill:#333;}#mermaid-svg-0CjnHVHy1pofBTDj .cluster-label span{color:#333;}#mermaid-svg-0CjnHVHy1pofBTDj .cluster-label span p{background-color:transparent;}#mermaid-svg-0CjnHVHy1pofBTDj .label text,#mermaid-svg-0CjnHVHy1pofBTDj span{fill:#333;color:#333;}#mermaid-svg-0CjnHVHy1pofBTDj .node rect,#mermaid-svg-0CjnHVHy1pofBTDj .node circle,#mermaid-svg-0CjnHVHy1pofBTDj .node ellipse,#mermaid-svg-0CjnHVHy1pofBTDj .node polygon,#mermaid-svg-0CjnHVHy1pofBTDj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0CjnHVHy1pofBTDj .rough-node .label text,#mermaid-svg-0CjnHVHy1pofBTDj .node .label text,#mermaid-svg-0CjnHVHy1pofBTDj .image-shape .label,#mermaid-svg-0CjnHVHy1pofBTDj .icon-shape .label{text-anchor:middle;}#mermaid-svg-0CjnHVHy1pofBTDj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-0CjnHVHy1pofBTDj .rough-node .label,#mermaid-svg-0CjnHVHy1pofBTDj .node .label,#mermaid-svg-0CjnHVHy1pofBTDj .image-shape .label,#mermaid-svg-0CjnHVHy1pofBTDj .icon-shape .label{text-align:center;}#mermaid-svg-0CjnHVHy1pofBTDj .node.clickable{cursor:pointer;}#mermaid-svg-0CjnHVHy1pofBTDj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-0CjnHVHy1pofBTDj .arrowheadPath{fill:#333333;}#mermaid-svg-0CjnHVHy1pofBTDj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0CjnHVHy1pofBTDj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0CjnHVHy1pofBTDj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0CjnHVHy1pofBTDj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-0CjnHVHy1pofBTDj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0CjnHVHy1pofBTDj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-0CjnHVHy1pofBTDj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0CjnHVHy1pofBTDj .cluster text{fill:#333;}#mermaid-svg-0CjnHVHy1pofBTDj .cluster span{color:#333;}#mermaid-svg-0CjnHVHy1pofBTDj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-0CjnHVHy1pofBTDj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0CjnHVHy1pofBTDj rect.text{fill:none;stroke-width:0;}#mermaid-svg-0CjnHVHy1pofBTDj .icon-shape,#mermaid-svg-0CjnHVHy1pofBTDj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0CjnHVHy1pofBTDj .icon-shape p,#mermaid-svg-0CjnHVHy1pofBTDj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-0CjnHVHy1pofBTDj .icon-shape .label rect,#mermaid-svg-0CjnHVHy1pofBTDj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0CjnHVHy1pofBTDj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0CjnHVHy1pofBTDj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0CjnHVHy1pofBTDj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否 → 淘汰
是
否 → 淘汰
是
否 → 淘汰
是
信噪比不足 → 淘汰
是
未中 → 本脉冲不发现
命中
① 状态门:传感器开机?EMCON 限制?目标在本域内?
淘汰
② 几何门:距离/方位/俯仰扫描范围
③ 视线门:Horizon 遮蔽 / LOS 地形采样
④ 物理门:雷达/声呐/红外/目视求解
⑤ 概率门:按探测概率抽取随机数
下一脉冲重试
⑥ 接触生成/更新:写入 Side.Contacts
下面用 C# 伪代码展示五级门限的判定顺序与提前 return 的写法。每一级都以最廉价的判据先行排除,命中才进入下一级,从而把昂贵的物理求解(④)留给极小候选集:
csharp
// 五级门限:按代价递增顺序判定,任一级不满足即提前 return(淘汰)
// 返回 null 表示本脉冲不发现;返回 Contact 表示生成/更新接触
Contact? EvaluateDetection(Sensor sensor, Target target)
{
// ① 状态门 ------ 数次布尔判读,纳秒级
// 淘汰条件:传感器未开机 / EMCON 限制 / 目标不在本域内
if (!sensor.IsPoweredOn) return null;
if (sensor.EmconRestricted) return null;
if (!sensor.IsTargetInDomain(target)) return null;
// ② 几何门 ------ 一次大圆距离计算,微秒级
// 淘汰条件:超出最大作用距离 / 方位·俯仰超出扫描范围
double range = GreatCircleDistance(sensor.Position, target.Position);
if (range > sensor.MaxRange) return null;
if (!sensor.WithinScanCone(target)) return null;
// ③ 视线门 ------ Horizon 闭式解;LOS 需地形采样,微秒~毫秒级
// 淘汰条件:被地球曲率遮蔽(Horizon)/ 被地形遮挡(LOS 采样)
if (HorizonBlocks(sensor, target)) return null;
if (TerrainLosSampling(sensor, target) == LosResult.Blocked) return null;
// ④ 物理门 ------ 雷达/声呐/红外/目视方程求解,毫秒级(最高)
// 淘汰条件:信噪比不足(此时候选集已被前三级压缩到很小)
double snr = SolvePhysics(sensor, target); // RadarModel / SonarModel / ...
if (snr < sensor.RequiredSnr) return null;
// ⑤ 概率门 ------ 一次随机数抽取,纳秒级
// 淘汰条件:按探测概率抽取未中 → 本脉冲不发现,下一脉冲重试
double pDetect = DetectionProbability(sensor, target, snr);
if (Random.Shared.NextDouble() > pDetect) return null;
// 全部通过 → 生成/更新 Contact,写入 Side.Contacts
return CreateOrUpdateContact(sensor, target);
}
下面用 Mermaid 时序图展示 EvaluateDetection 在单个脉冲内对 (Sensor, Target) 组合的调用顺序。五级门限依次执行,任一级不满足即提前 return null 退出;只有全部通过才进入 CreateOrUpdateContact 写入 Side.Contacts:
Side.Contacts Target Sensor EvaluateDetection 脉冲循环 Side.Contacts Target Sensor EvaluateDetection 脉冲循环 #mermaid-svg-bCIga20lrvAjrgIJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-bCIga20lrvAjrgIJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-bCIga20lrvAjrgIJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-bCIga20lrvAjrgIJ .error-icon{fill:#552222;}#mermaid-svg-bCIga20lrvAjrgIJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-bCIga20lrvAjrgIJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-bCIga20lrvAjrgIJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-bCIga20lrvAjrgIJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-bCIga20lrvAjrgIJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-bCIga20lrvAjrgIJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-bCIga20lrvAjrgIJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-bCIga20lrvAjrgIJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-bCIga20lrvAjrgIJ .marker.cross{stroke:#333333;}#mermaid-svg-bCIga20lrvAjrgIJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-bCIga20lrvAjrgIJ p{margin:0;}#mermaid-svg-bCIga20lrvAjrgIJ .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-bCIga20lrvAjrgIJ text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-bCIga20lrvAjrgIJ .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-bCIga20lrvAjrgIJ .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-bCIga20lrvAjrgIJ .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-bCIga20lrvAjrgIJ .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-bCIga20lrvAjrgIJ #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-bCIga20lrvAjrgIJ .sequenceNumber{fill:white;}#mermaid-svg-bCIga20lrvAjrgIJ #sequencenumber{fill:#333;}#mermaid-svg-bCIga20lrvAjrgIJ #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-bCIga20lrvAjrgIJ .messageText{fill:#333;stroke:none;}#mermaid-svg-bCIga20lrvAjrgIJ .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-bCIga20lrvAjrgIJ .labelText,#mermaid-svg-bCIga20lrvAjrgIJ .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-bCIga20lrvAjrgIJ .loopText,#mermaid-svg-bCIga20lrvAjrgIJ .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-bCIga20lrvAjrgIJ .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-bCIga20lrvAjrgIJ .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-bCIga20lrvAjrgIJ .noteText,#mermaid-svg-bCIga20lrvAjrgIJ .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-bCIga20lrvAjrgIJ .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-bCIga20lrvAjrgIJ .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-bCIga20lrvAjrgIJ .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-bCIga20lrvAjrgIJ .actorPopupMenu{position:absolute;}#mermaid-svg-bCIga20lrvAjrgIJ .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-bCIga20lrvAjrgIJ .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-bCIga20lrvAjrgIJ .actor-man circle,#mermaid-svg-bCIga20lrvAjrgIJ line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-bCIga20lrvAjrgIJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} alt未中命中 alt信噪比不足通过 alt被遮蔽/遮挡通过 alt超出距离/扫描范围通过 alt任一不满足全部通过 对 (Sensor, Target) 组合调用① 状态门:IsPoweredOn / EmconRestricted / IsTargetInDomainreturn null(本脉冲不发现)② 几何门:GreatCircleDistance + WithinScanConereturn null(淘汰)③ 视线门:HorizonBlocks + TerrainLosSamplingreturn null(淘汰)④ 物理门:SolvePhysics(RadarModel 等)return null(淘汰)⑤ 概率门:DetectionProbability + 随机抽取return null(本脉冲不发现,下一脉冲重试)⑥ CreateOrUpdateContact 写入 Side.Contacts返回 Contactreturn Contact(发现)
这张时序图把 C# 伪代码中的顺序判定链映射为逐级嵌套的 alt 分支:每一级门限都先尝试廉价判据,不满足即沿提前退出路径 return null,只有通过者才继续深入下一级。前三级(状态/几何/视线)以纳秒~微秒级判据完成绝大多数淘汰,物理门(④)只面对极小候选集,概率门(⑤)以一次随机抽取收尾,最终由 CreateOrUpdateContact 把结果写入 Side.Contacts------与「分级快速排除」的设计哲学完全一致。
这段伪代码把流程图中的六个步骤(①~⑤ 门限 + ⑥ 接触生成)映射为顺序判定的 return 链:前三级以纳秒~微秒级判据快速淘汰,只有通过者才进入毫秒级的物理求解,最后以一次随机抽取完成概率门------与「分级快速排除」的设计哲学完全一致。
代价说明:① 为数次布尔判读(依赖 3.1 节的 Is* 标志位);② 为一次大圆距离计算;③ 中 Horizon 为闭式解、LOS 需地形采样(故有 5.2 节的包络快速排除与相邻栅格判定两项优化);④ 代价最高,但此时候选集已被前三级压缩到很小。
五级门限的代价与收益对比如下:
| 门限 | 计算代价 | 主要依赖函数/判据 | 典型耗时量级 | 淘汰比例 |
|---|---|---|---|---|
| ① 状态门 | 数次布尔判读 | Is* 标志位(3.1 节) | 纳秒级 | 高(大量未开机/域外组合在此被排除) |
| ② 几何门 | 一次大圆距离计算 | 距离/方位/俯仰扫描范围 | 微秒级 | 中高(超出最大作用距离的组合) |
| ③ 视线门 | Horizon 闭式解;LOS 需地形采样 | Horizon / LOS 采样(5.2 节两项优化) | 微秒~毫秒级 | 中(被地球曲率/地形遮蔽的组合) |
| ④ 物理门 | 雷达/声呐/红外/目视方程求解 | RadarModel / SonarModel / InfraredModel / VisualModel | 毫秒级(最高) | 低(候选集已被前三级压缩到很小) |
| ⑤ 概率门 | 一次随机数抽取 | 探测概率分布 | 纳秒级 | 按概率随机淘汰(未中则下一脉冲重试) |
整体收益:前三级门限以纳秒~微秒级的廉价判据,在进入毫秒级物理求解之前就排除了绝大多数"传感器---目标"组合,使昂贵的物理门只作用于极小候选集------这正是"分级快速排除"策略的核心价值所在(B 级)。
这一结构在源码中的对应证据是:ActiveUnit_Sensory.cs 达 243 KB 且含 Pre/Post Pulse 两个挂钩,而实际的物理求解集中在 RadarModel / SonarModel / InfraredModel / VisualModel 四个无状态静态类中。感知的筛选与编排在实体侧,求解在模型侧,职责分离清晰(B 级)。
探测结果不直接暴露真值,而是生成 Contact 对象。Contact 携带定位误差椭圆、分类置信度与 BDA 估计等级,在 Post-Pulse 阶段进行老化与外推(见 4.2 节)。这使信息不对称成为模型的内生属性,而非事后叠加的显示层效果------这是该引擎区别于多数商业推演软件的一处根本设计(C 级)。
6.2 交战链路
交战链路由 ActiveUnit_Weaponry(771 KB,全工程第三大文件)与 Doctrine、Mission 协同完成。
#mermaid-svg-ep8xcLEEFqmPzVfp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ep8xcLEEFqmPzVfp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ep8xcLEEFqmPzVfp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ep8xcLEEFqmPzVfp .error-icon{fill:#552222;}#mermaid-svg-ep8xcLEEFqmPzVfp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ep8xcLEEFqmPzVfp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ep8xcLEEFqmPzVfp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ep8xcLEEFqmPzVfp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ep8xcLEEFqmPzVfp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ep8xcLEEFqmPzVfp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ep8xcLEEFqmPzVfp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ep8xcLEEFqmPzVfp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ep8xcLEEFqmPzVfp .marker.cross{stroke:#333333;}#mermaid-svg-ep8xcLEEFqmPzVfp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ep8xcLEEFqmPzVfp p{margin:0;}#mermaid-svg-ep8xcLEEFqmPzVfp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ep8xcLEEFqmPzVfp .cluster-label text{fill:#333;}#mermaid-svg-ep8xcLEEFqmPzVfp .cluster-label span{color:#333;}#mermaid-svg-ep8xcLEEFqmPzVfp .cluster-label span p{background-color:transparent;}#mermaid-svg-ep8xcLEEFqmPzVfp .label text,#mermaid-svg-ep8xcLEEFqmPzVfp span{fill:#333;color:#333;}#mermaid-svg-ep8xcLEEFqmPzVfp .node rect,#mermaid-svg-ep8xcLEEFqmPzVfp .node circle,#mermaid-svg-ep8xcLEEFqmPzVfp .node ellipse,#mermaid-svg-ep8xcLEEFqmPzVfp .node polygon,#mermaid-svg-ep8xcLEEFqmPzVfp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ep8xcLEEFqmPzVfp .rough-node .label text,#mermaid-svg-ep8xcLEEFqmPzVfp .node .label text,#mermaid-svg-ep8xcLEEFqmPzVfp .image-shape .label,#mermaid-svg-ep8xcLEEFqmPzVfp .icon-shape .label{text-anchor:middle;}#mermaid-svg-ep8xcLEEFqmPzVfp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ep8xcLEEFqmPzVfp .rough-node .label,#mermaid-svg-ep8xcLEEFqmPzVfp .node .label,#mermaid-svg-ep8xcLEEFqmPzVfp .image-shape .label,#mermaid-svg-ep8xcLEEFqmPzVfp .icon-shape .label{text-align:center;}#mermaid-svg-ep8xcLEEFqmPzVfp .node.clickable{cursor:pointer;}#mermaid-svg-ep8xcLEEFqmPzVfp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ep8xcLEEFqmPzVfp .arrowheadPath{fill:#333333;}#mermaid-svg-ep8xcLEEFqmPzVfp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ep8xcLEEFqmPzVfp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ep8xcLEEFqmPzVfp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ep8xcLEEFqmPzVfp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ep8xcLEEFqmPzVfp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ep8xcLEEFqmPzVfp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ep8xcLEEFqmPzVfp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ep8xcLEEFqmPzVfp .cluster text{fill:#333;}#mermaid-svg-ep8xcLEEFqmPzVfp .cluster span{color:#333;}#mermaid-svg-ep8xcLEEFqmPzVfp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ep8xcLEEFqmPzVfp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ep8xcLEEFqmPzVfp rect.text{fill:none;stroke-width:0;}#mermaid-svg-ep8xcLEEFqmPzVfp .icon-shape,#mermaid-svg-ep8xcLEEFqmPzVfp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ep8xcLEEFqmPzVfp .icon-shape p,#mermaid-svg-ep8xcLEEFqmPzVfp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ep8xcLEEFqmPzVfp .icon-shape .label rect,#mermaid-svg-ep8xcLEEFqmPzVfp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ep8xcLEEFqmPzVfp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ep8xcLEEFqmPzVfp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ep8xcLEEFqmPzVfp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ① 目标选择:从 Side.Contacts 筛选可交战目标
② 武器匹配:校验五组包线
③ 配算 Weaponeering:依 WRA 规则决定用量
④ 发射:实例化 Weapon 注入 GuidedWeaponsInAir
⑤ 飞行与制导:逐脉冲更新,可换靶
⑥ 末端:导引头捕获 → CEP 落点抽样
⑦ 引爆:生成 Explosion 实体
① 目标选择 的约束来源:Doctrine 的 WCS(分空/海/潜/陆四域)、_BehaviorTowardsTargetAmbiguity(对模糊目标的处置)、PriorityTargetList(优先目标清单)、ExclusionZones / NoNavZones(交战禁区)。
② 武器匹配:遍历挂载武器,校验射程 · 发射高度 · 目标高度 · 目标速度 · 发射速度五组包线(分析报告 5.1 节),另加 ValidTargets 位标志与 Directors 火控指挥仪可用性。
下面用 C# 伪代码展示五组包线的校验顺序与提前 return 的写法。每一组都以廉价判据先行排除,命中才进入下一组,从而把配算与实例化(③④)留给极小候选集:
csharp
// 五组包线校验:按代价递增顺序判定,任一组不满足即提前 return(淘汰)
// 返回 null 表示该武器不可用;返回 Weapon 表示通过全部包线校验
Weapon? MatchWeapon(Weapon weapon, Contact target, Unit shooter)
{
// ① 射程包线 ------ 一次距离比较,纳秒级
// 淘汰条件:目标距离超出武器最小/最大射程
double range = GreatCircleDistance(shooter.Position, target.Position);
if (range < weapon.MinRange || range > weapon.MaxRange) return null;
// ② 发射高度包线 ------ 一次数值比较,纳秒级
// 淘汰条件:发射平台高度超出武器允许的发射高度区间
if (shooter.Altitude < weapon.MinLaunchAltitude) return null;
if (shooter.Altitude > weapon.MaxLaunchAltitude) return null;
// ③ 目标高度包线 ------ 一次数值比较,纳秒级
// 淘汰条件:目标高度超出武器可交战的高度区间
if (target.Altitude < weapon.MinTargetAltitude) return null;
if (target.Altitude > weapon.MaxTargetAltitude) return null;
// ④ 目标速度包线 ------ 一次数值比较,纳秒级
// 淘汰条件:目标速度超出武器可拦截的速度区间
if (target.Speed < weapon.MinTargetSpeed) return null;
if (target.Speed > weapon.MaxTargetSpeed) return null;
// ⑤ 发射速度包线 ------ 一次数值比较,纳秒级
// 淘汰条件:发射平台当前速度超出武器允许的发射速度区间
if (shooter.Speed < weapon.MinLaunchSpeed) return null;
if (shooter.Speed > weapon.MaxLaunchSpeed) return null;
// 全部通过 → 该武器可交战,进入配算(③)
return weapon;
}
这段伪代码把五组包线映射为顺序判定的 return 链:五组判据均为纳秒级的数值比较,代价极低,却能在进入配算与实例化之前排除绝大多数不可交战的「武器---目标」组合------与「高代价计算后置」的设计哲学完全一致。实际源码中还会叠加 ValidTargets 位标志与 Directors 火控指挥仪可用性两项前置过滤(见分析报告 5.1 节)。
③ 配算 :WeaponQty(齐射发数)· ShooterQty(射击平台数)· FiringRange(开火距离)· SelfDefenceRange(自卫距离),四项均为可空值,按 4 级条令继承链解析(见 7.1 节)。
④ 发射 :实例化 Weapon 对象并注入 Scenario.GuidedWeaponsInAir,此后弹药作为独立 ActiveUnit 参与运动学与感知。
⑤ 飞行与制导:逐脉冲更新;中段可由 DataLinkParent 换靶;BlindTime 内导引头不工作;HasGoneAutonomous 后脱离控制。
⑥ 末端:导引头捕获 → CEP 落点抽样 → 命中/脱靶。
⑦ 引爆:生成 Explosion 实体,转入毁伤链路。
关键结构性判断(B 级):第 ④ 步之后,弹药离开发射平台的控制流,成为独立实体。这使得"拦截来袭导弹"不需要任何特殊逻辑------来袭弹药就是一个可被探测(步骤 ①)、可被匹配武器(步骤 ②)、可被击毁的普通目标。3.3 节所述"把 Weapon 纳入 ActiveUnit 继承树"的收益,在此得到完整体现。
6.3 毁伤链路
#mermaid-svg-G07uASjk9R6hK9zr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-G07uASjk9R6hK9zr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-G07uASjk9R6hK9zr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-G07uASjk9R6hK9zr .error-icon{fill:#552222;}#mermaid-svg-G07uASjk9R6hK9zr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-G07uASjk9R6hK9zr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-G07uASjk9R6hK9zr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-G07uASjk9R6hK9zr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-G07uASjk9R6hK9zr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-G07uASjk9R6hK9zr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-G07uASjk9R6hK9zr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-G07uASjk9R6hK9zr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-G07uASjk9R6hK9zr .marker.cross{stroke:#333333;}#mermaid-svg-G07uASjk9R6hK9zr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-G07uASjk9R6hK9zr p{margin:0;}#mermaid-svg-G07uASjk9R6hK9zr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-G07uASjk9R6hK9zr .cluster-label text{fill:#333;}#mermaid-svg-G07uASjk9R6hK9zr .cluster-label span{color:#333;}#mermaid-svg-G07uASjk9R6hK9zr .cluster-label span p{background-color:transparent;}#mermaid-svg-G07uASjk9R6hK9zr .label text,#mermaid-svg-G07uASjk9R6hK9zr span{fill:#333;color:#333;}#mermaid-svg-G07uASjk9R6hK9zr .node rect,#mermaid-svg-G07uASjk9R6hK9zr .node circle,#mermaid-svg-G07uASjk9R6hK9zr .node ellipse,#mermaid-svg-G07uASjk9R6hK9zr .node polygon,#mermaid-svg-G07uASjk9R6hK9zr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-G07uASjk9R6hK9zr .rough-node .label text,#mermaid-svg-G07uASjk9R6hK9zr .node .label text,#mermaid-svg-G07uASjk9R6hK9zr .image-shape .label,#mermaid-svg-G07uASjk9R6hK9zr .icon-shape .label{text-anchor:middle;}#mermaid-svg-G07uASjk9R6hK9zr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-G07uASjk9R6hK9zr .rough-node .label,#mermaid-svg-G07uASjk9R6hK9zr .node .label,#mermaid-svg-G07uASjk9R6hK9zr .image-shape .label,#mermaid-svg-G07uASjk9R6hK9zr .icon-shape .label{text-align:center;}#mermaid-svg-G07uASjk9R6hK9zr .node.clickable{cursor:pointer;}#mermaid-svg-G07uASjk9R6hK9zr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-G07uASjk9R6hK9zr .arrowheadPath{fill:#333333;}#mermaid-svg-G07uASjk9R6hK9zr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-G07uASjk9R6hK9zr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-G07uASjk9R6hK9zr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-G07uASjk9R6hK9zr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-G07uASjk9R6hK9zr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-G07uASjk9R6hK9zr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-G07uASjk9R6hK9zr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-G07uASjk9R6hK9zr .cluster text{fill:#333;}#mermaid-svg-G07uASjk9R6hK9zr .cluster span{color:#333;}#mermaid-svg-G07uASjk9R6hK9zr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-G07uASjk9R6hK9zr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-G07uASjk9R6hK9zr rect.text{fill:none;stroke-width:0;}#mermaid-svg-G07uASjk9R6hK9zr .icon-shape,#mermaid-svg-G07uASjk9R6hK9zr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-G07uASjk9R6hK9zr .icon-shape p,#mermaid-svg-G07uASjk9R6hK9zr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-G07uASjk9R6hK9zr .icon-shape .label rect,#mermaid-svg-G07uASjk9R6hK9zr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-G07uASjk9R6hK9zr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-G07uASjk9R6hK9zr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-G07uASjk9R6hK9zr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Explosion 实体生成:位置/当量 ExpYield/战斗部类型/引爆介质
① 作用半径解算:GetCutoffRange_Blast_nm / _Frag_nm
② 受影响单元筛选:半径内扫描
③ 单体毁伤量:破片 + 冲击波 × 地表覆盖衰减
④ 命中部位判定:ComponentHitType 13 种
⑤ 次生灾害:FireIntensity / FloodIntensity 状态机
⑥ 存续与表现:MaxDuration 按介质声速折算
① 作用半径解算:介质分支------空中 / 水面 / 水下(×4.411)/ 地下(×8.823)/ 外空(0)。
下面用 C# 代码展示作用半径解算的介质分支写法。根据引爆介质调用对应的 GetCutoffRange_*_nm 函数,返回以海里为单位的半径值:
csharp
// 作用半径解算:按引爆介质分支,返回以海里为单位的截止半径
// 空中/水面走冲击波与破片两条路径;水下/地下按介质系数放大;外空为 0
double ResolveCutoffRange(Explosion explosion)
{
switch (explosion.Medium)
{
case BlastMedium.Air:
// 空中:冲击波 + 破片,取两者较大者作为作用半径
double blastAir = GetCutoffRange_Blast_nm(explosion.ExpYield, BlastMedium.Air);
double fragAir = GetCutoffRange_Frag_nm(explosion.ExpYield, BlastMedium.Air);
return Math.Max(blastAir, fragAir);
case BlastMedium.Surface:
// 水面:同样取冲击波与破片较大者
double blastSurface = GetCutoffRange_Blast_nm(explosion.ExpYield, BlastMedium.Surface);
double fragSurface = GetCutoffRange_Frag_nm(explosion.ExpYield, BlastMedium.Surface);
return Math.Max(blastSurface, fragSurface);
case BlastMedium.Underwater:
// 水下:冲击波按 ×4.411 放大(水介质声速/密度特性)
return GetCutoffRange_Blast_nm(explosion.ExpYield, BlastMedium.Underwater) * 4.411;
case BlastMedium.Underground:
// 地下:冲击波按 ×8.823 放大(土岩介质耦合更强)
return GetCutoffRange_Blast_nm(explosion.ExpYield, BlastMedium.Underground) * 8.823;
case BlastMedium.Space:
// 外空:无大气/水介质传播,作用半径为 0
return 0.0;
default:
return 0.0;
}
}
这段代码把流程图中的「① 作用半径解算」映射为介质分支的 switch:空中与水面同时考虑冲击波与破片两条毁伤路径并取较大者,水下与地下按介质系数放大冲击波半径,外空则直接返回 0------与「高代价计算后置」的原则一致,先用廉价的分支判断确定求解路径,再调用对应的物理函数。同时,6.4 节的一致性约束在此得到体现:表现层 WaterSplash / GroundImpact 视觉实体直接复用 GetCutoffRange_Blast_nm 的返回值,保证界面所见即判定所用。
② 受影响单元筛选:半径内单元扫描(Explosion.cs 有 7 处 Parallel);核爆与 EMP 走独立路径:全场遍历 + 逐一 LOS 判定。
③ 单体毁伤量:破片(二次方衰减)+ 冲击波(空中二次方/水下三次方),乘以地表覆盖衰减系数(城区 0.25 ... 开阔地 1.00)。
下面用 C# 伪代码展示单体毁伤量的计算过程。破片按二次方衰减、冲击波按介质区分(空中二次方/水下三次方)衰减,两者叠加后再乘以地表覆盖衰减系数:
csharp
// 单体毁伤量:破片(二次方衰减) + 冲击波(空中二次方/水下三次方),再乘地表覆盖衰减系数
// 返回 0~1 的毁伤比例,供后续 ComponentHitType 判定具体失效部件
double ComputeUnitDamage(Explosion explosion, Unit unit, double distance)
{
// ① 破片毁伤 ------ 二次方衰减
// 系数 FragCoeff 由战斗部类型决定(见分析报告 5.3 节破片初速/质量分布)
// 衰减规律:随距离平方反比下降,距离越远破片密度越低
double fragDamage = explosion.FragCoeff / (distance * distance);
// ② 冲击波毁伤 ------ 按介质区分衰减指数
// 空中:二次方衰减(大气中冲击波超压随距离平方下降)
// 水下:三次方衰减(水介质声速/密度特性使衰减更快,见 5.3 节)
double blastDamage;
if (explosion.Medium == BlastMedium.Underwater)
blastDamage = explosion.BlastCoeff / (distance * distance * distance);
else
blastDamage = explosion.BlastCoeff / (distance * distance);
// ③ 叠加:破片 + 冲击波,取两者之和作为基础毁伤量
double rawDamage = fragDamage + blastDamage;
// ④ 地表覆盖衰减系数 ------ 城区 0.25 ... 开阔地 1.00
// 取值来源:地表覆盖类型对冲击波/破片的遮蔽与吸收效应(见分析报告 5.3 节)
// 城区建筑密集,遮蔽强 → 0.25;开阔地无遮蔽 → 1.00
double coverFactor = GetSurfaceCoverFactor(unit.SurfaceCover); // Urban=0.25 ... Open=1.00
// ⑤ 最终毁伤量 = 基础毁伤量 × 地表覆盖衰减系数,并夹取到 [0, 1]
return Math.Clamp(rawDamage * coverFactor, 0.0, 1.0);
}
这段伪代码把「③ 单体毁伤量」映射为三步计算:先分别按二次方/三次方衰减求出破片与冲击波毁伤,再叠加为原始毁伤量,最后乘以地表覆盖衰减系数并夹取到 0, 1。其中衰减指数与覆盖系数的取值均来自分析报告 5.3 节------空中冲击波按距离平方衰减、水下因介质特性按三次方衰减,城区 0.25 与开阔地 1.00 分别对应遮蔽最强与无遮蔽两种极端地表。计算得到的毁伤比例随后进入步骤 ④,由 ComponentHitType(13 种)决定具体失效部件,而非统一扣血。
④ 命中部位判定:ComponentHitType(13 种),决定失效的具体部件,而非统一扣血。
⑤ 次生灾害:FireIntensity / FloodIntensity 状态机启动,此后逐脉冲持续扣减 DP,同时损管按概率降级。
下面用 Mermaid 状态图展示 FireIntensity 与 FloodIntensity 两个状态机的迁移路径。两者都从「无」经引爆触发进入「活跃」,此后逐脉冲持续作用;只有损管扑灭或单元沉没两个终止条件才能结束状态机:
#mermaid-svg-UkmuRkH6Hz2H0JGT{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UkmuRkH6Hz2H0JGT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UkmuRkH6Hz2H0JGT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UkmuRkH6Hz2H0JGT .error-icon{fill:#552222;}#mermaid-svg-UkmuRkH6Hz2H0JGT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UkmuRkH6Hz2H0JGT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UkmuRkH6Hz2H0JGT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UkmuRkH6Hz2H0JGT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UkmuRkH6Hz2H0JGT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UkmuRkH6Hz2H0JGT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UkmuRkH6Hz2H0JGT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UkmuRkH6Hz2H0JGT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UkmuRkH6Hz2H0JGT .marker.cross{stroke:#333333;}#mermaid-svg-UkmuRkH6Hz2H0JGT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UkmuRkH6Hz2H0JGT p{margin:0;}#mermaid-svg-UkmuRkH6Hz2H0JGT defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-UkmuRkH6Hz2H0JGT g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-UkmuRkH6Hz2H0JGT g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-UkmuRkH6Hz2H0JGT g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-UkmuRkH6Hz2H0JGT g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-UkmuRkH6Hz2H0JGT g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-UkmuRkH6Hz2H0JGT .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-UkmuRkH6Hz2H0JGT .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-UkmuRkH6Hz2H0JGT .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-UkmuRkH6Hz2H0JGT .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-UkmuRkH6Hz2H0JGT .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-UkmuRkH6Hz2H0JGT .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-UkmuRkH6Hz2H0JGT .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-UkmuRkH6Hz2H0JGT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UkmuRkH6Hz2H0JGT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-UkmuRkH6Hz2H0JGT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UkmuRkH6Hz2H0JGT .edgeLabel .label text{fill:#333;}#mermaid-svg-UkmuRkH6Hz2H0JGT .label div .edgeLabel{color:#333;}#mermaid-svg-UkmuRkH6Hz2H0JGT .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-UkmuRkH6Hz2H0JGT .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-UkmuRkH6Hz2H0JGT .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-UkmuRkH6Hz2H0JGT .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-UkmuRkH6Hz2H0JGT .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-UkmuRkH6Hz2H0JGT .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UkmuRkH6Hz2H0JGT .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UkmuRkH6Hz2H0JGT #statediagram-barbEnd{fill:#333333;}#mermaid-svg-UkmuRkH6Hz2H0JGT .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UkmuRkH6Hz2H0JGT .cluster-label,#mermaid-svg-UkmuRkH6Hz2H0JGT .nodeLabel{color:#131300;}#mermaid-svg-UkmuRkH6Hz2H0JGT .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-UkmuRkH6Hz2H0JGT .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-UkmuRkH6Hz2H0JGT .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-UkmuRkH6Hz2H0JGT .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-UkmuRkH6Hz2H0JGT .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-UkmuRkH6Hz2H0JGT .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-UkmuRkH6Hz2H0JGT .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-UkmuRkH6Hz2H0JGT .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-UkmuRkH6Hz2H0JGT .note-edge{stroke-dasharray:5;}#mermaid-svg-UkmuRkH6Hz2H0JGT .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-UkmuRkH6Hz2H0JGT .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-UkmuRkH6Hz2H0JGT .statediagram-note text{fill:black;}#mermaid-svg-UkmuRkH6Hz2H0JGT .statediagram-note .nodeLabel{color:black;}#mermaid-svg-UkmuRkH6Hz2H0JGT .statediagram .edgeLabel{color:red;}#mermaid-svg-UkmuRkH6Hz2H0JGT #dependencyStart,#mermaid-svg-UkmuRkH6Hz2H0JGT #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-UkmuRkH6Hz2H0JGT .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-UkmuRkH6Hz2H0JGT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 初始
引爆触发(FireIntensity 启动)
逐脉冲扣减 DP / 蔓延
损管扑灭(概率降级至 0)
单元沉没(DP 归零)
再次引爆(复燃)
初始
引爆触发(FloodIntensity 启动)
逐脉冲扣减 DP / 进水扩散
损管扑灭(概率降级至 0)
单元沉没(DP 归零)
再次引爆(复进水)
单元沉没,状态机终止
FireNone
FireActive
Sunk
FloodNone
FloodActive
这张状态图把「⑤ 次生灾害」的持续性特征具象化:FireIntensity 与 FloodIntensity 都不是一次性事件,而是被注入实体的长期状态机------一旦引爆触发便进入活跃态,在后续数百个脉冲中持续扣减 DP 并可能蔓延扩散。状态机的退出只有两条路径:一是损管按概率逐步降级直至扑灭(回到无状态,但可能被再次引爆复燃/复进水),二是单元 DP 归零沉没(状态机彻底终止)。这正是毁伤链路区别于探测、交战两条瞬时链路的核心特征------毁伤不是瞬间结算,而是被注入实体的一个长期过程(B 级)。
⑥ 存续与表现:Explosion.MaxDuration 按介质声速折算,派生 WaterSplash / GroundImpact 视觉实体。
毁伤链路有一个不同于前两条链路的特征:它是持续的。步骤 ⑤ 启动的火灾与进水状态机会在此后数百个脉冲中持续作用,直到损管扑灭或单元沉没。因此毁伤不是一个瞬时事件,而是被注入实体的一个长期过程(B 级)。
下面用 Mermaid 时序图展示 Explosion 实体从生成到视觉实体派生的完整调用顺序。从引爆生成实体开始,依次经过作用半径解算、受影响单元筛选、单体毁伤量计算、命中部位判定,再到次生灾害状态机启动,最后按介质声速折算存续时长并派生视觉实体:
WaterSplash / GroundImpact Fire/Flood 状态机 受影响单元 GetCutoffRange_* Explosion Weapon(引爆) WaterSplash / GroundImpact Fire/Flood 状态机 受影响单元 GetCutoffRange_* Explosion Weapon(引爆) #mermaid-svg-qKz0dQair3qVrpce{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qKz0dQair3qVrpce .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qKz0dQair3qVrpce .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qKz0dQair3qVrpce .error-icon{fill:#552222;}#mermaid-svg-qKz0dQair3qVrpce .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qKz0dQair3qVrpce .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qKz0dQair3qVrpce .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qKz0dQair3qVrpce .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qKz0dQair3qVrpce .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qKz0dQair3qVrpce .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qKz0dQair3qVrpce .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qKz0dQair3qVrpce .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qKz0dQair3qVrpce .marker.cross{stroke:#333333;}#mermaid-svg-qKz0dQair3qVrpce svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qKz0dQair3qVrpce p{margin:0;}#mermaid-svg-qKz0dQair3qVrpce .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qKz0dQair3qVrpce text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-qKz0dQair3qVrpce .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-qKz0dQair3qVrpce .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-qKz0dQair3qVrpce .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-qKz0dQair3qVrpce .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-qKz0dQair3qVrpce #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-qKz0dQair3qVrpce .sequenceNumber{fill:white;}#mermaid-svg-qKz0dQair3qVrpce #sequencenumber{fill:#333;}#mermaid-svg-qKz0dQair3qVrpce #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-qKz0dQair3qVrpce .messageText{fill:#333;stroke:none;}#mermaid-svg-qKz0dQair3qVrpce .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qKz0dQair3qVrpce .labelText,#mermaid-svg-qKz0dQair3qVrpce .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-qKz0dQair3qVrpce .loopText,#mermaid-svg-qKz0dQair3qVrpce .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-qKz0dQair3qVrpce .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-qKz0dQair3qVrpce .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-qKz0dQair3qVrpce .noteText,#mermaid-svg-qKz0dQair3qVrpce .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-qKz0dQair3qVrpce .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qKz0dQair3qVrpce .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qKz0dQair3qVrpce .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qKz0dQair3qVrpce .actorPopupMenu{position:absolute;}#mermaid-svg-qKz0dQair3qVrpce .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-qKz0dQair3qVrpce .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qKz0dQair3qVrpce .actor-man circle,#mermaid-svg-qKz0dQair3qVrpce line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-qKz0dQair3qVrpce :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ⑦ 引爆:生成 Explosion 实体(位置/当量/战斗部/介质)① 作用半径解算:介质分支 switch返回截止半径(海里)② 受影响单元筛选:半径内扫描(7 处 Parallel)返回半径内单元集合③ 单体毁伤量:破片二次方 + 冲击波二次方/三次方 × 地表覆盖衰减返回 0~1 毁伤比例④ 命中部位判定:ComponentHitType(13 种)返回具体失效部件⑤ 次生灾害:FireIntensity / FloodIntensity 状态机启动状态机进入活跃态(此后逐脉冲持续作用)⑥ 存续与表现:MaxDuration 按介质声速折算派生 WaterSplash / GroundImpact 视觉实体
这张时序图把毁伤链路的六个步骤映射为一条顺序调用链:从 Weapon 引爆生成 Explosion 实体开始,先以廉价的介质分支解算作用半径,再以半径内扫描限定受影响单元集合,随后对每个单元计算单体毁伤量并判定命中部位,最后启动次生灾害状态机并派生视觉实体。与前两条链路相比,毁伤链路的本质差异在于持续性 ------探测与交战都是瞬时结算:探测在单个脉冲内完成判定,未中则下一脉冲重试;交战在发射瞬间完成配算与实例化,此后弹药转为独立实体持续飞行。而毁伤链路在步骤 ⑤ 启动的 FireIntensity / FloodIntensity 状态机会在此后数百个脉冲中持续扣减 DP 并可能蔓延扩散,直到损管扑灭或单元沉没才终止。因此毁伤不是一个瞬时事件,而是被注入实体的一个长期过程(B 级)。
6.4 计算与表现的一致性约束
工程中明确维护着一条约束:表现层的视觉尺度必须取自计算层的同一函数返回值(A 级)。
具体证据是:爆炸派生的 WaterSplash 与 GroundImpact 视觉实体,其尺度直接调用 GetCutoffRange_Blast_nm 获取,而非另设一套显示参数(见分析报告 5.3 节)。同样地,MainForm 中鼠标悬停显示的地形坡度调用的是 Terrain.InvokeWatcher------即雷达地杂波计算所用的同一个最大坡度函数。
这条约束的价值在于可验证性:用户在界面上看到的爆炸范围就是实际参与毁伤判定的范围,看到的地形坡度就是实际影响杂波的坡度。对于一款用于严肃分析的工具,显示与计算不一致是比显示不精确更严重的缺陷(C 级)。
三条链路在「高代价计算后置」原则下的实现差异,可横向对比如下:
| 维度 | 探测链路(6.1) | 交战链路(6.2) | 毁伤链路(6.3) |
|---|---|---|---|
| 输入 | (Sensor, Target) 组合 | Side.Contacts 候选目标 + 挂载武器 | Explosion 实体(位置/当量/战斗部/介质) |
| 输出 | Contact 对象(写入 Side.Contacts) | Weapon 实体(注入 GuidedWeaponsInAir) | 毁伤状态(DP 扣减、次生灾害、视觉实体) |
| 核心判据 | 五级门限(状态/几何/视线/物理/概率) | 五组包线 + ValidTargets + Directors | 作用半径 + 地表覆盖衰减 + ComponentHitType |
| 关键函数 | Is* 标志位、GreatCircleDistance、Horizon/LOS、RadarModel 等 | WCS、包线校验、Weaponeering 配算 | GetCutoffRange_Blast_nm / _Frag_nm、Explosion.cs |
| 代价特征 | 前三级纳秒~微秒级,物理门毫秒级(最高) | 包线校验微秒级,配算与实例化毫秒级 | 半径扫描 + 并行筛选,核爆/EMP 全场遍历 |
| 持续性 | 瞬时(每脉冲判定,未中则下一脉冲重试) | 瞬时(发射后弹药转为独立实体持续飞行) | 持续(火灾/进水状态机在数百脉冲内持续作用) |
三条链路对「高代价计算后置」的落实方式各不相同,但共享同一骨架:先用廉价判据把候选集压缩到极小,再让昂贵的物理求解只作用于幸存者。探测链路把这一思想落实得最彻底------五级门限中前三级以纳秒~微秒级判据完成绝大多数淘汰,物理门只面对极小候选集;交战链路则把「过滤」前置到目标选择与武器匹配阶段,用包线校验在配算与实例化之前排除不可交战组合;毁伤链路以作用半径解算与半径内扫描限定作用域,使逐单元毁伤量计算只作用于受影响单元。三者的差异在于「高代价计算」的具体形态不同------探测是方程求解、交战是配算与实例化、毁伤是逐单元毁伤量------但都遵循「先廉价排除、后昂贵求解」的同一原则,这正是本章三条链路能够共享同一设计哲学的根本原因。
三条链路对「高代价计算后置」的落实方式,可按下表横向对比:
| 链路 | 廉价判据 | 昂贵计算 | 持续性 | 关键证据文件 |
|---|---|---|---|---|
| 探测链路(6.1) | 五级门限前三级:状态门(Is* 标志位布尔判读)、几何门(大圆距离/扫描范围)、视线门(Horizon 闭式解 / LOS 地形采样) | 物理门:雷达/声呐/红外/目视方程求解(RadarModel / SonarModel / InfraredModel / VisualModel) | 瞬时(每脉冲判定,未中则下一脉冲重试) | ActiveUnit_Sensory.cs(243 KB,含 Pre/Post Pulse 挂钩) |
| 交战链路(6.2) | 五组包线校验(射程/发射高度/目标高度/目标速度/发射速度)+ ValidTargets 位标志 + Directors 火控可用性 | 配算 Weaponeering(WeaponQty / ShooterQty / FiringRange / SelfDefenceRange)与武器实例化 | 瞬时(发射后弹药转为独立实体持续飞行) | ActiveUnit_Weaponry.cs(771 KB,全工程第三大文件) |
| 毁伤链路(6.3) | 作用半径解算(介质分支 switch)与半径内单元扫描 | 逐单元毁伤量计算(破片二次方 + 冲击波二次方/三次方 × 地表覆盖衰减) | 持续(FireIntensity / FloodIntensity 状态机在数百脉冲内持续作用) | Explosion.cs(含 7 处 Parallel 扫描) |
这张表将三条链路对「高代价计算后置」的落实方式收敛为同一骨架:先用廉价判据把候选集压缩到极小,再让昂贵的物理求解只作用于幸存者。探测链路把廉价判据做到最彻底------五级门限中前三级以纳秒~微秒级判据完成绝大多数淘汰,物理门只面对极小候选集;交战链路把「过滤」前置到目标选择与武器匹配阶段,用包线校验在配算与实例化之前排除不可交战组合;毁伤链路以作用半径解算与半径内扫描限定作用域,使逐单元毁伤量计算只作用于受影响单元。三者的差异在于「高代价计算」的具体形态不同------探测是方程求解、交战是配算与实例化、毁伤是逐单元毁伤量------但都遵循「先廉价排除、后昂贵求解」的同一原则,这正是本章三条链路能够共享同一设计哲学的根本原因。
6.5 本章小结
三条主链路共享同一设计哲学:把高代价计算后置,用低代价判据先行排除。探测链路用五级门限压缩候选集,交战链路用包线校验过滤目标,毁伤链路用半径扫描限定作用域------每一步都在为后续更昂贵的计算缩小输入规模。
同时,三条链路都遵循实体与模型分离的原则:编排与状态在实体侧(ActiveUnit 及其派生类),物理求解在无状态静态模型类中。这保证了职责清晰、可进行独立测试,也让"弹药即实体"的统一抽象成为可能。
最后,6.4 节的一致性约束为整章提供了可验证性保障:显示层不另设参数,直接复用计算层函数,使界面所见即判定所用。