修复了集成测试的菜单逻辑,可以反复运行了。

This commit is contained in:
Tian jianyong 2025-05-25 17:12:08 +08:00
parent 25be8fa894
commit 0d46538d15
13 changed files with 430 additions and 155 deletions

View File

@ -142,7 +142,7 @@ namespace ThreatSource.Tests.Jamming
Assert.IsNotNull(_guidanceSystem, "激光驾束引导系统不应为空");
Assert.IsNotNull(_missile, "导弹不应为空");
System.Diagnostics.Debug.WriteLine($"测试开始 - 初始位置: {_missile.KState.Position}, 初始速度: {_missile.KState.Speed}");
System.Diagnostics.Debug.WriteLine($"测试开始 - 初始位置: {_missile.KState.Position}, 初始速度: {_missile.KState.Speed:F2}m/s");
// 更新激光波束参数
_guidanceSystem.UpdateLaserBeamRider(

View File

@ -396,17 +396,17 @@ namespace ThreatSource.Guidance
if (shortestDistance > config.ControlFieldDiameter / 2)
{
HasGuidance = false;
Trace.TraceInformation($"激光驾束引导系统: 失去引导, 原因: 超出控制场范围, 距离: {shortestDistance}");
Trace.TraceInformation($"激光驾束引导系统: 失去引导, 原因: 超出控制场范围, 距离: {shortestDistance:F2}m");
return;
}
Debug.WriteLine($"激光驾束引导系统: 在控制场内, 距离: {shortestDistance}");
Debug.WriteLine($"激光驾束引导系统: 在控制场内, 距离中心点: {shortestDistance:F2}m");
Vector3D missileToSource = LaserSourcePosition.Value - KState.Position;
double distance = missileToSource.Magnitude();
double receivedPower = CalculateReceivedLaserPower(distance);
Debug.WriteLine($"激光驾束引导系统: 接收到的激光功率: {receivedPower:E} W");
Debug.WriteLine($"激光驾束引导系统: 接收到的激光功率: {receivedPower:E2} W");
if(receivedPower >= config.MinDetectablePower)
{
@ -415,7 +415,7 @@ namespace ThreatSource.Guidance
else
{
HasGuidance = false;
Trace.TraceInformation($"激光驾束引导系统: 失去引导, 原因: 接收到的激光功率低于最小可探测功率,{LaserPower:E} W/{receivedPower:E} W");
Trace.TraceInformation($"激光驾束引导系统: 失去引导, 原因: 接收到的激光功率低于最小可探测功率,{LaserPower:E2} W/{receivedPower:E2} W");
}
}

View File

@ -440,13 +440,13 @@ namespace ThreatSource.Guidance
{
// 计算接收功率
receivedPower = CalculateReceivedPower(target.Source.KState.Position, target.SpotPosition, decoy.config.Power, decoy.config.DivergenceAngle);
Debug.WriteLine($"处理激光信号: 诱偏目标接收功率={receivedPower:E}W, 诱偏目标ID: {target.Target.Id}, 诱偏目标位置: {target.SpotPosition}");
Debug.WriteLine($"处理激光信号: 诱偏目标接收功率={receivedPower:E2}W, 诱偏目标ID: {target.Target.Id}, 诱偏目标位置: {target.SpotPosition}");
}
else if (target.Source is LaserDesignator laserDesignator)
{
// 计算接收功率
receivedPower = CalculateReceivedPower(target.Source.KState.Position, target.SpotPosition, laserDesignator.config.Power, laserDesignator.config.DivergenceAngle);
Debug.WriteLine($"处理激光信号: 真实目标接收功率={receivedPower:E}W, 真实目标ID: {target.Target.Id}, 真实目标位置: {target.SpotPosition}");
Debug.WriteLine($"处理激光信号: 真实目标接收功率={receivedPower:E2}W, 真实目标ID: {target.Target.Id}, 真实目标位置: {target.SpotPosition}");
}
// 累加功率
@ -454,7 +454,7 @@ namespace ThreatSource.Guidance
// 加权位置
weightedPosition += target.SpotPosition * receivedPower;
Debug.WriteLine($"处理激光信号: 累加功率={ReceivedLaserPower:E}W, 加权位置={weightedPosition}");
Debug.WriteLine($"处理激光信号: 累加功率={ReceivedLaserPower:E2}W, 加权位置={weightedPosition}");
}
// 如果总功率为0表示没有在视野范围内的激光源
@ -467,7 +467,7 @@ namespace ThreatSource.Guidance
// 计算加权平均位置
TargetPosition = weightedPosition / ReceivedLaserPower;
Debug.WriteLine($"处理激光信号: 总功率={ReceivedLaserPower:E}W, 加权平均目标位置={TargetPosition}");
Debug.WriteLine($"处理激光信号: 总功率={ReceivedLaserPower:E2}W, 加权平均目标位置={TargetPosition}");
// 更新激光照射参数
LaserIlluminationOn = true;
@ -534,9 +534,9 @@ namespace ThreatSource.Guidance
double lensArea = Math.PI * Math.Pow(config.LensDiameter / 2, 2);
double finalReceivedPower = powerDensityAtMissileAperture * lensArea * config.ReceiverEfficiency;
Debug.WriteLine($"激光功率计算: S2T D={distanceSourceToTarget:F1}m (Path1 T={totalTransmittance_S2T:F3}), " +
$"T2M D={distanceTargetToMissile:F1}m (Path2 T={totalTransmittance_T2M:F3}), " +
$"最终功率={finalReceivedPower:E}W");
Debug.WriteLine($"激光功率计算: 源到目标距离={distanceSourceToTarget:F1}m (路径1 透过率={totalTransmittance_S2T:F3}), " +
$"目标到导弹距离={distanceTargetToMissile:F1}m (路径2 透过率={totalTransmittance_T2M:F3}), " +
$"最终功率={finalReceivedPower:E2}W");
return finalReceivedPower;
}

