- 3D球冠探测: IsInCoverage, DetectionEntity, Tick 第5步扫描 - 探测融合: EarliestDetection 采样法, break 修复 - planner 诊断: HasInterceptWindow 拦截窗口检查 - TryGenerateFireEvents 返回拒绝原因 - Summary 含失败原因+建议值(探测范围/弧长) - PlanningFailed 事件: 引擎在规划失败时发出事件 - 硬编码消除: Phase2Duration→AmmunitionSpec ExpansionFactor/TimingSafetyMargin→PlannerConfig 速度从 waypoint.Speed 读取(不用 TypicalSpeed) - TestData 改为从 seeded 数据库读取(不再内嵌 JSON) - 默认数据加 3D球冠参数,巡航导弹速度300→200 空基航路10km→20km, 位置调整 - 222 测试全通过
7.1 KiB
7.1 KiB
后端对接文档(Unity 前端)
版本:V1.3
日期:2026-06-15
Unity 版本:2022.3.62f3c1
一、交付物
从仓库取以下内容,拖入 Unity 项目:
src/Unity/Assets/Plugins/ ← DLL(Core + sqlite + JSON)
src/Unity/Assets/Scripts/Managers/ ← 桥接脚本
将以下文件放到 Unity 项目 Assets/StreamingAssets/ 目录下:
data/defaults.json ← 默认数据(首次运行自动复制到 persistentDataPath)
data/planner_config.json ← 规划器配置(同上)
二、快速开始
- 将
defaults.json和planner_config.json放到Assets/StreamingAssets/ - 创建空 GameObject,挂
SimulationBootstrap - 运行 — 自动种子数据库,选一个
[Demo]想定,启动仿真
SimulationBootstrap是前端开发的参考模板,展示预设模式(一行代码)和自定义模式(用 DefaultData 预设组装)两种路径。
如需验证全部模块,挂
ManagerVerification→ Inspector 右键Run Full Verification。
三、核心流程(使用预设想定)
3.1 列出预设想定
var scenario = GetComponent<ScenarioManager>();
var demos = scenario.Search("Demo", null, null, 1, 100);
// → 返回 6 个预设想定:
// [Demo] 无防御-无人机抵达目标
// [Demo] 管控区域侵入
// [Demo] 活塞拦截-西风5ms
// [Demo] 喷气式拦截-活性材料
// [Demo] 空基拦截-东风5ms
// [Demo] 3架空基编队拦截
3.2 启动仿真(一行代码)
var runner = GetComponent<SimulationRunner>();
// 选一个预设想定,直接运行(引擎自动调用 Planner 生成发射计划)
runner.LoadAndStart(demos.Items[0].Id); // 例如:活塞拦截-西风5ms
runner.Engine.TimeScale = 4f; // 加速
// 订阅事件
runner.Engine.OnMunitionLaunched += m => Instantiate(shellPrefab, ToVector3(m.PosX, m.PosY, m.PosZ));
runner.Engine.OnCloudGenerated += c => SpawnCloud(c.Dispersion.Center, c.Dispersion.Radius);
runner.Engine.OnDroneDestroyed += d => PlayExplosion(d.PosX, d.PosY, d.PosZ);
runner.Engine.OnTargetDetected += (d, det) => ShowDetectionMark(d.PosX, d.PosY, d.PosZ);
runner.Engine.OnDroneReachedTarget += d => ShowReached(d.PosX, d.PosY, d.PosZ);
runner.Engine.OnZoneIntruded += (d, z) => AlertIntrusion(z.Name);
runner.Engine.OnSimulationEnded += () => GenerateReport();
3.3 自定义想定(高级)
var scenario = GetComponent<ScenarioManager>();
var task = scenario.CreateTask("自定义想定", "");
// 使用默认数据预设快速配置
var defaults = DefaultData.Load(new UnityPathProvider());
scenario.SaveScene(task.Id, defaults.Weather.First(w => w.Id == "sunny-calm").ToCombatScene());
scenario.SaveTarget(task.Id, defaults.Targets.First(p => p.Id == "shahed").ToTargetConfig());
scenario.SaveRoute(task.Id, "default",
defaults.Formations.First(f => f.Id == "single").ToRoutePlan(),
defaults.Routes.First(r => r.Id == "5km-h500").ToWaypoints(200));
scenario.SaveDeployment(task.Id, new List<EquipmentDeployment>
{
defaults.FireUnits.First(f => f.Id == "ground-light")
.ToEquipmentDeployment(AerosolType.InertGas, 1, 1500, 0, 50),
});
scenario.SaveCloudDispersal(task.Id, new CloudDispersal
{ AerosolType = (int)AerosolType.InertGas, DisperseHeight = 500 });
scenario.UpdateStep(task.Id, 5);
// 运行
var runner = GetComponent<SimulationRunner>();
runner.LoadAndStart(task.Id);
3.3 仿真事件一览
| 事件 | 参数 | 触发时机 |
|---|---|---|
OnTargetDetected |
DroneEntity, DetectionEntity |
无人机首次进入探测设备 3D 球冠范围(离开后再次进入会重新触发) |
OnMunitionLaunched |
MunitionEntity |
发射计划时间到达 |
OnCloudGenerated |
CloudEntity |
弹药到达释放高度 |
OnDroneDestroyed |
DroneEntity |
HP ≤ 0 |
OnDroneReachedTarget |
DroneEntity |
到达最后航路点 |
OnZoneIntruded |
DroneEntity, ControlZoneEntity |
进入管控区 |
OnSimulationEnded |
无 | 所有无人机状态 ≠ Flying |
四、Manager API
ScenarioManager
var mgr = GetComponent<ScenarioManager>();
SimTask task = mgr.CreateTask("任务名", ""); // 空字符串 = 自动编号 SIM-yyyyMMdd-xxx
mgr.SaveScene(id, combatScene);
mgr.SaveTarget(id, targetConfig);
mgr.SaveDeployment(id, equipmentList);
mgr.SaveCloud(id, cloudDispersal);
mgr.SaveRoute(id, "default", routePlan, waypoints);
TaskFullConfig detail = mgr.GetDetail(id);
PagedResult<SimTask> result = mgr.Search("关键词", from, to, page, pageSize);
SimulationRunner
var runner = GetComponent<SimulationRunner>();
runner.Engine.SetFireSchedule(fireEvents); // 从推荐方案取
runner.LoadAndStart(taskId);
runner.Engine.TimeScale = 4f;
runner.Engine.State / Drones / Clouds / Munitions / DetectionEntities / Events
runner.Stop();
ReportManager
var mgr = GetComponent<ReportManager>();
var config = scenario.GetDetail(taskId);
var report = mgr.Generate(taskId, config, runner.Engine.Events.ToList(),
runner.Engine.Drones[0].Status.ToString(),
runner.Engine.SimulationTime);
string path = mgr.Export(report.Id); // → persistentDataPath/reports/xxx.md
ReplayController
var replay = GetComponent<ReplayController>();
replay.LoadReplay(taskId);
// replay.TotalFrames / replay.GetFrame(frameIndex)
五、默认数据
首次运行 DatabaseManager.OpenMainDb() 自动从 data/defaults.json 种子数据库:
| 类别 | 内容 | 示例 ID |
|---|---|---|
| 弹药 | 3 种 | inert / active / fuel |
| 编队 | 6 种 | single / line-3 / swarm-10 |
| 航线 | 6 条 | 3km-h300 / 5km-h500 / 10km-h500 / 20km-h500 |
| 火力单元 | 4 种 | ground-light / ground-standard / ground-heavy / air-standard |
| 无人机 | 6 种 | quadcopter / shahed / cruise-missile |
| 探测设备 | 4 种 | radar-mr / eo-station |
| 天气 | 6 种 | sunny-calm / fog / night |
| 预设想定 | 6 个 | [Demo] 活塞拦截-西风5ms |
所有默认数据名称含 [Demo] 前缀,UI 中可识别。预设可通过 API 直接获取:
var defaults = DefaultData.Load(new UnityPathProvider());
var ammo = defaults.Ammunition.First(a => a.Id == "inert");
var route = defaults.Routes.First(r => r.Id == "5km-h500").ToWaypoints(200);
var unit = defaults.FireUnits.First(f => f.Id == "ground-light").ToEquipmentDeployment(AerosolType.InertGas, 1, 1500, 0, 50);
六、更新后端
cd src/CounterDrone.Core
dotnet publish -c Release -o ../../unity_plugins
# 覆盖 Assets/Plugins/CounterDrone.Core/ 下所有 DLL
七、参考
| 文档 | 位置 |
|---|---|
| 架构设计 | docs/design/architecture/总体架构设计.md |
| 实体事件映射 | docs/design/technical/仿真器实体与事件映射.md |
| 任务跟踪 | docs/implementation/tasks/实施计划与任务跟踪.md |
| 测试报告 | test/reports/(每次集成测试自动生成) |
| 测试状态 | 191 测试,24 秒(集成) |