对接文档更新: 事件驱动API + FireSchedule + 默认弹药表
This commit is contained in:
parent
04e02c43eb
commit
202e5ee117
@ -1,175 +1,166 @@
|
||||
# 后端对接文档(Unity 前端)
|
||||
|
||||
> **版本**:V1.0
|
||||
> **日期**:2026-06-11
|
||||
> **版本**:V1.1
|
||||
> **日期**:2026-06-12
|
||||
> **Unity 版本**:2022.3.62f3c1
|
||||
|
||||
---
|
||||
|
||||
## 一、交付物
|
||||
|
||||
前端同学从项目仓库取以下两个目录,拖入自己的 Unity 项目:
|
||||
从仓库取以下内容,拖入 Unity 项目:
|
||||
|
||||
```
|
||||
src/Unity/Assets/Plugins/ ← 16 个 DLL,零配置,拖入即用
|
||||
src/Unity/Assets/Scripts/Managers/ ← 6 个 C# 桥接脚本
|
||||
src/Unity/Assets/Plugins/ ← 16 个 DLL(Core + sqlite + JSON)
|
||||
src/Unity/Assets/Scripts/Managers/ ← 桥接脚本
|
||||
data/default_ammo.json ← 默认弹药参数(放到 persistentDataPath 下)
|
||||
```
|
||||
|
||||
> 不要改 DLL,以后更新时替换即可。Manager 脚本可以按需修改。
|
||||
|
||||
---
|
||||
|
||||
## 二、快速验证
|
||||
|
||||
1. 拖入上述两个目录后,等 Unity 编译完成
|
||||
2. 创建一个空 GameObject,挂 `ManagerVerification` 组件
|
||||
1. 拖入上述目录,等 Unity 编译
|
||||
2. 创建空 GameObject,挂 `ManagerVerification`
|
||||
3. Inspector 右键 → `Run Full Verification`
|
||||
4. Console 看到 7 行 `OK` 即表示集成成功
|
||||
4. Console 看到 7 行 OK
|
||||
|
||||
---
|
||||
|
||||
## 三、Manager API
|
||||
## 三、核心流程
|
||||
|
||||
所有 Manager 都是 `MonoBehaviour`,挂到场景即可用。建议做成 Singleton。
|
||||
|
||||
### ModelManager — 模型管理
|
||||
### 3.1 创建想定 & 获取推荐方案
|
||||
|
||||
```csharp
|
||||
var mgr = GetComponent<ModelManager>();
|
||||
var scenario = GetComponent<ScenarioManager>();
|
||||
var task = scenario.CreateTask("拦截活塞式无人机", "");
|
||||
scenario.SaveScene(task.Id, new CombatScene { WindSpeed = 3 });
|
||||
scenario.SaveTarget(task.Id, new TargetConfig { PowerType = (int)PowerType.Piston, ... });
|
||||
scenario.SaveRoute(task.Id, routePlan, waypoints);
|
||||
|
||||
// 导入模型
|
||||
ModelInfo model = mgr.Import("C:/models/drone.fbx", "旋翼无人机");
|
||||
// 支持的格式: .fbx .obj .stl .glb .gltf(≤500MB)
|
||||
// 推荐方案(自动从数据库读弹药规格)
|
||||
var detail = scenario.GetDetail(task.Id);
|
||||
var ammoCatalog = db.Table<AmmunitionSpec>().ToList(); // DatabaseManager 已种子
|
||||
var rec = new DefaultDefenseAdvisor(ammoCatalog).Recommend(new ThreatProfile { ... });
|
||||
|
||||
// 查询
|
||||
List<ModelInfo> all = mgr.GetAll();
|
||||
ModelInfo one = mgr.Get("model-id");
|
||||
|
||||
// 删除
|
||||
mgr.Delete("model-id");
|
||||
// 应用到想定
|
||||
scenario.SaveCloud(task.Id, rec.Best.RecommendedCloud);
|
||||
scenario.SaveDeployment(task.Id, rec.Best.Platforms.Select(p => new EquipmentDeployment { ... }).ToList());
|
||||
```
|
||||
|
||||
### ScenarioManager — 想定管理
|
||||
|
||||
```csharp
|
||||
var mgr = GetComponent<ScenarioManager>();
|
||||
|
||||
// 创建任务
|
||||
SimTask task = mgr.CreateTask("城市防御演习", ""); // 空字符串 = 自动编号
|
||||
|
||||
// 5 步配置
|
||||
mgr.SaveScene(task.Id, new CombatScene { WindSpeed = 5, ... });
|
||||
mgr.SaveTarget(task.Id, new TargetConfig { Quantity = 3, ... });
|
||||
mgr.SaveDeployment(task.Id, new List<EquipmentDeployment> { ... });
|
||||
mgr.SaveCloud(task.Id, new CloudDispersal { AerosolType = ..., ... });
|
||||
mgr.SaveRoute(task.Id, new RoutePlan { ... }, waypointList);
|
||||
|
||||
// 算法推荐(需要先填充弹药库 AmmunitionSpec)
|
||||
var advisor = new DefaultDefenseAdvisor(ammoCatalog);
|
||||
var rec = advisor.Recommend(threatProfile);
|
||||
// rec.Best.RecommendedCloud → 云团参数
|
||||
// rec.Best.Platforms → 搭载平台部署方案
|
||||
// rec.Best.InterceptProbability → 拦截概率 0~1
|
||||
|
||||
// 搜索
|
||||
var result = mgr.Search("关键词", "2026-01-01", "2026-12-31", page: 1, pageSize: 10);
|
||||
```
|
||||
|
||||
### SimulationRunner — 仿真运行
|
||||
### 3.2 启动仿真(事件驱动)
|
||||
|
||||
```csharp
|
||||
var runner = GetComponent<SimulationRunner>();
|
||||
|
||||
// 加载想定并启动(需先配置好想定 + 云团的 RecommendedTiming)
|
||||
runner.LoadAndStart(taskId);
|
||||
// 推荐方案的 FireSchedule 直接传给引擎
|
||||
runner.Engine.SetFireSchedule(rec.Best.FireSchedule);
|
||||
runner.LoadAndStart(task.Id);
|
||||
runner.Engine.TimeScale = 4f; // 加速
|
||||
|
||||
// 可选:加速
|
||||
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();
|
||||
|
||||
// 每帧 Update
|
||||
void Update() {
|
||||
if (runner.Engine.State == SimulationState.Running) {
|
||||
var result = runner.Engine.Tick(Time.deltaTime);
|
||||
// result.EntitySnapshots → 所有实体位置,更新 3D GameObject
|
||||
// result.NewEvents → 本帧事件
|
||||
}
|
||||
}
|
||||
|
||||
// 无人机位置
|
||||
runner.Engine.Drones[0].PosX / PosY / PosZ
|
||||
runner.Engine.Drones[0].Status // Flying / Destroyed / ReachedTarget
|
||||
runner.Engine.Drones[0].Hp // 0~1
|
||||
|
||||
// 云团
|
||||
runner.Engine.Clouds[i].Dispersion.Center / Radius / CoreDensity
|
||||
// 不需要手动 Tick —— SimulationBootstrap 已封装好了
|
||||
```
|
||||
|
||||
### ReportManager — 报告
|
||||
### 3.3 仿真事件一览
|
||||
|
||||
| 事件 | 参数 | 触发时机 |
|
||||
|------|------|------|
|
||||
| `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, 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 / Events
|
||||
runner.Stop();
|
||||
```
|
||||
|
||||
### ReportManager
|
||||
|
||||
```csharp
|
||||
var mgr = GetComponent<ReportManager>();
|
||||
|
||||
// 生成(仿真结束后)
|
||||
var report = mgr.Generate(taskId, config, events, droneStatus, duration);
|
||||
|
||||
// 导出 Markdown 文件
|
||||
string path = mgr.Export(report.Id);
|
||||
|
||||
// 搜索
|
||||
var result = mgr.Search("关键词", null, null, 1, 10);
|
||||
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 — 回放
|
||||
### ReplayController
|
||||
|
||||
```csharp
|
||||
var replay = GetComponent<ReplayController>();
|
||||
|
||||
replay.LoadReplay(taskId);
|
||||
|
||||
// 逐帧读取
|
||||
for (int i = 0; i < replay.TotalFrames; i++) {
|
||||
var frame = replay.GetFrame(i);
|
||||
// frame 是 List<SimFrameRecord>,包含该帧所有实体位置
|
||||
}
|
||||
// replay.TotalFrames / replay.GetFrame(frameIndex)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、关键数据模型
|
||||
## 五、默认弹药
|
||||
|
||||
| 模型 | 说明 |
|
||||
|------|------|
|
||||
| `SimTask` | 仿真任务(Id, Name, TaskNumber, Status, CurrentStep) |
|
||||
| `CombatScene` | 作战场景(天气/风速/温度/时间) |
|
||||
| `TargetConfig` | 目标配置(类型/数量/速度/动力) |
|
||||
| `EquipmentDeployment` | 装备部署(探测/发射平台/弹药) |
|
||||
| `CloudDispersal` | 云团抛撒配置(类型/位置/时机/规模) |
|
||||
| `RoutePlan` + `Waypoint` | 航路规划 |
|
||||
| `DefenseSolution` | 推荐方案(气溶胶选型/云团参数/平台部署/拦截概率) |
|
||||
| `SimulationReport` | 仿真报告(含 Markdown 内容) |
|
||||
| `SimFrameRecord` | 逐帧回放数据 |
|
||||
首次运行 `DatabaseManager.OpenMainDb()` 会检查 `persistentDataPath/default_ammo.json`。如果存在且 `AmmunitionSpec` 表为空,自动导入。
|
||||
|
||||
完整数据模型见 Core 源码 `Models/` 目录。
|
||||
当前默认参数(`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 |
|
||||
| 扩散模型 | 三阶段(爆轰→湍流→高斯) | | |
|
||||
|
||||
---
|
||||
|
||||
## 五、更新后端
|
||||
|
||||
当后端代码更新后:
|
||||
## 六、更新后端
|
||||
|
||||
```bash
|
||||
cd src/CounterDrone.Core
|
||||
dotnet publish -c Release -o ../../unity_plugins
|
||||
# 覆盖 Assets/Plugins/CounterDrone.Core/ 下所有 DLL
|
||||
```
|
||||
|
||||
然后把 `unity_plugins/` 下的新 DLL 覆盖到 `Assets/Plugins/CounterDrone.Core/` 即可。Manager 脚本一般不需要改。
|
||||
|
||||
---
|
||||
|
||||
## 六、参考
|
||||
## 七、参考
|
||||
|
||||
| 文档 | 位置 |
|
||||
|------|------|
|
||||
| 架构设计 | `docs/design/architecture/总体架构设计.md` |
|
||||
| 实体事件映射 | `docs/design/technical/仿真器实体与事件映射.md` |
|
||||
| 任务跟踪 | `docs/implementation/tasks/实施计划与任务跟踪.md` |
|
||||
| 测试报告 | `test/reports/`(每次集成测试自动生成) |
|
||||
| 测试状态 | 128 测试,95.4% 行覆盖率 |
|
||||
| 测试状态 | **129 测试,95.4% 行覆盖率,12 秒** |
|
||||
|
||||
Loading…
Reference in New Issue
Block a user