SimulationRunner 新增 DataService 属性 SimulationBootstrap 自动创建 DataService 并注入 Runner 前端调用: runner.DataService.GetAllDrones() 等
135 lines
6.1 KiB
C#
135 lines
6.1 KiB
C#
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using CounterDrone.Core;
|
||
using CounterDrone.Core.Algorithms;
|
||
using CounterDrone.Core.Models;
|
||
using CounterDrone.Core.Repository;
|
||
using CounterDrone.Core.Services;
|
||
using UnityEngine;
|
||
using UVector3 = UnityEngine.Vector3;
|
||
using AVector3 = CounterDrone.Core.Algorithms.Vector3;
|
||
|
||
namespace CounterDrone.Unity
|
||
{
|
||
/// <summary>
|
||
/// 前端参考模板 — 展示两种运行方式:
|
||
/// 1. 预设模式:直接运行数据库中的 [Demo] 想定(最简单)
|
||
/// 2. 自定义模式:用 DefaultData 预设快速组装新想定 → Planner → 仿真
|
||
/// </summary>
|
||
public class SimulationBootstrap : MonoBehaviour
|
||
{
|
||
[Header("Mode")]
|
||
[SerializeField] private bool _usePreset = true; // true=预设想定, false=自定义
|
||
|
||
[Header("Custom Settings")]
|
||
[SerializeField] private float _droneSpeed = 200f;
|
||
[SerializeField] private float _routeLength = 5000f;
|
||
[SerializeField] private float _timeScale = 4f;
|
||
|
||
public SimulationRunner Runner { get; private set; }
|
||
|
||
void Start()
|
||
{
|
||
var paths = new UnityPathProvider();
|
||
var dbm = new DatabaseManager(paths);
|
||
var db = dbm.OpenMainDb(); // 自动种子弹药 + 6个[Demo]想定 + 基础数据
|
||
SqliteConnectionTracker.Track(db);
|
||
|
||
var dataService = new DataService(
|
||
new AmmunitionSpecRepository(db), new FireUnitSpecRepository(db),
|
||
new DroneSpecRepository(db), new SensorSpecRepository(db),
|
||
new EnvironmentSpecRepository(db), new FormationTemplateRepository(db),
|
||
new RouteTemplateRepository(db));
|
||
|
||
var scenario = new ScenarioService(
|
||
new SimTaskRepository(db), new CombatSceneRepository(db),
|
||
new ControlZoneRepository(db), new TargetConfigRepository(db),
|
||
new EquipmentDeploymentRepository(db), new CloudDispersalRepository(db),
|
||
new RoutePlanRepository(db), new WaypointRepository(db));
|
||
|
||
string taskId;
|
||
|
||
if (_usePreset)
|
||
{
|
||
// 方式1:直接使用预设想定(最简单)
|
||
var demos = scenario.SearchTasks("Demo", null, null, 1, 1);
|
||
if (demos.TotalCount == 0)
|
||
{
|
||
Debug.LogError("无预设想定,请确认 defaults.json 已放入 StreamingAssets");
|
||
return;
|
||
}
|
||
taskId = demos.Items[0].Id;
|
||
Debug.Log($"使用预设想定: {demos.Items[0].Name}");
|
||
}
|
||
else
|
||
{
|
||
// 方式2:用 DefaultData 预设组装自定义想定
|
||
var defaults = DefaultData.Load(paths);
|
||
|
||
var task = scenario.CreateTask("Unity Demo", "");
|
||
taskId = task.Id;
|
||
|
||
scenario.SaveScene(taskId, defaults.Environments.First(w => w.Id == "sunny-calm").ToCombatScene());
|
||
scenario.SaveTarget(taskId, defaults.Drones.First(p => p.Id == "shahed").ToTargetConfig());
|
||
scenario.SaveRoute(taskId, "default",
|
||
defaults.Formations.First(f => f.Id == "single").ToRoutePlan(),
|
||
defaults.Routes.First(r => _routeLength > 6000 ? r.Id == "10km-h500" : r.Id == "5km-h500")
|
||
.ToWaypoints(_droneSpeed));
|
||
|
||
// 从火力单元预设构建 FireUnit → Planner 自动生成方案 → 引擎执行
|
||
var detail = scenario.GetTaskDetail(taskId);
|
||
var ammoCatalog = db.Table<AmmunitionSpec>().ToList();
|
||
var planner = new DefensePlanner(ammoCatalog, PlannerConfig.Load(paths));
|
||
var threats = new List<DroneWave>
|
||
{
|
||
new DroneWave { WaveId = "default", Target = detail.Targets[0], Route = detail.Routes[0], Waypoints = detail.WaypointGroups["default"] }
|
||
};
|
||
var fireUnits = new List<FireUnit>();
|
||
for (int i = 0; i < 4; i++)
|
||
fireUnits.Add(new FireUnit
|
||
{
|
||
Id = $"fu{i}",
|
||
Type = PlatformType.GroundBased,
|
||
Position = new AVector3(_routeLength / 2f + i * 50, 0, 50),
|
||
MuzzleVelocity = 800, TotalMunitions = 3,
|
||
AmmoTypes = new() { AerosolType.InertGas, AerosolType.ActiveMaterial, AerosolType.ActiveFuel },
|
||
});
|
||
var plan = planner.Plan(fireUnits, threats, detail.Scene, new List<DetectionSource>());
|
||
|
||
scenario.SaveCloudDispersal(taskId, new CloudDispersal
|
||
{
|
||
AerosolType = (int)AerosolType.InertGas,
|
||
DisperseHeight = detail.Targets[0].TypicalAltitude,
|
||
Source = "Algorithm",
|
||
});
|
||
scenario.SaveDeployment(taskId, new List<EquipmentDeployment>
|
||
{
|
||
defaults.FireUnits.First(f => f.Id == "ground-light")
|
||
.ToEquipmentDeployment(AerosolType.InertGas, 1, _routeLength / 2f, 0, 50),
|
||
});
|
||
scenario.UpdateStep(taskId, 5);
|
||
|
||
Debug.Log($"自定义想定: {plan.Best.ThreatsEngaged} 威胁已分配, {plan.Best.MergedSchedule.Count} 发, 概率 {plan.Best.OverallProbability:P0}");
|
||
}
|
||
|
||
SqliteConnectionTracker.Untrack(db);
|
||
db.Dispose();
|
||
|
||
// 运行仿真
|
||
Runner = GetComponent<SimulationRunner>();
|
||
if (Runner == null) Runner = gameObject.AddComponent<SimulationRunner>();
|
||
else Runner.enabled = true;
|
||
Runner.DataService = dataService;
|
||
Runner.LoadAndStart(taskId);
|
||
Runner.Engine.TimeScale = _timeScale;
|
||
|
||
// 定位相机
|
||
var cam = Camera.main;
|
||
if (cam == null) { cam = new GameObject("MainCamera").AddComponent<Camera>(); cam.tag = "MainCamera"; }
|
||
float midX = _usePreset ? 2500f : _routeLength / 2f;
|
||
cam.transform.position = new UVector3(midX, 2000, -3000);
|
||
cam.transform.LookAt(new UVector3(midX, 500, 0));
|
||
}
|
||
}
|
||
}
|