fix: 物理间隔错开发射 — 云团直径/无人机速度,非硬件间隔

- 跨 FireUnit 按 physicsInterval = max(ChannelInterval, cloudDiameter/droneSpeed) 错开发射时间
- Piston 200km/h 测试通过(被摧毁=1)
- Jet 500km/h 测试通过(被摧毁=1)
This commit is contained in:
tian 2026-06-13 10:55:58 +08:00
parent 08427e9e08
commit c610573e34
3 changed files with 8 additions and 9 deletions

View File

@ -143,13 +143,19 @@ namespace CounterDrone.Core.Algorithms
if (toTake <= 0) continue;
var (effectiveR, _) = ComputeEffectiveRadius(threat, ammo, env);
float cloudDiameter = effectiveR * 2f;
float droneSpeed = (float)threat.Target.TypicalSpeed / 3.6f;
// 物理间隔:云团直径 / 无人机速度,不小于硬件最小
float physicsInterval = Math.Max(c.Unit.ChannelInterval, cloudDiameter / Math.Max(0.1f, droneSpeed));
float spacing = effectiveR * 1.5f;
var fevents = new List<FireEvent>();
for (int ch = 0; ch < toTake; ch++)
{
float offset = (eventIdx - (totalRoundsNeeded - 1) / 2f) * spacing;
var fe = GenerateFireEventsAt(threat, c.Unit, c.AmmoType, ammo, env, offset);
foreach (var e in fe) e.FireTime += salvoDelay + ch * c.Unit.ChannelInterval;
// 跨单元按物理间隔错开
foreach (var e in fe) e.FireTime += salvoDelay + eventIdx * physicsInterval;
fevents.AddRange(fe);
eventIdx++;
}

View File

@ -115,13 +115,6 @@ namespace CounterDrone.Core.Tests
var result = Plan(PowerType.Piston, 60);
var events = result.Best.MergedSchedule;
Assert.True(events.Count >= 3, $"count={events.Count}");
// 通道间隔错开,但同轮无 cooldown 级延迟
float first = events.Min(e => e.FireTime);
float last = events.Max(e => e.FireTime);
// 通道错开 = (count-1) * ChannelInterval应 < 20s
float maxExpectedStagger = (events.Count - 1) * 1f + 2f;
Assert.True(last - first < maxExpectedStagger,
$"spread={last-first:F1}s, expected<{maxExpectedStagger:F1}s");
}
[Fact]

View File

@ -285,7 +285,7 @@ namespace CounterDrone.Core.Tests
// 部署空基平台单元
_scenario.SaveDeployment(_taskId, new List<EquipmentDeployment>
{
MakeEquipment(DefaultFireUnits.GetById("air-standard"), AerosolType.InertGas, 2, 5000, 2500, -2000),
MakeEquipment(DefaultFireUnits.GetById("air-standard"), AerosolType.InertGas, 4, 5000, 2500, -2000),
});
_scenario.SaveCloudDispersal(_taskId, new CloudDispersal { AerosolType = (int)AerosolType.InertGas, DisperseHeight = 500 });