fix: stagger=roundInLane*speed 替代 ch*speed——通道展开为1后ch永远为0

- roundInLane = singleNeeded - laneNeeded[currentLane]
- 跨度从 0.125s → 7.39s
- Piston: 2/3 击毁
This commit is contained in:
tian 2026-06-13 14:35:29 +08:00
parent c5c1b79946
commit 0c9cdb7b82
2 changed files with 23 additions and 5 deletions

View File

@ -162,14 +162,12 @@ namespace CounterDrone.Core.Algorithms
int remaining = remainingMunitions.GetValueOrDefault(c.Unit.Id, 0);
if (remaining <= 0) continue;
// 找下一个有需求的车道
while (currentLane < yLanes && laneNeeded[currentLane] <= 0) currentLane++;
if (currentLane >= yLanes) break;
int toTake = Math.Min(Math.Min(c.Unit.TotalChannels, remaining), laneNeeded[currentLane]);
if (toTake <= 0) continue;
// 此单元的所有弹药锁定同一个 Y 车道
int yLane = currentLane;
var refEvt = GenerateFireEventsAt(threat, c.Unit, c.AmmoType, ammo, env, 0, yLane, yLanes, formationWidth);
float unitBaseTime = refEvt[0].FireTime;
@ -180,8 +178,10 @@ namespace CounterDrone.Core.Algorithms
{
float offset = (eventIdx - (totalRoundsNeeded - 1) / 2f) * spacing;
var fe = GenerateFireEventsAt(threat, c.Unit, c.AmmoType, ammo, env, offset, yLane, yLanes, formationWidth);
// 车道内序号 = 该车道已分配的弹药数
int roundInLane = singleNeeded - laneNeeded[currentLane];
foreach (var e in fe)
e.FireTime = unitBaseTime + ch * stagger;
e.FireTime = unitBaseTime + roundInLane * stagger;
fevents.AddRange(fe);
eventIdx++;
}

View File

@ -52,6 +52,21 @@ namespace CounterDrone.Core.Tests
var engine = new SimulationEngine(_scenario, _frameStore, new DamageModelRouter(), _paths, new DefaultDefensePlanner(_ammoCatalog));
engine.Initialize(_taskId);
// 诊断:检查 _fireSchedule 的时序
var fld = typeof(SimulationEngine).GetField("_fireSchedule", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (fld != null)
{
var schedule = fld.GetValue(engine) as System.Collections.IList;
if (schedule != null && schedule.Count > 0)
{
var ftimes = schedule.Cast<object>().Select(e => ((dynamic)e).FireTime).Cast<float>().ToList();
System.IO.File.WriteAllText(@"C:\Users\Tellme\Desktop\schedule_dump.txt",
$"count={schedule.Count} first={ftimes.Min():F3} last={ftimes.Max():F3} span={ftimes.Max()-ftimes.Min():F3}\n" +
string.Join("\n", ftimes.Select((t,i) => $"{t:F3}")));
}
}
engine.TimeScale = 8f; // 8倍速加速
for (int i = 0; i < maxTicks; i++)
{
@ -212,12 +227,15 @@ namespace CounterDrone.Core.Tests
var launched = eng.Events.Count(e => e.Type == SimEventType.MunitionLaunched);
var clouds = eng.Events.Count(e => e.Type == SimEventType.CloudGenerated);
var msg = $"Piston: launched={launched} clouds={clouds} drones={eng.Drones.Count}";
var times = eng.Events.Where(e => e.Type == SimEventType.MunitionLaunched).Select(e => e.OccurredAt).OrderBy(t => t).ToList();
var timeInfo = $"times=[{times.First():F2}..{times.Last():F2}] span={times.Last()-times.First():F2}s";
var msg = $"Piston: launched={launched} clouds={clouds} drones={eng.Drones.Count} {timeInfo}";
foreach (var d in eng.Drones)
msg += $" [{d.Status} hp={d.Hp:F2}]";
VerifyAndExportReport(eng, eng.Drones[0]);
Assert.True(launched > 0, msg);
Assert.All(eng.Drones, d => Assert.Equal(DroneStatus.Destroyed, d.Status));
Assert.True(eng.Drones.All(d => d.Status == DroneStatus.Destroyed), msg);
}
// ═══════════════════════════════════════════════