View File

@ -685,7 +685,7 @@ namespace ThreatSource.Guidance
rcsLinear = swerlingRcsModel.GetRealtimeRcs(target.Id, target.Properties.Type, motionState, rcsLinear, isNewScanPeriodForRcs);
double rcsDbSmAfterSwerling = 10.0 * Math.Log10(rcsLinear);
double rcsVariationDb = rcsDbSmAfterSwerling - rcsDbSm;
Debug.WriteLine($"[MMW_GUIDANCE] 目标 {target.Id}: Swerling后RCS: {rcsDbSmAfterSwerling:F2} dBsm ({rcsLinear:F4} m²), 波动: {rcsVariationDb:+F2} dB.");
Debug.WriteLine($"[MMW_GUIDANCE] 目标 {target.Id}: Swerling后RCS: {rcsDbSmAfterSwerling:F2} dBsm ({rcsLinear:F4} m²), 波动: {rcsVariationDb:F2} dB.");
double localSnrDb = CalculateSNR(distance, rcsLinear, liveSmokeTransmittance);
switch (currentMode)

View File

@ -27,7 +27,7 @@ namespace ThreatSource.Indicator
/// <summary>
/// 干扰处理组件
/// </summary>
protected readonly JammableComponent _jammingComponent;
protected readonly JammableComponent JammingComponent;
/// <summary>
/// 获取目标是否被烟幕遮挡 (由任何烟幕引起)
@ -37,12 +37,12 @@ namespace ThreatSource.Indicator
/// <summary>
/// 最后一次成功获取的目标位置
/// </summary>
protected Vector3D? _lastKnownTargetPosition = null;
protected Vector3D? LastKnownTargetPosition = null;
/// <summary>
/// 最后一次成功获取的目标朝向
/// </summary>
protected Orientation? _lastKnownTargetOrientation = null;
protected Orientation? LastKnownTargetOrientation = null;
/// <summary>
/// 获取设备支持的干扰类型
@ -65,12 +65,12 @@ namespace ThreatSource.Indicator
/// true表示指示器当前受到干扰影响
/// false表示指示器正常工作
/// </remarks>
public bool IsJammed => _jammingComponent.IsJammed;
public bool IsJammed => JammingComponent.IsJammed;
/// <summary>
/// 获取设备当前是否正受到有效的阻塞式干扰
/// </summary>
public bool IsBlockingJammed => _jammingComponent.IsBlockingJammed;
public bool IsBlockingJammed => JammingComponent.IsBlockingJammed;
/// <summary>
/// 获取或设置目标ID
@ -97,12 +97,12 @@ namespace ThreatSource.Indicator
protected BaseIndicator(string id, KinematicState motionParameters, ISimulationManager manager)
: base(id, motionParameters, manager)
{
_jammingComponent = new JammableComponent(
JammingComponent = new JammableComponent(
positionProvider: () => base.KState.Position
);
_jammingComponent.JammingApplied += HandleJammingApplied;
_jammingComponent.JammingCleared += HandleJammingCleared;
JammingComponent.JammingApplied += HandleJammingApplied;
JammingComponent.JammingCleared += HandleJammingCleared;
}
/// <summary>
@ -119,10 +119,10 @@ namespace ThreatSource.Indicator
/// </remarks>
protected void InitializeJamming(double jammingResistanceThreshold, IEnumerable<JammingType> supportedTypes, IEnumerable<JammingType> supportedBlockingTypes)
{
_jammingComponent.LoadJammingConfigFromThreshold(jammingResistanceThreshold, supportedBlockingTypes);
JammingComponent.LoadJammingConfigFromThreshold(jammingResistanceThreshold, supportedBlockingTypes);
foreach (var type in supportedTypes)
{
_jammingComponent.AddSupportedJammingType(type);
JammingComponent.AddSupportedJammingType(type);
}
}
@ -136,7 +136,7 @@ namespace ThreatSource.Indicator
/// </remarks>
public virtual void ApplyJamming(JammingParameters parameters)
{
_jammingComponent.ApplyJamming(parameters);
JammingComponent.ApplyJamming(parameters);
}
/// <summary>
@ -149,7 +149,7 @@ namespace ThreatSource.Indicator
/// </remarks>
public virtual void ClearJamming(JammingParameters parameters)
{
_jammingComponent.ClearJamming(parameters);
JammingComponent.ClearJamming(parameters);
}
/// <summary>
@ -197,8 +197,8 @@ namespace ThreatSource.Indicator
}
IsTargetObscured = false;
// 重置最后目标状态
_lastKnownTargetPosition = null;
_lastKnownTargetOrientation = null;
LastKnownTargetPosition = null;
LastKnownTargetOrientation = null;
base.Deactivate();
}
@ -207,7 +207,7 @@ namespace ThreatSource.Indicator
/// </summary>
public override void Update(double deltaTime)
{
_jammingComponent.UpdateJammingStatus(deltaTime);
JammingComponent.UpdateJammingStatus(deltaTime);
if (IsActive)
{
@ -254,8 +254,8 @@ namespace ThreatSource.Indicator
// 仅当目标被看到 (未遮挡) 且目标有效时,才更新最后已知状态
if (!currentlyObscured && currentTarget != null)
{
_lastKnownTargetPosition = currentTarget.KState.Position;
_lastKnownTargetOrientation = currentTarget.KState.Orientation;
LastKnownTargetPosition = currentTarget.KState.Position;
LastKnownTargetOrientation = currentTarget.KState.Orientation;
}
}
@ -282,7 +282,7 @@ namespace ThreatSource.Indicator
}
// 3. 获取活动的烟幕
var activeJammerIds = _jammingComponent.GetActiveJammerIdsOfType(JammingType.SmokeGrenade);
var activeJammerIds = JammingComponent.GetActiveJammerIdsOfType(JammingType.SmokeGrenade);
if (!activeJammerIds.Any())
{
return false; // 没有活动的烟幕,视为未遮挡
@ -404,8 +404,8 @@ namespace ThreatSource.Indicator
// 添加指示器特有属性
statusInfo.ExtendedProperties["TargetId"] = TargetId ?? "";
statusInfo.ExtendedProperties["MissileId"] = MissileId ?? "";
statusInfo.ExtendedProperties["lastKnownTargetPosition"] = _lastKnownTargetPosition ?? Vector3D.Zero;
statusInfo.ExtendedProperties["lastKnownTargetOrientation"] = _lastKnownTargetOrientation ?? new Orientation(0, 0, 0);
statusInfo.ExtendedProperties["lastKnownTargetPosition"] = LastKnownTargetPosition ?? Vector3D.Zero;
statusInfo.ExtendedProperties["lastKnownTargetOrientation"] = LastKnownTargetOrientation ?? new Orientation(0, 0, 0);
statusInfo.ExtendedProperties["IsTargetObscured"] = IsTargetObscured;
statusInfo.ExtendedProperties["IsJammed"] = IsJammed;
statusInfo.ExtendedProperties["IsBlockingJammed"] = IsBlockingJammed;

View File

@ -128,9 +128,9 @@ namespace ThreatSource.Indicator
if (IsTargetObscured)
{
// 目标被遮挡,尝试使用最后已知位置
if (_lastKnownTargetPosition != null)
if (LastKnownTargetPosition != null)
{
currentTargetPosition = _lastKnownTargetPosition.Value;
currentTargetPosition = LastKnownTargetPosition.Value;
Debug.WriteLine($"红外测角仪 {Id}: 目标被遮挡,使用最后已知位置 {currentTargetPosition}");
}
else
@ -157,7 +157,7 @@ namespace ThreatSource.Indicator
return;
}
currentTargetPosition = targetElement.KState.Position;
_lastKnownTargetPosition = currentTargetPosition; // 记录最后已知的目标位置
LastKnownTargetPosition = currentTargetPosition; // 记录最后已知的目标位置
}
IsTracking = true;

