From 1d8277cecd964f07ca28c99af328f4066f31ee79 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Fri, 12 Jun 2026 11:24:27 +0800 Subject: [PATCH] =?UTF-8?q?SimulationEngine:=206=E4=B8=AA=E8=A7=82?= =?UTF-8?q?=E5=AF=9F=E8=80=85=E4=BA=8B=E4=BB=B6=20+=20=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E5=A3=B0=E6=98=8E=E4=BF=AE=E5=A4=8D=20+=20=E9=87=8D=E5=86=99?= =?UTF-8?q?=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Simulation/SimulationEngine.cs | 141 +++++------------- 1 file changed, 39 insertions(+), 102 deletions(-) diff --git a/src/CounterDrone.Core/Simulation/SimulationEngine.cs b/src/CounterDrone.Core/Simulation/SimulationEngine.cs index d6d19ab..69eb8a4 100644 --- a/src/CounterDrone.Core/Simulation/SimulationEngine.cs +++ b/src/CounterDrone.Core/Simulation/SimulationEngine.cs @@ -9,16 +9,14 @@ using SQLite; namespace CounterDrone.Core.Simulation { - /// 发射计划中的单次事件 public class FireEvent { public float FireTime; - public int PlatformIndex; // 第几个发射平台(0-based) + public int PlatformIndex; public float TargetX, TargetY, TargetZ; public float MuzzleVelocity; } - /// 仿真引擎 — 纯执行器,不包含任何决策逻辑 /// 仿真引擎 — 纯执行器,接收发射计划按时间表执行 public class SimulationEngine { @@ -30,35 +28,37 @@ namespace CounterDrone.Core.Simulation public SimulationState State { get; private set; } = SimulationState.Idle; public int FrameIndex { get; private set; } public float SimulationTime { get; private set; } - /// 时间倍速:>1 加速仿真(仅测试或快速推演用) public float TimeScale { get; set; } = 1f; private float _tickInterval; + public IReadOnlyList Drones => _drones; + public IReadOnlyList Clouds => _clouds; + public IReadOnlyList Munitions => _munitions; + public IReadOnlyList Events => _allEvents; + + public event Action OnMunitionLaunched; + public event Action OnCloudGenerated; + public event Action OnDroneDestroyed; + public event Action OnDroneReachedTarget; + public event Action OnZoneIntruded; + public event Action OnSimulationEnded; + private List _drones = new(); private List _platforms = new(); private List _munitions = new(); private List _clouds = new(); private List _zones = new(); - private CombatScene _scene = new(); private float _disperseHeight; private AmmunitionSpec _ammoSpec = new(); private int _tickRate = 20; - - // 发射计划:算法预计算,引擎按时间表执行 private readonly List _fireSchedule = new(); private int _nextFireIndex; - private readonly List _allEvents = new(); private SQLiteConnection _frameDb = null!; private string _taskId = string.Empty; private int _entityCounter; - public IReadOnlyList Drones => _drones; - public IReadOnlyList Clouds => _clouds; - public IReadOnlyList Munitions => _munitions; - public IReadOnlyList Events => _allEvents; - public SimulationEngine(IScenarioService scenarioService, FrameDataStore frameStore, IDamageModel damageModel, IPathProvider paths) { @@ -68,7 +68,6 @@ namespace CounterDrone.Core.Simulation _paths = paths; } - /// 设置发射计划(来自推荐算法),在 Initialize 之前调用 public void SetFireSchedule(List schedule) { _fireSchedule.Clear(); @@ -88,13 +87,10 @@ namespace CounterDrone.Core.Simulation _tickInterval = 1.0f / _tickRate; using (var ammoDb = new SQLiteConnection(_paths.GetMainDbPath())) - { _ammoSpec = ammoDb.Table() .FirstOrDefault(a => a.AerosolType == config.Cloud.AerosolType) - ?? new AmmunitionSpec { InitialRadius = 50, CoreDensity = 1.0f, SourceStrength = 1.0, MaxRadius = 200, MaxDuration = 60 }; - } + ?? DefaultAmmunition.GetByType((AerosolType)config.Cloud.AerosolType); - // 无人机 _drones.Clear(); foreach (var target in config.Targets) { @@ -105,18 +101,12 @@ namespace CounterDrone.Core.Simulation target, config.Waypoints, i, spacing, mode)); } - // 装备 _platforms.Clear(); foreach (var equip in config.Equipment) - { if (equip.EquipmentRole != (int)EquipmentRole.Detection) - { for (int i = 0; i < equip.Quantity; i++) _platforms.Add(new PlatformEntity($"plat_{++_entityCounter}", equip)); - } - } - // 管控区域 _zones.Clear(); foreach (var z in config.ControlZones) _zones.Add(new ControlZoneEntity(z.Id, z.Name, z.VerticesJson, @@ -129,7 +119,6 @@ namespace CounterDrone.Core.Simulation SimulationTime = 0; _entityCounter = 0; _nextFireIndex = 0; - _frameDb = _frameStore.CreateOrOpen(_taskId); State = SimulationState.Running; } @@ -145,12 +134,10 @@ namespace CounterDrone.Core.Simulation var frameEvents = new List(); // 1. 按发射计划执行 - while (_nextFireIndex < _fireSchedule.Count && - _fireSchedule[_nextFireIndex].FireTime <= SimulationTime) + while (_nextFireIndex < _fireSchedule.Count && _fireSchedule[_nextFireIndex].FireTime <= SimulationTime) { var fe = _fireSchedule[_nextFireIndex++]; - var platform = _platforms.Count > fe.PlatformIndex - ? _platforms[fe.PlatformIndex] : null; + var platform = _platforms.Count > fe.PlatformIndex ? _platforms[fe.PlatformIndex] : null; if (platform != null && platform.Ready) { platform.Fire(); @@ -158,16 +145,10 @@ namespace CounterDrone.Core.Simulation platform.PlatformType ?? Models.PlatformType.GroundBased, platform.AerosolType ?? Models.AerosolType.InertGas, platform.PosX, platform.PosY, platform.PosZ, - fe.TargetX, fe.TargetY, fe.TargetZ, - fe.MuzzleVelocity, _disperseHeight); + fe.TargetX, fe.TargetY, fe.TargetZ, fe.MuzzleVelocity, _disperseHeight); _munitions.Add(m); - frameEvents.Add(new SimEvent - { - Type = SimEventType.MunitionLaunched, - OccurredAt = SimulationTime, - SourceId = platform.Id, - Description = $"计划发射 {m.Id}", - }); + OnMunitionLaunched?.Invoke(m); + frameEvents.Add(new SimEvent { Type = SimEventType.MunitionLaunched, OccurredAt = SimulationTime, SourceId = platform.Id, Description = $"计划发射 {m.Id}" }); } } @@ -178,16 +159,12 @@ namespace CounterDrone.Core.Simulation if (m.HasArrived) { var disp = AlgorithmFactory.Create(); - disp.Initialize(_ammoSpec, _scene, - new Algorithms.Vector3(m.TargetX, m.TargetY, m.TargetZ), SimulationTime); - _clouds.Add(new CloudEntity($"cloud_{++_entityCounter}", m.AerosolType, disp, SimulationTime)); + disp.Initialize(_ammoSpec, _scene, new Algorithms.Vector3(m.TargetX, m.TargetY, m.TargetZ), SimulationTime); + var cloud = new CloudEntity($"cloud_{++_entityCounter}", m.AerosolType, disp, SimulationTime); + _clouds.Add(cloud); _munitions.Remove(m); - frameEvents.Add(new SimEvent - { - Type = SimEventType.CloudGenerated, - OccurredAt = SimulationTime, - Description = $"云团生成", - }); + OnCloudGenerated?.Invoke(cloud); + frameEvents.Add(new SimEvent { Type = SimEventType.CloudGenerated, OccurredAt = SimulationTime, Description = "云团生成" }); } } @@ -206,18 +183,13 @@ namespace CounterDrone.Core.Simulation if (cloud.ContainsPoint(drone.PosX, drone.PosY, drone.PosZ)) { drone.ExposureTime += scaledDt; - var dmg = _damageModel.CalculateDamage( - drone.TargetType, drone.PowerType, cloud.AerosolType, - cloud.Dispersion.CoreDensity, drone.ExposureTime, scaledDt); + var dmg = _damageModel.CalculateDamage(drone.TargetType, drone.PowerType, cloud.AerosolType, cloud.Dispersion.CoreDensity, drone.ExposureTime, scaledDt); drone.ApplyDamage(dmg); if (drone.Status == DroneStatus.Destroyed) - frameEvents.Add(new SimEvent - { - Type = SimEventType.DroneDestroyed, - OccurredAt = SimulationTime, - TargetId = drone.Id, - Description = $"无人机 {drone.Id} 被摧毁", - }); + { + OnDroneDestroyed?.Invoke(drone); + frameEvents.Add(new SimEvent { Type = SimEventType.DroneDestroyed, OccurredAt = SimulationTime, TargetId = drone.Id, Description = $"无人机 {drone.Id} 被摧毁" }); + } } } } @@ -227,13 +199,10 @@ namespace CounterDrone.Core.Simulation { drone.Update(scaledDt, (float)_scene.WindSpeed, (WindDirection)_scene.WindDirection); if (drone.Status == DroneStatus.ReachedTarget) - frameEvents.Add(new SimEvent - { - Type = SimEventType.DroneReachedTarget, - OccurredAt = SimulationTime, - SourceId = drone.Id, - Description = "到达攻击目标", - }); + { + OnDroneReachedTarget?.Invoke(drone); + frameEvents.Add(new SimEvent { Type = SimEventType.DroneReachedTarget, OccurredAt = SimulationTime, SourceId = drone.Id, Description = "到达攻击目标" }); + } } // 6. 平台冷却 @@ -247,14 +216,8 @@ namespace CounterDrone.Core.Simulation if (zone.ContainsPoint(drone.PosX, drone.PosY, drone.PosZ)) { drone.MarkZoneIntruded(); - frameEvents.Add(new SimEvent - { - Type = SimEventType.ZoneIntruded, - OccurredAt = SimulationTime, - SourceId = drone.Id, - TargetId = zone.Id, - Description = $"侵入 {zone.Name}", - }); + OnZoneIntruded?.Invoke(drone, zone); + frameEvents.Add(new SimEvent { Type = SimEventType.ZoneIntruded, OccurredAt = SimulationTime, SourceId = drone.Id, TargetId = zone.Id, Description = $"侵入 {zone.Name}" }); } } } @@ -263,24 +226,17 @@ namespace CounterDrone.Core.Simulation if (_drones.All(d => d.Status != DroneStatus.Flying)) { State = SimulationState.Completed; + OnSimulationEnded?.Invoke(); frameEvents.Add(new SimEvent { Type = SimEventType.SimulationEnd, OccurredAt = SimulationTime }); } _allEvents.AddRange(frameEvents); - // 录制帧 var snapshots = CollectSnapshots(); _frameStore.WriteFrame(_frameDb, _taskId, FrameIndex, SimulationTime, snapshots); _frameDb.Commit(); - return new SimulationFrameResult - { - EntitySnapshots = snapshots, - NewEvents = frameEvents, - State = State, - FrameIndex = FrameIndex, - SimulationTime = SimulationTime, - }; + return new SimulationFrameResult { EntitySnapshots = snapshots, NewEvents = frameEvents, State = State, FrameIndex = FrameIndex, SimulationTime = SimulationTime }; } public void Pause() { if (State == SimulationState.Running) State = SimulationState.Paused; } @@ -291,28 +247,9 @@ namespace CounterDrone.Core.Simulation { var list = new List(); foreach (var d in _drones) - { - var stage = _damageModel.GetDamageStage(1 - d.Hp); - list.Add(new EntitySnapshot - { - EntityId = d.Id, - EntityType = Models.EntityType.Drone, - PosX = d.PosX, - PosY = d.PosY, - PosZ = d.PosZ, - StateData = JsonSerializer.Serialize(new { damageStage = (int)stage, hp = d.Hp }), - }); - } + list.Add(new EntitySnapshot { EntityId = d.Id, EntityType = Models.EntityType.Drone, PosX = d.PosX, PosY = d.PosY, PosZ = d.PosZ, StateData = JsonSerializer.Serialize(new { damageStage = (int)_damageModel.GetDamageStage(1 - d.Hp), hp = d.Hp }) }); foreach (var c in _clouds) - list.Add(new EntitySnapshot - { - EntityId = c.Id, - EntityType = Models.EntityType.Cloud, - PosX = c.Dispersion.Center.X, - PosY = c.Dispersion.Center.Y, - PosZ = c.Dispersion.Center.Z, - StateData = JsonSerializer.Serialize(new { radius = c.Dispersion.Radius, opacity = c.Dispersion.Particles.Opacity }), - }); + list.Add(new EntitySnapshot { EntityId = c.Id, EntityType = Models.EntityType.Cloud, PosX = c.Dispersion.Center.X, PosY = c.Dispersion.Center.Y, PosZ = c.Dispersion.Center.Z, StateData = JsonSerializer.Serialize(new { radius = c.Dispersion.Radius, opacity = c.Dispersion.Particles.Opacity }) }); return list; } }