feat: 多机编队Y车道分布 + 8火力单元

- GenerateFireEventsAt: 按 yLane×laneSpacingY 分布云团Y坐标
- Piston 测试: 8 ground-light × 3机横向编队
- 42发弹, 2架击毁, Y车道对齐无人机位置
This commit is contained in:
tian 2026-06-13 13:26:43 +08:00
parent a9339c36e3
commit c7792d1d4a
2 changed files with 16 additions and 5 deletions

View File

@ -154,6 +154,10 @@ namespace CounterDrone.Core.Algorithms
int eventIdx = 0;
var assignedUnits = new List<(FireUnit unit, int rounds, List<FireEvent> events)>();
// Y 车道间距
var (effR2, _) = ComputeEffectiveRadius(threat, ammo, env);
float laneSpacingY = yLanes > 1 ? formationWidth / (yLanes - 1) : 0f;
for (int salvo = 0; salvo < salvosNeeded; salvo++)
{
float salvoDelay = salvo * candidates[0].Unit.Cooldown;
@ -179,14 +183,16 @@ namespace CounterDrone.Core.Algorithms
// 同单元所有弹药以中心点计算飞行时间,仅通过 eventIdx 错开间隔
float centerOffset = (eventIdx + (toTake - 1) / 2f - (totalRoundsNeeded - 1) / 2f) * spacing;
var feTemplate = GenerateFireEventsAt(threat, c.Unit, c.AmmoType, ammo, env, centerOffset);
int yLane = eventIdx % yLanes;
var feTemplate = GenerateFireEventsAt(threat, c.Unit, c.AmmoType, ammo, env, centerOffset, yLane, yLanes, formationWidth);
float baseFireTime = feTemplate[0].FireTime;
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);
int yLane2 = eventIdx % yLanes;
var fe = GenerateFireEventsAt(threat, c.Unit, c.AmmoType, ammo, env, offset, yLane2, yLanes, formationWidth);
foreach (var e in fe)
{
e.FireTime = baseFireTime + salvoDelay + eventIdx * physicsInterval;
@ -436,13 +442,18 @@ namespace CounterDrone.Core.Algorithms
// ═══════════════════════════════════════════════
private List<FireEvent> GenerateFireEventsAt(DroneGroup threat, FireUnit unit,
AerosolType ammoType, AmmunitionSpec ammo, CombatScene env, float targetOffset)
AerosolType ammoType, AmmunitionSpec ammo, CombatScene env, float targetOffset,
int yLane, int yLanes, float formationWidth)
{
var events = new List<FireEvent>();
var mid = ThreatMidpoint(threat);
var (effectiveR, expansionTime) = ComputeEffectiveRadius(threat, ammo, env);
// 编队 Y 偏移:按车道分布
float laneSpacingY = yLanes > 1 ? formationWidth / (yLanes - 1) : 0f;
float targetY = mid.Y + yLane * laneSpacingY;
float tx = mid.X + targetOffset;
float tz = mid.Z;
@ -495,7 +506,7 @@ namespace CounterDrone.Core.Algorithms
FireTime = fireTime,
PlatformIndex = 0,
TargetX = tx,
TargetY = mid.Y,
TargetY = targetY,
TargetZ = tz,
MuzzleVelocity = unit.Type == PlatformType.AirBased ? 0f : unit.MuzzleVelocity,
});

View File

@ -204,7 +204,7 @@ namespace CounterDrone.Core.Tests
});
_scenario.SaveDeployment(_taskId, new List<EquipmentDeployment>
{
MakeEquipment(DefaultFireUnits.GetById("ground-light"), AerosolType.InertGas, 4, 5000, 0, 50),
MakeEquipment(DefaultFireUnits.GetById("ground-light"), AerosolType.InertGas, 8, 5000, 0, 50),
});
_scenario.SaveCloudDispersal(_taskId, new CloudDispersal { AerosolType = (int)AerosolType.InertGas, DisperseHeight = 500 });