CounterDroneBackend/docs/对接文档_Unity前端.md
tian 56d345189e refactor: 编组概念拆分为批次(WaveId)+火力单元(FireUnit)
Breaking: Group表/枚举/Service/Repository移除; GroupId->WaveId; DroneGroup->DroneWave; DroneGroupId->DroneWaveId; GroupManager删除

Docs: CHANGELOG 0.7.0; 总体架构 V10; DefensePlanner V4; 实施计划 V1.4; 对接文档 V1.2

Tests: 204/204 pass
2026-06-15 15:13:48 +08:00

5.7 KiB
Raw Blame History

后端对接文档Unity 前端)

版本V1.2
日期2026-06-15
Unity 版本2022.3.62f3c1


一、交付物

从仓库取以下内容,拖入 Unity 项目:

src/Unity/Assets/Plugins/              ← 16 个 DLLCore + sqlite + JSON
src/Unity/Assets/Scripts/Managers/     ← 桥接脚本
data/default_ammo.json                 ← 默认弹药参数(放到 persistentDataPath 下)

二、快速验证

  1. 拖入上述目录,等 Unity 编译
  2. 创建空 GameObjectManagerVerification
  3. Inspector 右键 → Run Full Verification
  4. Console 看到 7 行 OK

三、核心流程

3.1 创建想定 & 获取推荐方案

var scenario = GetComponent<ScenarioManager>();
var task = scenario.CreateTask("拦截活塞式无人机", "");
scenario.SaveScene(task.Id, new CombatScene { WindSpeed = 3 });
scenario.SaveTarget(task.Id, new TargetConfig { WaveId = "default", PowerType = (int)PowerType.Piston, ... });
scenario.SaveRoute(task.Id, "default", routePlan, waypoints);

// 推荐方案DefensePlanner 五步流水线)
var detail = scenario.GetDetail(task.Id);
var ammoCatalog = db.Table<AmmunitionSpec>().ToList(); // DatabaseManager 已种子
var fireUnits = new List<FireUnit> { /* 从 EquipmentDeployment 构建 */ };
var threats = new List<DroneWave> { new DroneWave { WaveId = "default", Target = detail.Targets[0], Route = detail.Routes[0], Waypoints = detail.WaypointGroups["default"] } };
var plan = new DefensePlanner(ammoCatalog, PlannerConfig.Load(paths)).Plan(fireUnits, threats, detail.Scene, new List<DetectionSource>());

// 应用到想定(发射计划传给引擎,部署方案保存到配置)
var mergedSchedule = plan.Best.MergedSchedule;
// 部署火力单元到 EquipmentDeployment...
scenario.SaveCloud(task.Id, new CloudDispersal { /* 从 plan.Best.Assignments 推算云团参数 */ });
scenario.SaveDeployment(task.Id, equips);

3.2 启动仿真(事件驱动)

var runner = GetComponent<SimulationRunner>();

// 推荐方案的 FireSchedule 直接传给引擎
runner.Engine.SetFireSchedule(plan.Best.MergedSchedule);
runner.LoadAndStart(task.Id);
runner.Engine.TimeScale = 4f;  // 加速

// 订阅事件,不需要每帧遍历 NewEvents
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.OnDroneReachedTarget += d => ShowReached(d.PosX, d.PosY, d.PosZ);
runner.Engine.OnZoneIntruded     += (d, z) => AlertIntrusion(z.Name);
runner.Engine.OnSimulationEnded  += () => GenerateReport();

// 不需要手动 Tick —— SimulationBootstrap 已封装好了

3.3 仿真事件一览

事件 参数 触发时机
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 / 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() 会检查 persistentDataPath/default_ammo.json。如果存在且 AmmunitionSpec 表为空,自动导入。

当前默认参数(data/default_ammo.json

参数 惰性气体弹 活性材料弹 活性燃料弹
药剂质量 10 kg 12 kg 10 kg
爆发药 TNT 1.5 kg 4.0 kg 1.5 kg
初始半径 R₀ 3.75 m 5.14 m 3.75 m
扩散模型 三阶段(爆轰→湍流→高斯)

六、更新后端

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/(每次集成测试自动生成)
测试状态 204 测试95.4% 行覆盖率63 秒