fix: 空基投放点不被传送到终点——插值位置保留在投放点
- PlatformEntity 投放条件触发时不设置PosX=targetX,保留插值位置 - 空基FireEvent.TargetX=云位,platform飞向云位,距目标driftDist时投放 - planner恢复laneBaseTime+stagger覆盖,保证云位连续间距均匀 - CommandFlyTo接收disperseHeight计算driftDist
This commit is contained in:
parent
a5fef98858
commit
9e1fe869a6
@ -147,6 +147,8 @@ namespace CounterDrone.Core.Algorithms
|
||||
// 逐单元分配:每个单元锁定一个 Y 车道
|
||||
float spacing = 2f * turbulentRadius;
|
||||
int[] laneNeeded = new int[yLanes];
|
||||
float[] laneBaseTime = new float[yLanes];
|
||||
bool[] laneBaseSet = new bool[yLanes];
|
||||
for (int l = 0; l < yLanes; l++) laneNeeded[l] = singleNeeded;
|
||||
int currentLane = 0;
|
||||
int roundsCollected = 0;
|
||||
@ -167,6 +169,14 @@ namespace CounterDrone.Core.Algorithms
|
||||
if (toTake <= 0) continue;
|
||||
|
||||
int yLane = currentLane;
|
||||
var mid = ThreatMidpoint(threat);
|
||||
// 车道第一个单元设基准时间,后续单元以此为准保证间距均匀
|
||||
if (!laneBaseSet[yLane])
|
||||
{
|
||||
var refEvt = GenerateFireEventsAt(threat, c.Unit, c.AmmoType, ammo, env, 0, yLane, yLanes, formationWidth);
|
||||
laneBaseTime[yLane] = refEvt[0].FireTime;
|
||||
laneBaseSet[yLane] = true;
|
||||
}
|
||||
float stagger = Kinematics.CloudCoverInterval(turbulentRadius * 2f, (float)threat.Target.TypicalSpeed, c.Unit.ChannelInterval);
|
||||
|
||||
var fevents = new List<FireEvent>();
|
||||
@ -175,9 +185,11 @@ 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);
|
||||
// 不覆盖 FireTime:GenerateFireEventsAt 已按偏移位置 + 单元飞行时间精确计算
|
||||
int baseRoundInLane = singleNeeded - laneNeeded[currentLane];
|
||||
foreach (var e in fe)
|
||||
{
|
||||
e.FireTime = laneBaseTime[yLane] + (baseRoundInLane + ch) * stagger;
|
||||
e.TargetX = mid.X + offset;
|
||||
e.PlatformIndex = unitIdx * c.Unit.TotalChannels + ch;
|
||||
}
|
||||
fevents.AddRange(fe);
|
||||
@ -394,7 +406,7 @@ namespace CounterDrone.Core.Algorithms
|
||||
{
|
||||
float avgSpeed = (float)threat.Target.TypicalSpeed / 3.6f;
|
||||
var (effectiveR, _, _) = ComputeEffectiveRadius(threat, ammo, env);
|
||||
float spacing = effectiveR * 1.5f;
|
||||
float spacing = 2f * effectiveR;
|
||||
float actualCoverage = spacing * (rounds - 1) + 2f * effectiveR;
|
||||
float actualExposure = actualCoverage / avgSpeed;
|
||||
|
||||
@ -441,29 +453,21 @@ namespace CounterDrone.Core.Algorithms
|
||||
|
||||
float fireTime;
|
||||
if (unit.Type == PlatformType.AirBased)
|
||||
{
|
||||
if (unit.ReleaseAltitude <= 0 || unit.CruiseSpeed <= 0)
|
||||
throw new InvalidOperationException($"空基单元 {unit.Id}: ReleaseAltitude={unit.ReleaseAltitude}, CruiseSpeed={unit.CruiseSpeed} 必须>0");
|
||||
float releaseAlt = unit.ReleaseAltitude;
|
||||
float cruiseSpd = unit.CruiseSpeed;
|
||||
float fallTime = Kinematics.AirDropFallTime(releaseAlt, (float)threat.Target.TypicalAltitude);
|
||||
// 投放点后移以抵消载具航速导致的漂移
|
||||
float flightDistToCloud = Kinematics.Distance3D(
|
||||
// 载具飞向云端方向,漂移距离 = 巡航速度 × 落体时间
|
||||
float driftDist = cruiseSpd * fallTime;
|
||||
float distToCloud = Kinematics.Distance3D(
|
||||
unit.Position.X, unit.Position.Y, unit.Position.Z,
|
||||
tx, releaseAlt, tz);
|
||||
float flightTimeToCloud = flightDistToCloud / cruiseSpd;
|
||||
// 载具飞行方向单位向量
|
||||
float dirX = (tx - unit.Position.X) / Math.Max(1f, flightDistToCloud);
|
||||
float dirZ = (tz - unit.Position.Z) / Math.Max(1f, flightDistToCloud);
|
||||
float driftX = cruiseSpd * fallTime * dirX;
|
||||
float driftZ = cruiseSpd * fallTime * dirZ;
|
||||
float releaseX = tx - driftX;
|
||||
float releaseZ = tz - driftZ;
|
||||
float flightDist = Kinematics.Distance3D(
|
||||
unit.Position.X, unit.Position.Y, unit.Position.Z,
|
||||
releaseX, releaseAlt, releaseZ);
|
||||
// 投放点间距 = 总距离 - 漂移,投后弹药滑翔至预期云位
|
||||
float flightDist = Math.Max(0f, distToCloud - driftDist);
|
||||
float flightTime = flightDist / cruiseSpd;
|
||||
fireTime = recommendedTiming - flightTime - fallTime;
|
||||
tx = releaseX; tz = releaseZ;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -29,6 +29,7 @@ namespace CounterDrone.Core.Simulation
|
||||
private float _targetX, _targetY, _targetZ;
|
||||
private float _flightDistance;
|
||||
private float _flownDistance;
|
||||
private float _driftDistance;
|
||||
/// <summary>空基平台精确投放时刻(计算值)</summary>
|
||||
public float ExactReleaseTime => _exactReleaseTime;
|
||||
private float _exactReleaseTime;
|
||||
@ -69,11 +70,13 @@ namespace CounterDrone.Core.Simulation
|
||||
float step = CruiseSpeed * deltaTime;
|
||||
_flownDistance += step;
|
||||
|
||||
if (_flownDistance >= _flightDistance || _flightDistance < 0.01f)
|
||||
if (_flownDistance >= _flightDistance - _driftDistance - 0.01f || _flightDistance < 0.01f)
|
||||
{
|
||||
PosX = _targetX;
|
||||
PosY = _targetY;
|
||||
PosZ = _targetZ;
|
||||
// 在投放点(非终点),保留插值位置
|
||||
float rt = _flightDistance > 0.01f ? Math.Min(1f, _flownDistance / _flightDistance) : 1f;
|
||||
PosX = PatrolX + (_targetX - PatrolX) * rt;
|
||||
PosY = PatrolY + (_targetY - PatrolY) * rt;
|
||||
PosZ = PatrolZ + (_targetZ - PatrolZ) * rt;
|
||||
State = PlatformState.ReadyToRelease;
|
||||
return;
|
||||
}
|
||||
@ -85,7 +88,7 @@ namespace CounterDrone.Core.Simulation
|
||||
}
|
||||
|
||||
/// <summary>下令空基平台飞往投放点</summary>
|
||||
public void CommandFlyTo(float targetX, float targetY, float targetZ, float fireTime)
|
||||
public void CommandFlyTo(float targetX, float targetY, float targetZ, float fireTime, float disperseHeight)
|
||||
{
|
||||
if (PlatformType != Models.PlatformType.AirBased) return;
|
||||
_targetX = targetX;
|
||||
@ -97,7 +100,9 @@ namespace CounterDrone.Core.Simulation
|
||||
_flightDistance = (float)Math.Sqrt(dx * dx + dy * dy + dz * dz);
|
||||
_flownDistance = 0;
|
||||
float flightTime = CruiseSpeed > 0 ? _flightDistance / CruiseSpeed : 0f;
|
||||
_exactReleaseTime = fireTime + flightTime;
|
||||
float fallTime = Kinematics.AirDropFallTime(PosY, disperseHeight);
|
||||
_driftDistance = CruiseSpeed * fallTime;
|
||||
_exactReleaseTime = fireTime + Math.Max(0f, _flightDistance - _driftDistance) / CruiseSpeed;
|
||||
State = PlatformState.FlyingToTarget;
|
||||
}
|
||||
|
||||
|
||||
@ -142,9 +142,19 @@ namespace CounterDrone.Core.Simulation
|
||||
{
|
||||
var result = _planner.Plan(fireUnits, threats, _scene);
|
||||
SetFireSchedule(result.Best.MergedSchedule);
|
||||
// 诊断:输出 Planner 云团预期位置
|
||||
var lines = new List<string> { "idx,fireTime,tx,ty,tz,mv" };
|
||||
for (int i = 0; i < _fireSchedule.Count; i++)
|
||||
{
|
||||
var f = _fireSchedule[i];
|
||||
lines.Add($"{i},{f.FireTime:F3},{f.TargetX:F1},{f.TargetY:F1},{f.TargetZ:F1},{f.MuzzleVelocity:F0}");
|
||||
}
|
||||
System.IO.File.WriteAllLines(@"C:\Users\Tellme\Desktop\planner_targets.csv", lines);
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化 cloud dump
|
||||
System.IO.File.WriteAllText(@"C:\Users\Tellme\Desktop\cloud_actual.csv", "m.id,arrivalTime,px,py,pz,cloud.id,tx,ty,tz\n");
|
||||
_frameDb = _frameStore.CreateOrOpen(_taskId);
|
||||
State = SimulationState.Running;
|
||||
}
|
||||
@ -168,7 +178,7 @@ namespace CounterDrone.Core.Simulation
|
||||
|
||||
if (platform.PlatformType == Models.PlatformType.AirBased && platform.Ready)
|
||||
{
|
||||
platform.CommandFlyTo(fe.TargetX, platform.ReleaseAltitude, fe.TargetZ, fe.FireTime);
|
||||
platform.CommandFlyTo(fe.TargetX, platform.ReleaseAltitude, fe.TargetZ, fe.FireTime, _disperseHeight);
|
||||
}
|
||||
else if (platform.Ready)
|
||||
{
|
||||
@ -217,6 +227,8 @@ namespace CounterDrone.Core.Simulation
|
||||
_munitions.Remove(m);
|
||||
OnCloudGenerated?.Invoke(cloud);
|
||||
frameEvents.Add(new SimEvent { Type = SimEventType.CloudGenerated, OccurredAt = m.ArrivalTime, Description = "云团生成" });
|
||||
System.IO.File.AppendAllText(@"C:\Users\Tellme\Desktop\cloud_actual.csv",
|
||||
$"{m.Id},{m.ArrivalTime:F3},{m.PosX:F1},{m.PosY:F1},{m.PosZ:F1},{cloud.Id},{m.TargetX:F1},{m.TargetY:F1},{m.TargetZ:F1}\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user