From c7792d1d4a48a25ae3c699b74eff9dbffa6f760a Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Sat, 13 Jun 2026 13:26:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A4=9A=E6=9C=BA=E7=BC=96=E9=98=9FY?= =?UTF-8?q?=E8=BD=A6=E9=81=93=E5=88=86=E5=B8=83=20+=208=E7=81=AB=E5=8A=9B?= =?UTF-8?q?=E5=8D=95=E5=85=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GenerateFireEventsAt: 按 yLane×laneSpacingY 分布云团Y坐标 - Piston 测试: 8 ground-light × 3机横向编队 - 42发弹, 2架击毁, Y车道对齐无人机位置 --- .../Algorithms/DefaultDefensePlanner.cs | 19 +++++++++++++++---- .../FullPipelineTests.cs | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/CounterDrone.Core/Algorithms/DefaultDefensePlanner.cs b/src/CounterDrone.Core/Algorithms/DefaultDefensePlanner.cs index d235e40..86d62d0 100644 --- a/src/CounterDrone.Core/Algorithms/DefaultDefensePlanner.cs +++ b/src/CounterDrone.Core/Algorithms/DefaultDefensePlanner.cs @@ -154,6 +154,10 @@ namespace CounterDrone.Core.Algorithms int eventIdx = 0; var assignedUnits = new List<(FireUnit unit, int rounds, List 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(); 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 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(); 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, }); diff --git a/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs b/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs index 84ed2c6..f3d396e 100644 --- a/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs +++ b/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs @@ -204,7 +204,7 @@ namespace CounterDrone.Core.Tests }); _scenario.SaveDeployment(_taskId, new List { - 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 });