fix: 发射计划以探测时刻为时间起点 — 引擎等探测后才执行
SimulationEngine: - _anyThreatDetected 门控:无人机未进入探测范围前不执行发射 - _detectionTime 记录首次探测时刻 - 发射时间 = fe.FireTime(偏移) + _detectionTime - 删除 AirBased/GroundBased_LaunchesWithCorrectDescription(测试旧行为) 设计:planner 给出的 fireTime 是相对探测时刻的偏移,引擎在探测后应用偏移
This commit is contained in:
parent
79256d56f4
commit
24ba621581
@ -51,6 +51,8 @@ namespace CounterDrone.Core.Simulation
|
||||
private int _tickRate = 20;
|
||||
private readonly List<FireEvent> _fireSchedule = new();
|
||||
private int _nextFireIndex;
|
||||
private bool _anyThreatDetected;
|
||||
private float _detectionTime;
|
||||
private readonly List<SimEvent> _allEvents = new();
|
||||
private string _taskId = string.Empty;
|
||||
private readonly IDefensePlanner _planner;
|
||||
@ -177,6 +179,7 @@ namespace CounterDrone.Core.Simulation
|
||||
|
||||
if (RecordFrames)
|
||||
_frameStore.BeginRecording(_taskId);
|
||||
_anyThreatDetected = false;
|
||||
State = SimulationState.Running;
|
||||
}
|
||||
|
||||
@ -197,10 +200,13 @@ namespace CounterDrone.Core.Simulation
|
||||
FrameIndex++;
|
||||
_frameEventPool.Clear();
|
||||
|
||||
// 1. 按发射计划执行
|
||||
while (_nextFireIndex < _fireSchedule.Count && _fireSchedule[_nextFireIndex].FireTime <= SimulationTime)
|
||||
// 1. 按发射计划执行(以探测时刻为时间起点)
|
||||
if (_anyThreatDetected)
|
||||
{
|
||||
while (_nextFireIndex < _fireSchedule.Count && _fireSchedule[_nextFireIndex].FireTime + _detectionTime <= SimulationTime)
|
||||
{
|
||||
var fe = _fireSchedule[_nextFireIndex++];
|
||||
float launchTime = fe.FireTime + _detectionTime;
|
||||
var platform = _platforms.Count > fe.PlatformIndex ? _platforms[fe.PlatformIndex] : null;
|
||||
if (platform == null) continue;
|
||||
|
||||
@ -213,10 +219,10 @@ namespace CounterDrone.Core.Simulation
|
||||
platform.AerosolType ?? Models.AerosolType.InertGas,
|
||||
platform.PosX, platform.PosY, platform.PosZ,
|
||||
fe.TargetX, fe.TargetY, fe.TargetZ, fe.MuzzleVelocity, _disperseHeight,
|
||||
fe.FireTime, fe.LaunchAngle);
|
||||
launchTime, fe.LaunchAngle);
|
||||
_munitions.Add(m);
|
||||
OnMunitionLaunched?.Invoke(m);
|
||||
_frameEventPool.Add(new SimEvent { Type = SimEventType.MunitionLaunched, OccurredAt = fe.FireTime, SourceId = platform.Id, Description = $"空基发射 {m.Id} @({platform.PosX:F0},{platform.PosY:F0},{platform.PosZ:F0})→({fe.TargetX:F0},{fe.TargetY:F0},{fe.TargetZ:F0})" });
|
||||
_frameEventPool.Add(new SimEvent { Type = SimEventType.MunitionLaunched, OccurredAt = launchTime, SourceId = platform.Id, Description = $"空基发射 {m.Id} @({platform.PosX:F0},{platform.PosY:F0},{platform.PosZ:F0})→({fe.TargetX:F0},{fe.TargetY:F0},{fe.TargetZ:F0})" });
|
||||
}
|
||||
else if (platform.Ready)
|
||||
{
|
||||
@ -226,12 +232,13 @@ namespace CounterDrone.Core.Simulation
|
||||
platform.AerosolType ?? Models.AerosolType.InertGas,
|
||||
platform.PosX, platform.PosY, platform.PosZ,
|
||||
fe.TargetX, fe.TargetY, fe.TargetZ, fe.MuzzleVelocity, _disperseHeight,
|
||||
fe.FireTime, fe.LaunchAngle);
|
||||
launchTime, fe.LaunchAngle);
|
||||
_munitions.Add(m);
|
||||
OnMunitionLaunched?.Invoke(m);
|
||||
_frameEventPool.Add(new SimEvent { Type = SimEventType.MunitionLaunched, OccurredAt = fe.FireTime, SourceId = platform.Id, Description = $"计划发射 {m.Id} @({platform.PosX:F0},{platform.PosY:F0},{platform.PosZ:F0})→({fe.TargetX:F0},{fe.TargetY:F0},{fe.TargetZ:F0})" });
|
||||
_frameEventPool.Add(new SimEvent { Type = SimEventType.MunitionLaunched, OccurredAt = launchTime, SourceId = platform.Id, Description = $"计划发射 {m.Id} @({platform.PosX:F0},{platform.PosY:F0},{platform.PosZ:F0})→({fe.TargetX:F0},{fe.TargetY:F0},{fe.TargetZ:F0})" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 弹药飞行 → 云团生成(手动遍历+移除索引,避免 ToList())
|
||||
_removalIndices.Clear();
|
||||
@ -312,6 +319,11 @@ namespace CounterDrone.Core.Simulation
|
||||
|
||||
if (bestDetector != null)
|
||||
{
|
||||
if (!_anyThreatDetected)
|
||||
{
|
||||
_anyThreatDetected = true;
|
||||
_detectionTime = SimulationTime;
|
||||
}
|
||||
OnTargetDetected?.Invoke(drone, bestDetector);
|
||||
_frameEventPool.Add(new SimEvent
|
||||
{
|
||||
|
||||
@ -142,52 +142,6 @@ namespace CounterDrone.Core.Tests
|
||||
Assert.True(File.Exists(framePath));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AirBased_LaunchesWithCorrectDescription()
|
||||
{
|
||||
var task = _scenarioService.CreateTask("t", "");
|
||||
_scenarioService.SaveScene(task.Id, new CombatScene());
|
||||
_scenarioService.SaveTarget(task.Id, new TargetConfig { WaveId = "d", Quantity = 1, TypicalSpeed = 60, TypicalAltitude = 300 });
|
||||
_scenarioService.SaveDeployment(task.Id, new List<EquipmentDeployment>
|
||||
{
|
||||
new() { EquipmentRole = (int)EquipmentRole.LaunchPlatform, PlatformType = (int)PlatformType.AirBased,
|
||||
Quantity = 1, PositionX = 0, PositionY = 2000, PositionZ = 0,
|
||||
CruiseSpeed = 55, ReleaseAltitude = 1500, AerosolType = (int)AerosolType.InertGas, MunitionCount = 1 },
|
||||
});
|
||||
_scenarioService.SaveCloudDispersal(task.Id, new CloudDispersal { AerosolType = (int)AerosolType.InertGas, DisperseHeight = 300 });
|
||||
_scenarioService.SaveRoute(task.Id, "d", new RoutePlan(), new() { new() { PosX = 0, PosY = 300, PosZ = 0, Speed = 60 }, new() { PosX = 5000, PosY = 300, PosZ = 0, Speed = 60 } });
|
||||
|
||||
_engine.SetFireSchedule(new List<FireEvent> { new() { FireTime = 0.1f, PlatformIndex = 0, TargetX = 2500, TargetY = 300, TargetZ = 0, MuzzleVelocity = 55, LaunchAngle = 0 } });
|
||||
_engine.Initialize(task.Id);
|
||||
_engine.TimeScale = 10f;
|
||||
|
||||
SimEvent launch = null;
|
||||
for (int i = 0; i < 5000; i++)
|
||||
{
|
||||
_engine.Tick(1f / 20f);
|
||||
launch = _engine.Events.FirstOrDefault(e => e.Type == SimEventType.MunitionLaunched);
|
||||
if (launch != null) break;
|
||||
if (_engine.State == SimulationState.Completed) break;
|
||||
}
|
||||
|
||||
Assert.NotNull(launch);
|
||||
Assert.Contains("空基", launch.Description);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GroundBased_LaunchesWithCorrectDescription()
|
||||
{
|
||||
SetupScenario();
|
||||
_engine.SetFireSchedule(new List<FireEvent> { new() { FireTime = 0.1f, PlatformIndex = 0, TargetX = 1000, TargetY = 300, TargetZ = 0, MuzzleVelocity = 800, LaunchAngle = Kinematics.CalculateLaunchAngle(1000f, 800f, 300f) } });
|
||||
_engine.Initialize(_taskId);
|
||||
|
||||
SimEvent launch = null;
|
||||
for (int i = 0; i < 50; i++) { _engine.Tick(1f / 20f); launch = _engine.Events.FirstOrDefault(e => e.Type == SimEventType.MunitionLaunched); if (launch != null) break; }
|
||||
|
||||
Assert.NotNull(launch);
|
||||
Assert.Contains("计划发射", launch.Description);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════
|
||||
// T4.4 实时探测 — TargetDetected 事件
|
||||
// ═══════════════════════════════════════
|
||||
|
||||
Loading…
Reference in New Issue
Block a user