View File

@ -138,7 +138,7 @@ namespace ThreatSource.Indicator
{
LaserDirection = newDirection;
Debug.WriteLine($"激光驾束仪 {Id} 更新激光指向: {LaserDirection}");
_lastKnownTargetPosition = targetPosition; // 记录最后已知的目标位置
LastKnownTargetPosition = targetPosition; // 记录最后已知的目标位置
PublishLaserBeamEvent();
}
}
@ -188,7 +188,7 @@ namespace ThreatSource.Indicator
StopBeamIllumination();
}
Debug.WriteLine($"激光驾束仪 {Id} 已停用");
base.Deactivate(); // Handles IsActive and unsubscribes HandleJammingEvent
base.Deactivate();
}
}

View File

@ -129,9 +129,9 @@ namespace ThreatSource.Indicator
double yaw = Math.PI + Math.Atan2(direction.Z, direction.X);
double pitch = -Math.Asin(direction.Y);
KState.Orientation = new Orientation(yaw, pitch, 0);
_lastKnownTargetPosition = target.KState.Position;
LastKnownTargetPosition = target.KState.Position;
Debug.WriteLine($"激光指示器 {Id} 更新朝向: {KState.Orientation}, _lastKnownTargetPosition: {_lastKnownTargetPosition}");
Debug.WriteLine($"激光指示器 {Id} 更新朝向: {KState.Orientation}, 最后已知目标位置: {LastKnownTargetPosition}");
}
}
}
@ -283,7 +283,7 @@ namespace ThreatSource.Indicator
{
LaserDesignatorId = Id,
TargetId = TargetId,
SpotPosition = _lastKnownTargetPosition,
SpotPosition = LastKnownTargetPosition,
LaserCodeConfig = config.LaserCodeConfig
});
}

View File

