- 新增 IDefensePlanner 接口 + DefaultDefensePlanner 实现 - FireUnit 重构为统一平台模型(Type/Position/CruiseSpeed/ReleaseAltitude/MuzzleVelocity) - DroneGroup 加入威胁指数(类型系数×速度系数)和优先级排序 - 五步流水线:威胁排序→弹药匹配→候选生成→贪心分配→时序生成 - 弹药精确匹配,不降级;临界方案基于50%概率阈值 - 删除 IDefenseAdvisor/DefaultDefenseAdvisor/RecommendMultiGroup - AlgorithmFactory 注册 IDefensePlanner - 测试更新:DefensePlannerTests 替代旧测试,FullPipelineTests 适配新 API - Unity Managers 更新调用 - 125 测试全通过
131 lines
6.0 KiB
C#
131 lines
6.0 KiB
C#
using System.Collections.Generic;
|
|
using System.IO;
|
|
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;
|
|
|
|
namespace CounterDrone.Unity
|
|
{
|
|
/// <summary>一键启动:创建想定 → 推荐方案 → 运行仿真</summary>
|
|
public class SimulationBootstrap : MonoBehaviour
|
|
{
|
|
[Header("Simulation Settings")]
|
|
[SerializeField] private float _droneSpeed = 200f;
|
|
[SerializeField] private float _routeLength = 20000f;
|
|
[SerializeField] private float _timeScale = 4f;
|
|
|
|
public SimulationRunner Runner { get; private set; }
|
|
|
|
void Start()
|
|
{
|
|
var paths = new UnityPathProvider();
|
|
|
|
// 清理上次残留数据
|
|
if (System.IO.File.Exists(paths.GetMainDbPath()))
|
|
System.IO.File.Delete(paths.GetMainDbPath());
|
|
if (System.IO.Directory.Exists(paths.GetFramesDir()))
|
|
System.IO.Directory.Delete(paths.GetFramesDir(), true);
|
|
|
|
var dbm = new DatabaseManager(paths);
|
|
var db = dbm.OpenMainDb();
|
|
foreach (var a in DefaultAmmunition.GetAll()) db.Insert(a);
|
|
|
|
// 创建想定
|
|
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));
|
|
|
|
var task = scenario.CreateTask("Unity Demo", "");
|
|
var taskId = task.Id;
|
|
|
|
scenario.SaveScene(taskId, new CombatScene
|
|
{
|
|
SceneType = (int)SceneType.Plain, WindSpeed = 3,
|
|
WindDirection = (int)WindDirection.W, Temperature = 22,
|
|
});
|
|
scenario.SaveTarget(taskId, new TargetConfig
|
|
{
|
|
GroupId = "default",
|
|
TargetType = (int)TargetType.Piston, PowerType = (int)PowerType.Piston,
|
|
Quantity = 1, TypicalSpeed = _droneSpeed, TypicalAltitude = 500,
|
|
});
|
|
scenario.SaveRoute(taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single },
|
|
new List<Waypoint>
|
|
{
|
|
new Waypoint { PosX = 0, PosY = 500, PosZ = 0, Speed = _droneSpeed },
|
|
new Waypoint { PosX = _routeLength, PosY = 500, PosZ = 0, Speed = _droneSpeed },
|
|
});
|
|
|
|
// 推荐方案
|
|
var detail = scenario.GetTaskDetail(taskId);
|
|
var ammoCatalog = db.Table<AmmunitionSpec>().ToList();
|
|
var planner = new DefaultDefensePlanner(ammoCatalog);
|
|
var droneGroup = new DroneGroup
|
|
{
|
|
GroupId = "default",
|
|
Target = detail.Targets[0],
|
|
Route = detail.Routes[0],
|
|
Waypoints = detail.WaypointGroups["default"],
|
|
};
|
|
var fireUnits = new List<FireUnit>
|
|
{
|
|
new FireUnit { Id = "u0", Type = PlatformType.GroundBased, Position = new AVector3(5000, 0, 50), MuzzleVelocity = 800, TotalMunitions = 1, AmmoTypes = new() { AerosolType.InertGas, AerosolType.ActiveMaterial, AerosolType.ActiveFuel } },
|
|
};
|
|
var result = planner.Plan(fireUnits, new List<DroneGroup> { droneGroup }, detail.Scene);
|
|
scenario.SaveCloudDispersal(taskId, new CloudDispersal
|
|
{
|
|
PositionX = (droneGroup.Waypoints[0].PosX + droneGroup.Waypoints[^1].PosX) / 2,
|
|
PositionY = (droneGroup.Waypoints[0].PosY + droneGroup.Waypoints[^1].PosY) / 2,
|
|
PositionZ = (droneGroup.Waypoints[0].PosZ + droneGroup.Waypoints[^1].PosZ) / 2,
|
|
DisperseHeight = droneGroup.Target.TypicalAltitude,
|
|
Source = "Algorithm",
|
|
});
|
|
|
|
var equips = new List<EquipmentDeployment>();
|
|
foreach (var u in fireUnits)
|
|
equips.Add(new EquipmentDeployment
|
|
{
|
|
EquipmentRole = (int)EquipmentRole.LaunchPlatform,
|
|
PlatformType = (int)u.Type, Quantity = 1,
|
|
PositionX = u.Position.X, PositionY = u.Position.Y, PositionZ = u.Position.Z,
|
|
AerosolType = (int)u.AmmoTypes[0],
|
|
MunitionCount = u.TotalMunitions, Cooldown = u.Cooldown, MuzzleVelocity = u.MuzzleVelocity,
|
|
CruiseSpeed = u.CruiseSpeed > 0 ? u.CruiseSpeed : null,
|
|
ReleaseAltitude = u.ReleaseAltitude > 0 ? u.ReleaseAltitude : null,
|
|
});
|
|
scenario.SaveDeployment(taskId, equips);
|
|
|
|
db.Close();
|
|
|
|
var plan = result.Best;
|
|
Debug.Log($"规划方案: {plan.ThreatsEngaged} 威胁被分配, {plan.MergedSchedule.Count} 发, 概率 {plan.OverallProbability:P0}");
|
|
|
|
// 运行仿真
|
|
Runner = GetComponent<SimulationRunner>();
|
|
if (Runner == null) Runner = gameObject.AddComponent<SimulationRunner>();
|
|
else Runner.enabled = true;
|
|
Runner.LoadAndStart(taskId);
|
|
|
|
// 设置倍速
|
|
if (Runner.Engine != null)
|
|
{
|
|
Runner.Engine.TimeScale = _timeScale;
|
|
Debug.Log($"Engine state: {Runner.Engine.State}, drones: {Runner.Engine.Drones.Count}");
|
|
}
|
|
|
|
// 移动 Game 视图相机
|
|
var cam = Camera.main;
|
|
if (cam == null) { var cgo = new GameObject("MainCamera"); cgo.AddComponent<Camera>(); cam = cgo.GetComponent<Camera>(); cam.tag = "MainCamera"; }
|
|
cam.transform.position = new UVector3(_routeLength / 2f, 2000, -3000);
|
|
cam.transform.LookAt(new UVector3(_routeLength / 2f, 500, 0));
|
|
Debug.Log("Camera positioned. In Scene view, double-click 'Simulation' in Hierarchy to focus.");
|
|
}
|
|
}
|
|
}
|