CounterDroneBackend/docs/对接文档_Unity前端.md
tian e250093a16 docs: 更新对接文档 V1.4,同步实体属性变更
- 事件示例:cloud.Dispersion.Center → cloud.PosX/Y/Z, cloud.Radius
- API 列表:新增 Platforms 访问
- 新增 EntitySnapshot 字段文档(VelX/Y/Z)
- 新增实体属性速查表(所有 5 种实体)
- 测试状态更新:243 测试 9 秒全部通过
- Unity 脚本同步更新
2026-06-17 12:20:55 +08:00

231 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 后端对接文档Unity 前端)
> **版本**V1.4
> **日期**2026-06-17
> **Unity 版本**2022.3.62f3c1
---
## 一、交付物
从仓库取以下内容,拖入 Unity 项目:
```
src/Unity/Assets/Plugins/ ← DLLCore + sqlite + JSON
src/Unity/Assets/Scripts/Managers/ ← 桥接脚本
将以下文件放到 Unity 项目 Assets/StreamingAssets/ 目录下:
data/defaults.json ← 默认数据(首次运行自动复制到 persistentDataPath
data/planner_config.json ← 规划器配置(同上)
```
---
## 二、快速开始
1.`defaults.json``planner_config.json` 放到 `Assets/StreamingAssets/`
2. 创建空 GameObject`SimulationBootstrap`
3. 运行 — 自动种子数据库,选一个 `[Demo]` 想定,启动仿真
> `SimulationBootstrap` 是前端开发的参考模板,展示预设模式(一行代码)和自定义模式(用 DefaultData 预设组装)两种路径。
> 如需验证全部模块,挂 `ManagerVerification` → Inspector 右键 `Run Full Verification`。
---
## 三、核心流程(使用预设想定)
### 3.1 列出预设想定
```csharp
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 启动仿真(一行代码)
```csharp
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.PosX, c.PosY, c.PosZ, c.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 自定义想定(高级)
```csharp
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
```csharp
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
```csharp
var runner = GetComponent<SimulationRunner>();
runner.Engine.SetFireSchedule(fireEvents); // 从推荐方案取
runner.LoadAndStart(taskId);
runner.Engine.TimeScale = 4f;
runner.Engine.State / Drones / Clouds / Munitions / Platforms / DetectionEntities / Events
runner.Stop();
```
### ReportManager
```csharp
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
```csharp
var replay = GetComponent<ReplayController>();
replay.LoadReplay(taskId);
// replay.TotalFrames / replay.GetFrame(frameIndex)
```
### EntitySnapshot每帧推送
| 字段 | 类型 | 说明 |
|------|------|------|
| `EntityId` | string | 实体唯一 ID |
| `EntityType` | enum | Drone/Platform/Munition/Cloud/DetectionEquip |
| `PosX/Y/Z` | float | 三维位置 |
| `VelX/Y/Z` | float | 瞬时速度 (m/s) |
| `Hp` | float | 无人机血量 (0~1) |
| `DamageStage` | int | 损伤阶段 (0~N) |
| `PlatformStateStr` | string | 平台状态 (Idle/FlyingToTarget/ReadyToRelease) |
| `CloudRadius` | float | 云团有效半径 |
| `CloudOpacity` | float | 云团不透明度 (0~1) |
| `CloudPhase` | int | 云团扩散阶段 (1/2/3) |
| `CloudElapsed` | float | 云团已存在时间 (s) |
### 实体属性(直接访问)
| 实体 | 关键属性 |
|------|------|
| **DroneEntity** | Id, PosX/Y/Z, Hp, Status, ExposureTime, TargetType, PowerType, Wingspan, CruiseSpeed, Route, TraveledArc, TotalArc, Progress |
| **CloudEntity** | Id, PosX/Y/Z, Radius, Density, Phase, Elapsed, IsDissipated, AerosolType |
| **MunitionEntity** | Id, PosX/Y/Z, Velocity, StartX/Y/Z, LaunchTime, ElapsedTime, LaunchAngle, Azimuth, MuzzleVelocity, FlightDuration, TargetX/Y/Z, ReleaseAltitude, HasArrived |
| **PlatformEntity** | Id, PosX/Y/Z, CurrentVelocity, State, MunitionCount, Cooldown, MuzzleVelocity, CruiseSpeed, ReleaseAltitude, TargetX/Y/Z, FlightDistance |
| **DetectionEntity** | Id, PosX/Y/Z, Source, IsInRange(), IsDetected() |
---
## 五、默认数据
首次运行 `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 直接获取:
```csharp
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);
```
---
## 六、更新后端
```bash
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/`(每次集成测试自动生成) |
| 测试状态 | **243 测试9 秒(全部通过)** |