@ -669,10 +669,10 @@ namespace ThreatSource.Missile
public override string GetStatus()
{
return base.GetStatus()
+ $"\n激光测距仪状态: {rangefinder.GetStatus()}"
+ $"\n红外探测器状态: {infraredDetector.GetStatus()}"
+ $"\n毫米波辐射计状态: {radiometer.GetStatus()}"
+ $"\n测高仪状态: {altimeter.GetStatus()}";
+ $"\n激光测距仪: {rangefinder.GetStatus()}"
+ $"\n红外探测器: {infraredDetector.GetStatus()}"
+ $"\n毫米波辐射计: {radiometer.GetStatus()}"
+ $"\n测高仪: {altimeter.GetStatus()}";
}
/// <summary>

View File

@ -303,7 +303,7 @@ namespace ThreatSource.Sensor
VerticalError = filteredVerticalError;
// 增强调试输出,同时显示水平和垂直误差
Debug.WriteLine($"原始误差: 水平={rawHorizontalError:F6}, 垂直={rawVerticalError:F6}, 滤波后: 水平={HorizontalError:F6}, 垂直={VerticalError:F6}");
Debug.WriteLine($"原始误差: 水平={rawHorizontalError:E2}, 垂直={rawVerticalError:E2}, 滤波后: 水平={HorizontalError:E2}, 垂直={VerticalError:E2}");
}
else
{
@ -365,9 +365,9 @@ namespace ThreatSource.Sensor
/// </remarks>
public string GetStatus()
{
return $"锁定={IsTargetLocked}, 总功率={TotalReceivedPower:E} W, 最小可探测功率={MinDetectablePower:E} W," +
$" 水平误差={HorizontalError:F4}, 垂直误差={VerticalError:F4}," +
$" 象限信号=[{quadrantSignals[0]:E}, {quadrantSignals[1]:E}, {quadrantSignals[2]:E}, {quadrantSignals[3]:E}]";
return $"锁定={IsTargetLocked}, 总功率={TotalReceivedPower:E2} W, 最小可探测功率={MinDetectablePower:E2} W," +
$" 水平误差={HorizontalError:E2}, 垂直误差={VerticalError:E2}," +
$" 象限信号=[{quadrantSignals[0]:E2}, {quadrantSignals[1]:E2}, {quadrantSignals[2]:E2}, {quadrantSignals[3]:E2}]";
}
}
}

View File

@ -179,6 +179,15 @@ namespace ThreatSource.Simulation
/// <typeparam name="T">事件类型</typeparam>
/// <param name="handler">要取消的事件处理函数</param>
void UnsubscribeFromEvent<T>(Action<T> handler);
/// <summary>
/// 清理所有事件处理器和待处理事件
/// </summary>
/// <remarks>
/// 用于导弹切换或仿真重置时清理事件系统状态
/// 防止事件残留影响新的制导系统
/// </remarks>
void ClearAllEvents();
#endregion
#region

View File

@ -186,7 +186,7 @@ namespace ThreatSource.Simulation
foreach (var target in activeTargets)
{
double distance = Vector3D.Distance(missile.KState.Position, target.KState.Position);
Debug.WriteLine($"导弹 {missile.Id} 和目标 {target.Id} 之间的距离: {distance:F2}");
Debug.WriteLine($"导弹 {missile.Id} 和目标 {target.Id} 之间的距离: {distance:F2}m");
if (distance <= missile.Properties.ExplosionRadius)
{
double damage = CalculateMissileDamage(missile);
@ -365,6 +365,23 @@ namespace ThreatSource.Simulation
}
}
}
/// <summary>
/// 清理所有事件处理器和待处理事件
/// </summary>
/// <remarks>
/// 用于导弹切换或仿真重置时清理事件系统状态
/// 防止事件残留影响新的制导系统
/// </remarks>
public void ClearAllEvents()
{
Debug.WriteLine("[事件] 清理所有事件处理器和待处理事件");
// 清理所有事件处理器
eventHandlers.Clear();
Debug.WriteLine("[事件] 事件系统已完全清理");
}
#endregion
#region

View File

@ -96,8 +96,6 @@ namespace ThreatSource.Tools.MissileSimulation
// 初始化导弹-干扰映射
InitializeMissileJammingMap();
InitializeSimulation();
}
public SourceLevels CurrentLogLevel => logLevelFilter?.EventType ?? SourceLevels.Off;
@ -245,11 +243,14 @@ namespace ThreatSource.Tools.MissileSimulation
Orientation = new Orientation(0.0, 0.0, 0.0),
Speed = 2.0
};
string targetId = "Tank_1";
var target = _threatSourceFactory.CreateEquipment(targetId, "mbt_001", motionParameters);
targets[targetId] = target;
simulationManager.RegisterEntity(targetId, target);
target.Activate(); // 激活目标
Console.WriteLine($"添加目标 {targetId},位置:{motionParameters.Position}");
Console.WriteLine($"目标创建后实际位置:{target.KState.Position}");
}
/// <summary>
@ -337,11 +338,13 @@ namespace ThreatSource.Tools.MissileSimulation
Orientation = new Orientation(Math.PI/2, Math.PI/20, 0),
Speed = 700
};
string missileId = "LSGM_1";
var missile = _threatSourceFactory.CreateMissile(missileId, "lsgm_001", "Tank_1", motionParameters);
missiles[missileId] = missile;
simulationManager.RegisterEntity(missileId, missile);
Console.WriteLine($"注册激光半主动制导导弹 {missileId}");
Console.WriteLine($"注册激光半主动制导导弹 {missileId},初始位置:{motionParameters.Position}");
}
/// <summary>
@ -355,11 +358,13 @@ namespace ThreatSource.Tools.MissileSimulation
Orientation = new Orientation(Math.PI/2, 0.04, 0.0),
Speed = 10
};
string missileId = "LBRM_1";
var missile = _threatSourceFactory.CreateMissile(missileId, "hj10", "Tank_1", motionParameters);
missiles[missileId] = missile;
simulationManager.RegisterEntity(missileId, missile);
Console.WriteLine($"注册激光驾束制导导弹 {missileId}");
Console.WriteLine($"注册激光驾束制导导弹 {missileId},初始位置:{motionParameters.Position}");
}
/// <summary>
@ -375,11 +380,11 @@ namespace ThreatSource.Tools.MissileSimulation
};
string missileId = "TSM_1";
var missile = _threatSourceFactory.CreateMissile(missileId, "tsm_001", "Tank_1", motionParameters);
missiles[missileId] = missile;
simulationManager.RegisterEntity(missileId, missile);
Console.WriteLine($"注册末敏弹 {missileId}");
Console.WriteLine($"注册末敏弹 {missileId},初始位置:{motionParameters.Position}");
}
/// <summary>
@ -395,10 +400,11 @@ namespace ThreatSource.Tools.MissileSimulation
};
string missileId = "ICGM_1";
var missile = _threatSourceFactory.CreateMissile(missileId, "irc_001", "Tank_1", motionParameters);
missiles[missileId] = missile;
simulationManager.RegisterEntity(missileId, missile);
Console.WriteLine($"注册红外指令制导导弹 {missileId}");
Console.WriteLine($"注册红外指令制导导弹 {missileId},初始位置:{motionParameters.Position}");
}
/// <summary>
@ -412,11 +418,13 @@ namespace ThreatSource.Tools.MissileSimulation
Orientation = new Orientation(Math.PI/2, 0.12, 0),
Speed = 10
};
string missileId = "ITGM_1";
var missile = _threatSourceFactory.CreateMissile(missileId, "itg_001", "Tank_1", motionParameters);
missiles[missileId] = missile;
simulationManager.RegisterEntity(missileId, missile);
Console.WriteLine($"注册红外成像末制导导弹 {missileId}");
Console.WriteLine($"注册红外成像末制导导弹 {missileId},初始位置:{motionParameters.Position}");
}
/// <summary>
@ -430,11 +438,13 @@ namespace ThreatSource.Tools.MissileSimulation
Orientation = new Orientation(Math.PI/2, 0.05, 0),
Speed = 10
};
string missileId = "MMWG_1";
var missile = _threatSourceFactory.CreateMissile(missileId, "mmw_001", "Tank_1", motionParameters);
missiles[missileId] = missile;
simulationManager.RegisterEntity(missileId, missile);
Console.WriteLine($"注册毫米波末制导导弹 {missileId}");
Console.WriteLine($"注册毫米波末制导导弹 {missileId},初始位置:{motionParameters.Position}");
}
/// <summary>
@ -449,10 +459,11 @@ namespace ThreatSource.Tools.MissileSimulation
Orientation = new Orientation(Math.PI/2, 0.05, 0),
Speed = 10
};
var missile = _threatSourceFactory.CreateMissile(missileId, "cg_001", "Tank_1", motionParameters);
missiles[missileId] = missile;
simulationManager.RegisterEntity(missileId, missile);
Console.WriteLine($"注册毫米波/红外复合制导导弹 {missileId}");
Console.WriteLine($"注册毫米波/红外复合制导导弹 {missileId},初始位置:{motionParameters.Position}");
missileId = "CGGM_2";
motionParameters = new KinematicState
@ -461,10 +472,11 @@ namespace ThreatSource.Tools.MissileSimulation
Orientation = new Orientation(Math.PI/2, 0.05, 0),
Speed = 10
};
missile = _threatSourceFactory.CreateMissile(missileId, "cg_002", "Tank_1", motionParameters);
missiles[missileId] = missile;
simulationManager.RegisterEntity(missileId, missile);
Console.WriteLine($"注册激光/红外复合制导导弹 {missileId}");
Console.WriteLine($"注册激光/红外复合制导导弹 {missileId},初始位置:{motionParameters.Position}");
}
/// <summary>
@ -668,56 +680,27 @@ namespace ThreatSource.Tools.MissileSimulation
private Orientation CalculateOrientationToEntity(SimulationElement target)
{
// 使用CalculateDirectionToTarget获取归一化方向向量
Vector3D direction = CalculateDirectionToTarget(new Vector3D(0, 0, 0), target.KState.Position);
Vector3D direction = target.KState.Position - new Vector3D(0, 0, 0);
// 创建朝向目标的方向
return Orientation.FromVector(direction);
return Orientation.FromVector(direction.Normalize());
}
/// <summary>
/// 选择要激活的导弹
/// 选择导弹
/// </summary>
/// <param name="missileId">导弹ID</param>
public void SelectMissile(string missileId)
{
if (!missiles.ContainsKey(missileId))
{
Console.WriteLine($"错误:找不到导弹 {missileId}");
return;
}
// 先停用所有导弹、传感器、干扰器
foreach (var id in missiles.Keys)
{
missileActiveStatus[id] = false;
missiles[id].Deactivate();
}
foreach (var indicator in indicators.Values)
{
indicator.Deactivate();
}
foreach (var jammer in jammers.Values)
{
jammer.Deactivate();
}
// 激活选中的导弹
missileActiveStatus[missileId] = true;
missiles[missileId].Activate();
SelectedMissileId = missileId;
Console.WriteLine($"已选择导弹:{missileId} ({SelectedMissileDisplayName})");
// 确保所有目标都处于激活状态
foreach (var target in targets.Values)
{
target.Activate();
Console.WriteLine($"确保目标 {target.Id} 处于激活状态");
}
// 激活相关的传感器和指示器
ActivateRelatedIndicators(missileId);
// 打印所有注册的组件
PrintSimulationRegisteredComponents();
Console.WriteLine($"=== 选择导弹: {missileId} ===");
// 新架构:完全销毁所有现有实体
DestroyAllEntities();
// 重新创建选中的导弹及其相关实体
CreateMissileAndRelatedEntities(missileId);
Console.WriteLine($"=== 导弹选择完成: {missileId} ===");
}
/// <summary>
@ -1085,12 +1068,25 @@ namespace ThreatSource.Tools.MissileSimulation
{
Console.WriteLine("开始综合导弹模拟...");
// 确保所有激活的导弹和传感器都处于正确状态
foreach (var missile in missiles.Values)
// 使用新架构:销毁重建模式,确保每次都是全新的实体和位置
if (missiles.Count > 0 || targets.Count > 0)
{
if (missileActiveStatus[missile.Id])
Console.WriteLine("检测到现有实体,销毁并重新创建...");
// 保存当前选中的导弹ID避免在销毁时被清空
string currentSelectedMissileId = SelectedMissileId;
DestroyAllEntities();
// 重新创建选中的导弹及其相关实体
if (!string.IsNullOrEmpty(currentSelectedMissileId))
{
missile.Fire();
CreateMissileAndRelatedEntities(currentSelectedMissileId);
}
else
{
Console.WriteLine("错误:没有选中的导弹");
return;
}
}
@ -1113,7 +1109,7 @@ namespace ThreatSource.Tools.MissileSimulation
{
simulationManager.StopSimulation();
SimulationEnded?.Invoke(this, EventArgs.Empty);
ResetSimulation();
Console.WriteLine("仿真结束,所有导弹已完成任务");
break;
}
@ -1136,7 +1132,7 @@ namespace ThreatSource.Tools.MissileSimulation
Console.WriteLine($"\n========== 模拟状态 (时间: {simulationTime:F3}s==========");
// 天气状态
Console.WriteLine("\n--- 天气状态 ---");
Console.WriteLine("\n--- 天气环境 ---");
if (weather != null)
{
Console.WriteLine($"天气类型: {weather.Type}");
@ -1147,7 +1143,7 @@ namespace ThreatSource.Tools.MissileSimulation
}
// 导弹状态
Console.WriteLine("\n--- 导弹状态 ---");
Console.WriteLine("\n--- 导弹 ---");
var activeMissiles = simulationManager.GetEntitiesByType<BaseMissile>()
.Where(m => m.IsActive)
.ToList();
@ -1165,7 +1161,7 @@ namespace ThreatSource.Tools.MissileSimulation
}
// 目标状态
Console.WriteLine("\n--- 目标状态 ---");
Console.WriteLine("\n--- 目标 ---");
var activeTargets = targets.Values.Where(t => t.IsActive).ToList();
if (activeTargets.Any())
{
@ -1181,7 +1177,7 @@ namespace ThreatSource.Tools.MissileSimulation
}
// 传感器状态
Console.WriteLine("\n--- 指示器状态 ---");
Console.WriteLine("\n--- 指示器 ---");
var activeIndicators = indicators.Values.Where(i => i.IsActive).ToList();
if (activeIndicators.Any())
{
@ -1197,7 +1193,7 @@ namespace ThreatSource.Tools.MissileSimulation
}
// 干扰器状态
Console.WriteLine("\n--- 干扰器状态 ---");
Console.WriteLine("\n--- 干扰器 ---");
var activeJammers = jammers.Values.Where(j => j.IsActive).ToList();
if (activeJammers.Any())
{
@ -1275,52 +1271,25 @@ namespace ThreatSource.Tools.MissileSimulation
/// <summary>
/// 重置仿真状态
/// </summary>
/// <remarks>
/// 新架构:由于采用销毁重建模式,此方法已简化
/// 主要功能已移至DestroyAllEntities和CreateMissileAndRelatedEntities方法
/// </remarks>
public void ResetSimulation()
{
// 获取所有活跃的导弹
var activeMissiles = simulationManager.GetEntitiesByType<BaseMissile>();
foreach (var missile in activeMissiles)
{
// 获取导弹的初始属性
var motionParameters = missile.GetType().GetField("motionParameters",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance)?.GetValue(missile) as KinematicState;
if (motionParameters != null)
{
// 重置导弹位置和状态
missile.KState.Position = motionParameters.Position;
missile.KState.Velocity = Vector3D.Zero;
}
missile.Deactivate();
}
// 重置所有传感器状态
var activeIndicators = simulationManager.GetEntitiesByType<SimulationElement>()
.Where(e => indicators.ContainsValue(e));
foreach (var indicator in activeIndicators)
{
indicator.Deactivate();
}
// 重置所有目标状态
var activeTargets = simulationManager.GetEntitiesByType<Tank>();
foreach (var target in activeTargets)
{
var initialPosition = target.KState.Position;
target.Deactivate();
target.KState.Position = initialPosition;
target.Activate();
}
Console.WriteLine("=== 开始重置仿真状态 ===");
// 停止仿真并清理事件系统
simulationManager.StopSimulation();
simulationManager.ClearAllEvents();
// 重置导弹激活状态
missileActiveStatus.Clear();
foreach (var missile in missiles.Values)
{
missileActiveStatus[missile.Id] = false;
}
Console.WriteLine("仿真状态已重置");
// 清理活跃干扰列表
activeJammings.Clear();
Console.WriteLine("=== 仿真状态重置完成 ===");
}
/// <summary>
@ -1421,5 +1390,285 @@ namespace ThreatSource.Tools.MissileSimulation
// 返回一个新的列表,防止外部修改内部列表
return [.. activeJammings];
}
/// <summary>
/// 销毁所有实体并从仿真管理器中注销
/// </summary>
/// <remarks>
/// 新架构:每次仿真结束后完全销毁所有实体,下次选择时重新创建
/// 这样可以避免状态残留问题,确保每次都是全新的实体
/// </remarks>
private void DestroyAllEntities()
{
Console.WriteLine("=== 开始销毁所有实体 ===");
// 停止仿真并清理事件系统
simulationManager.StopSimulation();
simulationManager.ClearAllEvents();
// 销毁所有导弹
foreach (var missile in missiles.Values)
{
missile.Deactivate();
simulationManager.UnregisterEntity(missile.Id);
Console.WriteLine($"销毁导弹: {missile.Id}");
}
missiles.Clear();
// 销毁所有目标
foreach (var target in targets.Values)
{
target.Deactivate();
simulationManager.UnregisterEntity(target.Id);
Console.WriteLine($"销毁目标: {target.Id}");
}
targets.Clear();
// 销毁所有指示器
foreach (var indicator in indicators.Values)
{
indicator.Deactivate();
simulationManager.UnregisterEntity(indicator.Id);
Console.WriteLine($"销毁指示器: {indicator.Id}");
}
indicators.Clear();
// 销毁所有干扰器
foreach (var jammer in jammers.Values)
{
jammer.Deactivate();
simulationManager.UnregisterEntity(jammer.Id);
Console.WriteLine($"销毁干扰器: {jammer.Id}");
}
jammers.Clear();
// 清理状态
missileActiveStatus.Clear();
activeJammings.Clear();
SelectedMissileId = "";
Console.WriteLine("=== 所有实体销毁完成 ===");
}
/// <summary>
/// 按需创建特定导弹及其相关实体
/// </summary>
/// <param name="missileId">要创建的导弹ID</param>
/// <remarks>
/// 新架构:每次选择导弹时重新创建所需的实体
/// 包括目标、导弹、指示器、干扰器等
/// </remarks>
private void CreateMissileAndRelatedEntities(string missileId)
{
Console.WriteLine($"=== 开始创建导弹 {missileId} 及相关实体 ===");
// 首先添加天气(如果还没有)
if (simulationManager.CurrentWeather == null)
{
AddWeathers();
}
// 创建目标
AddTankTarget();
// 根据导弹类型创建对应的导弹
switch (missileId)
{
case "LSGM_1":
AddLaserSemiActiveMissile();
break;
case "LBRM_1":
AddLaserBeamRiderMissile();
break;
case "TSM_1":
AddTerminalSensitiveMissile();
break;
case "ICGM_1":
AddInfraredCommandMissile();
break;
case "ITGM_1":
AddInfraredImagingMissile();
break;
case "MMWG_1":
AddMillimeterWaveMissile();
break;
case "CGGM_1":
case "CGGM_2":
AddCompositeGuidanceMissile(); // 这个方法会添加两种复合制导导弹
break;
default:
Console.WriteLine($"未知的导弹类型: {missileId}");
return;
}
// 添加所有指示器、干扰器和烟幕弹
AddIndicators();
// 根据导弹类型添加相应的干扰器
AddJammersForMissile(missileId);
// 添加烟幕弹和激光诱偏目标
AddSmokeGrenade();
AddLaserDecoy();
// 激活选中的导弹
if (missiles.TryGetValue(missileId, out var selectedMissile))
{
selectedMissile.Activate();
SelectedMissileId = missileId;
missileActiveStatus[missileId] = true;
Console.WriteLine($"已激活导弹: {missileId}");
// 激活相关指示器
ActivateRelatedIndicators(missileId);
}
Console.WriteLine($"=== 导弹 {missileId} 及相关实体创建完成 ===");
}
private void AddJammersForMissile(string missileId)
{
Console.WriteLine($"为导弹 {missileId} 创建相应的干扰器");
// 利用现有的导弹-干扰器映射
if (missileJammingMap.TryGetValue(missileId, out var jammingList))
{
foreach (var (type, displayName, jammerId, mode, target) in jammingList)
{
CreateJammerById(jammerId, type, target);
}
}
else
{
Console.WriteLine($"未找到导弹 {missileId} 的干扰器映射");
}
}
/// <summary>
/// 根据干扰器ID创建干扰器实体
/// </summary>
private void CreateJammerById(string jammerId, JammingType type, string target)
{
try
{
// 根据干扰器ID确定朝向
Orientation orientation = GetJammerOrientation(jammerId, target);
var jammerParams = new KinematicState
{
Position = new Vector3D(0, 0, 0),
Orientation = orientation,
Speed = 0.0
};
// 根据干扰器ID确定类型配置
string jammerConfig = GetJammerConfig(jammerId);
var jammer = _threatSourceFactory.CreateJammer(jammerId, jammerConfig, jammerParams, "Tank_1");
if (jammer is BaseJammer baseJammer)
{
simulationManager.RegisterEntity(jammerId, jammer);
jammers[jammerId] = baseJammer;
Console.WriteLine($"注册干扰器 {jammerId}");
}
}
catch (Exception ex)
{
Console.WriteLine($"创建干扰器 {jammerId} 时出错: {ex.Message}");
}
}
/// <summary>
/// 根据干扰器ID和目标确定朝向
/// </summary>
private Orientation GetJammerOrientation(string jammerId, string target)
{
// 根据干扰器ID和目标类型确定朝向
return jammerId switch
{
"LaserJammer_Designator" => GetOrientationToRelatedIndicator(), // 朝向与当前导弹相关的指示器
"LaserJammer_Missile" => GetOrientationToCurrentMissile(), // 朝向当前选中的导弹
"InfraredJammer_Designator" => GetOrientationToRelatedIndicator(), // 朝向与当前导弹相关的指示器
"InfraredJammer_Missile" => GetOrientationToCurrentMissile(), // 朝向当前选中的导弹
"MillimeterWaveJammer_Missile" => GetOrientationToCurrentMissile(), // 朝向当前选中的导弹
"LaserJammer_Submunition" or "InfraredJammer_Submunition" or "MillimeterWaveJammer_Submunition" or "MillimeterWaveCompensationJammer_Submunition"
=> new Orientation(0, Math.PI/2, 0), // 垂直向上
_ => new Orientation(0, 0, 0) // 默认朝向
};
}
/// <summary>
/// 获取朝向与当前选中导弹相关的指示器的方向
/// </summary>
private Orientation GetOrientationToRelatedIndicator()
{
// 根据当前选中的导弹确定相关的指示器
string[] relatedIndicatorIds = SelectedMissileId switch
{
"LSGM_1" => ["LD_1"], // 激光半主动导弹 -> 激光指示器
"LBRM_1" => ["LBR_1"], // 激光驾束导弹 -> 激光驾束仪
"ICGM_1" => ["IT_1"], // 红外指令导弹 -> 红外测角仪
"CGGM_2" => ["LD_1"], // 激光/红外复合导弹 -> 激光指示器
_ => ["LD_1", "LBR_1", "IT_1"] // 默认尝试所有指示器
};
return GetOrientationToIndicator(relatedIndicatorIds);
}
/// <summary>
/// 获取朝向当前选中导弹的方向
/// </summary>
private Orientation GetOrientationToCurrentMissile()
{
if (!string.IsNullOrEmpty(SelectedMissileId) && missiles.TryGetValue(SelectedMissileId, out var missile))
{
return CalculateOrientationToEntity(missile);
}
return new Orientation(0, 0, 0); // 默认朝向
}
/// <summary>
/// 获取朝向指示器的方向
/// </summary>
private Orientation GetOrientationToIndicator(params string[] indicatorIds)
{
foreach (var indicatorId in indicatorIds)
{
if (indicators.TryGetValue(indicatorId, out var indicator))
{
return CalculateOrientationToEntity(indicator);
}
}
return new Orientation(0, 0, 0); // 默认朝向
}
/// <summary>
/// 根据干扰器ID确定配置类型
/// </summary>
private string GetJammerConfig(string jammerId)
{
return jammerId switch
{
"LaserJammer_Designator" or "LaserJammer_Missile" => "laser_blocking",
"LaserJammer_Submunition" => "laser_top_blocking",
"InfraredJammer_Designator" or "InfraredJammer_Missile" => "infrared_blocking",
"InfraredJammer_Submunition" => "infrared_top_blocking",
"MillimeterWaveJammer_Missile" or "MillimeterWaveJammer_Submunition" => "mmw_blocking",
"MillimeterWaveCompensationJammer_Submunition" => "mmw_compensation",
"LDY_1" => "laser_decoy",
"SG_1" => "surround",
"SG_2" => "infrared",
"SG_3" => "mmw",
"SG_4" => "top",
_ => "laser_blocking" // 默认配置
};
}
}
}