843 lines
31 KiB
C#
843 lines
31 KiB
C#
using ThreatSource.Simulation;
|
||
using ThreatSource.Utils;
|
||
using ThreatSource.Sensor;
|
||
using ThreatSource.Target;
|
||
|
||
namespace ThreatSource.Missile
|
||
{
|
||
/// <summary>
|
||
/// 末敏子弹类,实现了多传感器融合的末端制导功能
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 该类提供了末敏子弹的核心功能:
|
||
/// - 多传感器融合(红外、毫米波、激光)
|
||
/// - 螺旋扫描搜索
|
||
/// - 自主目标识别
|
||
/// - 末端精确制导
|
||
/// 通过多种传感器的协同工作实现对目标的精确打击
|
||
/// </remarks>
|
||
public class TerminalSensitiveSubmunition : BaseMissile
|
||
{
|
||
/// <summary>
|
||
/// 子弹飞行阶段枚举
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 定义了子弹飞行的八个主要阶段:
|
||
/// - Separation:分离阶段,从母弹分离
|
||
/// - Deceleration:减速阶段,调整速度
|
||
/// - ParachuteDeployment:降落伞打开阶段,稳定下降
|
||
/// - StableScan:稳定扫描阶段,稳定下降
|
||
/// - Detection:目标探测阶段,搜索确定目标
|
||
/// - Attack:攻击阶段,末端制导
|
||
/// - Explode:爆炸阶段,命中目标
|
||
/// - SelfDestruct:自毁阶段,触发自毁
|
||
/// </remarks>
|
||
private enum SubmunitionStage
|
||
{
|
||
Separation, // 分离阶段
|
||
Deceleration, // 减速阶段
|
||
ParachuteDeployment, // 降落伞打开阶段
|
||
StableScan, // 稳定扫描阶段
|
||
Detection, // 目标探测阶段
|
||
Attack, // 攻击阶段
|
||
Explode, // 爆炸阶段
|
||
SelfDestruct // 自毁阶段
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取或设置当前飞行阶段
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 用于控制子弹在不同阶段的行为
|
||
/// 影响传感器工作模式和制导方式
|
||
/// </remarks>
|
||
private SubmunitionStage currentStage;
|
||
|
||
/// <summary>
|
||
/// 螺旋扫描旋转速度,单位:弧度/秒
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 定义了螺旋扫描时的旋转角速度
|
||
/// 4转/秒 = 8π弧度/秒
|
||
/// </remarks>
|
||
private const double SpiralRotationSpeed = 8 * Math.PI;
|
||
|
||
/// <summary>
|
||
/// 减速阶段末速,单位:米/秒
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 定义了减速阶段的垂直下降速度
|
||
/// </remarks>
|
||
private const double DecelerationEndSpeed = 40;
|
||
|
||
/// <summary>
|
||
/// 垂直下降速度,单位:米/秒
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 定义了扫描和攻击阶段的垂直下降速度
|
||
/// </remarks>
|
||
private const double VerticalDeclineSpeed = 10;
|
||
|
||
/// <summary>
|
||
/// 扫描角度,单位:弧度
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 定义了螺旋扫描的锥角
|
||
/// 30度 = π/6弧度
|
||
/// </remarks>
|
||
public const double ScanAngle = 30 * Math.PI / 180;
|
||
|
||
/// <summary>
|
||
/// 开伞高度,单位:米
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 打开降落伞的高度阈值
|
||
/// 影响降落伞打开阶段的触发时机
|
||
/// </remarks>
|
||
private const double ParachuteDeploymentHeight = 400;
|
||
|
||
/// <summary>
|
||
/// 减速加速度,单位:米/秒²
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 减速阶段的减速度大小
|
||
/// 影响速度调整的快慢
|
||
/// </remarks>
|
||
private const double DecelerationAcceleration = 50;
|
||
|
||
/// <summary>
|
||
/// 稳定扫描高度,单位:米
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 开始螺旋扫描的高度阈值
|
||
/// 影响扫描阶段的触发时机
|
||
/// </remarks>
|
||
private const double StableScanHeight = 200;
|
||
|
||
/// <summary>
|
||
/// 目标探测距离,单位:米
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 目标探测的距离阈值
|
||
/// 影响目标探测阶段的触发时机
|
||
/// </remarks>
|
||
private const double TargetDetectionDistance = 150;
|
||
|
||
/// <summary>
|
||
/// 自毁高度,单位:米
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 触发自毁的高度阈值
|
||
/// 保证子弹不会危及友方
|
||
/// </remarks>
|
||
private const double SelfDestructHeight = 20;
|
||
|
||
/// <summary>
|
||
/// 攻击速度,单位:米/秒
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 攻击阶段的期望速度
|
||
/// 影响末端制导的精度
|
||
/// </remarks>
|
||
private double AttackSpeed = 200;
|
||
|
||
/// <summary>
|
||
/// 是否已经探测到目标
|
||
/// </summary>
|
||
private bool isTargetDetected = false;
|
||
|
||
/// <summary>
|
||
/// 第一次探测到目标时记录的目标方位角
|
||
/// </summary>
|
||
private double? firstDetectionAngle = null;
|
||
|
||
/// <summary>
|
||
/// 获取或设置最后一次检测到目标的时间
|
||
/// </summary>
|
||
private double? lastDetectionTime = null;
|
||
|
||
/// <summary>
|
||
/// 获取或设置螺旋扫描的当前角度
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 用于控制螺旋扫描的方向
|
||
/// 影响传感器的指向
|
||
/// </remarks>
|
||
private double spiralAngle;
|
||
|
||
/// <summary>
|
||
/// 扫描方向向量
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 表示传感器的当前指向
|
||
/// 用于目标探测和跟踪
|
||
/// </remarks>
|
||
private Vector3D scanDirection;
|
||
|
||
/// <summary>
|
||
/// 获取扫描方向向量
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 表示传感器的当前指向
|
||
/// 用于目标探测和跟踪
|
||
/// </remarks>
|
||
public Vector3D ScanDirection => scanDirection;
|
||
|
||
/// <summary>
|
||
/// 目标ID
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 记录目标的唯一标识符
|
||
/// 用于目标识别和跟踪
|
||
/// </remarks>
|
||
public string TargetId { get; }
|
||
|
||
/// <summary>
|
||
/// 红外探测器实例
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 用于探测目标的红外辐射
|
||
/// 提供目标方位信息
|
||
/// </remarks>
|
||
private readonly InfraredDetector infraredDetector;
|
||
|
||
/// <summary>
|
||
/// 毫米波辐射计实例
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 用于探测目标的毫米波辐射
|
||
/// 提供目标特征信息
|
||
/// </remarks>
|
||
private readonly MillimeterWaveRadiometer radiometer;
|
||
|
||
/// <summary>
|
||
/// 毫米波测高仪实例
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 用于测量对地高度
|
||
/// 控制飞行阶段转换
|
||
/// </remarks>
|
||
private readonly MillimeterWaveAltimeter altimeter;
|
||
|
||
/// <summary>
|
||
/// 激光测距仪实例
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 用于精确测量目标距离
|
||
/// 提供攻击阶段的制导信息
|
||
/// </remarks>
|
||
private readonly LaserRangefinder rangefinder;
|
||
|
||
/// <summary>
|
||
/// 初始化末敏子弹的新实例
|
||
/// </summary>
|
||
/// <param name="targetId">目标ID</param>
|
||
/// <param name="properties">子弹配置参数</param>
|
||
/// <param name="manager">仿真管理器实例</param>
|
||
/// <remarks>
|
||
/// 构造过程:
|
||
/// - 初始化基本属性
|
||
/// - 创建传感器系统
|
||
/// - 配置传感器参数
|
||
/// - 设置初始状态
|
||
/// </remarks>
|
||
public TerminalSensitiveSubmunition(string targetId, MissileProperties properties, ISimulationManager manager)
|
||
: base(properties, manager)
|
||
{
|
||
TargetId = targetId;
|
||
|
||
currentStage = SubmunitionStage.Separation;
|
||
spiralAngle = 0;
|
||
// 初始化扫描方向为正北
|
||
scanDirection = new Vector3D(0, 0, 1).Normalize();
|
||
|
||
// 初始化传感器
|
||
infraredDetector = new InfraredDetector(this, 500, InfraredBand.Short, 2.5); // 红外探测器,探测距离 500 米,近红外,视场角1度
|
||
radiometer = new MillimeterWaveRadiometer(this, 500, MillimeterWaveBand.Band3, 2.5); // 毫米波辐射计,探测距离500米,工作波段3mm,扫描视场角1度
|
||
altimeter = new MillimeterWaveAltimeter(this, 1000, MillimeterWaveBand.Band8, 0.5, 25); // 毫米波测高仪,测量精度0.5米
|
||
rangefinder = new LaserRangefinder(this, 500, 1.06, 100, 0.5); // 激光测距仪,测量距离500米,波长1.06µm,测量频率100Hz,测量精度0.5米
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新子弹状态
|
||
/// </summary>
|
||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||
/// <remarks>
|
||
/// 更新过程:
|
||
/// - 更新所有传感器
|
||
/// - 根据当前阶段更新状态
|
||
/// - 处理阶段转换
|
||
/// - 调用基类更新
|
||
/// </remarks>
|
||
public override void Update(double deltaTime)
|
||
{
|
||
base.Update(deltaTime);
|
||
|
||
// 更新传感器
|
||
infraredDetector.Update(deltaTime);
|
||
radiometer.Update(deltaTime);
|
||
altimeter.Update(deltaTime);
|
||
rangefinder.Update(deltaTime);
|
||
|
||
switch (currentStage)
|
||
{
|
||
case SubmunitionStage.Separation:
|
||
UpdateSeparationStage(deltaTime);
|
||
break;
|
||
case SubmunitionStage.Deceleration:
|
||
UpdateDecelerationStage(deltaTime);
|
||
break;
|
||
case SubmunitionStage.ParachuteDeployment:
|
||
UpdateParachuteDeploymentStage(deltaTime);
|
||
break;
|
||
case SubmunitionStage.StableScan:
|
||
UpdateStableScanStage(deltaTime);
|
||
break;
|
||
case SubmunitionStage.Detection:
|
||
UpdateDetectionStage(deltaTime);
|
||
break;
|
||
case SubmunitionStage.Attack:
|
||
UpdateAttackStage(deltaTime);
|
||
break;
|
||
case SubmunitionStage.Explode:
|
||
UpdateExplodeStage(deltaTime);
|
||
break;
|
||
case SubmunitionStage.SelfDestruct:
|
||
UpdateSelfDestructStage(deltaTime);
|
||
break;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新分离阶段状态
|
||
/// </summary>
|
||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||
/// <remarks>
|
||
/// 分离阶段处理:
|
||
/// - 施加重力加速度
|
||
/// - 更新位置和速度
|
||
/// - 分离阶段结束,进入减速阶段
|
||
/// </remarks>
|
||
private void UpdateSeparationStage(double deltaTime)
|
||
{
|
||
// 分离阶段
|
||
Vector3D deceleration = new(0, 9.8, 0);
|
||
Velocity += deceleration * deltaTime;
|
||
Position += Velocity * deltaTime;
|
||
|
||
// 分离阶段结束,进入减速阶段
|
||
currentStage = SubmunitionStage.Deceleration;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新减速阶段状态
|
||
/// </summary>
|
||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||
/// <remarks>
|
||
/// 减速阶段处理:
|
||
/// - 启用制导控制
|
||
/// - 计算减速加速度
|
||
/// - 更新速度和位置
|
||
/// - 检查高度条件
|
||
/// - 如果高度小于等于开伞高度,则进入降落伞打开阶段
|
||
/// </remarks>
|
||
private void UpdateDecelerationStage(double deltaTime)
|
||
{
|
||
IsGuidance = true;
|
||
|
||
if(!altimeter.IsActive)
|
||
{
|
||
// 激活毫米波测高雷达
|
||
altimeter.Activate();
|
||
}
|
||
|
||
// 减速减旋,垂直速度减小
|
||
Vector3D deceleration = - Velocity.Normalize() * DecelerationAcceleration;
|
||
Velocity += deceleration * deltaTime;
|
||
|
||
if (Velocity.Magnitude() <= DecelerationEndSpeed)
|
||
{
|
||
Velocity = new Vector3D(0, -DecelerationEndSpeed, 0);
|
||
GuidanceAcceleration = Vector3D.Zero;
|
||
}
|
||
|
||
if(IsSensorsJammed())
|
||
{
|
||
// 如果传感器受到干扰,则高度计无法工作
|
||
Console.WriteLine("减速阶段:传感器受到干扰,无法进行高度测量");
|
||
return;
|
||
}
|
||
|
||
// 检查高度是否小于等于开伞高度
|
||
if(((AltimeterSensorData)altimeter.GetSensorData()).Altitude <= ParachuteDeploymentHeight)
|
||
{
|
||
// 如果是,则进入降落伞打开阶段
|
||
currentStage = SubmunitionStage.ParachuteDeployment;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新降落伞打开阶段状态
|
||
/// </summary>
|
||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||
/// <remarks>
|
||
/// 降落伞打开阶段处理:
|
||
/// - 打开降落伞
|
||
/// - 降落伞减速和稳定
|
||
/// - 调整姿态准备扫描
|
||
/// - 激活测高雷达开始工作(第二次测高)
|
||
/// - 在200米高度进入扫描阶段
|
||
/// - 此时子弹速度 10 米/秒
|
||
/// </remarks>
|
||
private void UpdateParachuteDeploymentStage(double deltaTime)
|
||
{
|
||
if (Velocity.Magnitude() <= VerticalDeclineSpeed)
|
||
{
|
||
Velocity = new Vector3D(0, -VerticalDeclineSpeed, 0);
|
||
GuidanceAcceleration = Vector3D.Zero;
|
||
}
|
||
|
||
if(IsSensorsJammed())
|
||
{
|
||
// 如果传感器受到干扰,则高度计无法工作
|
||
Console.WriteLine("开伞阶段:传感器受到干扰,无法进行高度测量");
|
||
return;
|
||
}
|
||
|
||
if (((AltimeterSensorData)altimeter.GetSensorData()).Altitude <= StableScanHeight)
|
||
{
|
||
currentStage = SubmunitionStage.StableScan;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新稳定扫描阶段状态
|
||
/// </summary>
|
||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||
/// <remarks>
|
||
/// 扫描阶段处理:
|
||
/// - 激活传感器系统
|
||
/// - 执行螺旋扫描
|
||
/// - 处理目标探测
|
||
/// - 检查目标确认条件
|
||
/// </remarks>
|
||
private void UpdateStableScanStage(double deltaTime)
|
||
{
|
||
if(!rangefinder.IsActive)
|
||
{
|
||
// 激活激光测距仪
|
||
rangefinder.Activate();
|
||
}
|
||
|
||
// 检查传感器干扰状态
|
||
if (IsSensorsJammed())
|
||
{
|
||
Console.WriteLine("稳定扫描阶段:传感器受到干扰,无法进行距离测量");
|
||
return;
|
||
}
|
||
|
||
// 更新螺旋角度(顺时针旋转,标准方位角)
|
||
spiralAngle = (spiralAngle + SpiralRotationSpeed * deltaTime); // 顺时针角度增加
|
||
while (spiralAngle >= 2 * Math.PI)
|
||
{
|
||
spiralAngle -= 2 * Math.PI;
|
||
}
|
||
|
||
// 更新扫描方向(标准方位角,顺时针为正)
|
||
scanDirection = new Vector3D(
|
||
Math.Sin(spiralAngle) * Math.Sin(ScanAngle),
|
||
-Math.Cos(ScanAngle),
|
||
Math.Cos(spiralAngle) * Math.Sin(ScanAngle)
|
||
).Normalize();
|
||
|
||
// 如果距离小于等于目标探测距离,则进入目标探测阶段
|
||
if (((RangefinderSensorData)rangefinder.GetSensorData()).Distance <= TargetDetectionDistance)
|
||
{
|
||
currentStage = SubmunitionStage.Detection;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新目标探测阶段状态
|
||
/// </summary>
|
||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||
/// <remarks>
|
||
/// 目标探测阶段处理:
|
||
/// - 多传感器协同工作
|
||
/// - 进行目标特征识别
|
||
/// - 执行二次扫描确认
|
||
/// - 为攻击阶段做准备
|
||
/// </remarks>
|
||
private void UpdateDetectionStage(double deltaTime)
|
||
{
|
||
// 激活毫米波辐射计
|
||
if(!radiometer.IsActive)
|
||
{
|
||
radiometer.Activate();
|
||
}
|
||
// 激活红外探测器
|
||
if(!infraredDetector.IsActive)
|
||
{
|
||
infraredDetector.Activate();
|
||
}
|
||
|
||
// 检查传感器干扰状态
|
||
if (IsSensorsJammed())
|
||
{
|
||
Console.WriteLine("探测阶段:传感器受到干扰,无法进行目标探测");
|
||
return;
|
||
}
|
||
|
||
// 更新螺旋角度(顺时针旋转)
|
||
spiralAngle = (spiralAngle + SpiralRotationSpeed * deltaTime); // 顺时针角度增加
|
||
while (spiralAngle >= 2 * Math.PI)
|
||
{
|
||
spiralAngle -= 2 * Math.PI;
|
||
}
|
||
|
||
// 计算扫描方向
|
||
scanDirection = new Vector3D(
|
||
Math.Sin(spiralAngle) * Math.Sin(ScanAngle),
|
||
-Math.Cos(ScanAngle),
|
||
Math.Cos(spiralAngle) * Math.Sin(ScanAngle)
|
||
).Normalize();
|
||
|
||
// 获取传感器数据
|
||
RadiometerSensorData? radiometerData = null;
|
||
InfraredSensorData? infraredData = null;
|
||
|
||
if (radiometer.GetSensorData() is RadiometerSensorData rd)
|
||
{
|
||
radiometerData = rd;
|
||
}
|
||
if (infraredDetector.GetSensorData() is InfraredSensorData id)
|
||
{
|
||
infraredData = id;
|
||
}
|
||
|
||
bool isRadiationDetected = radiometerData?.IsTargetDetected ?? false;
|
||
bool isInfraredDetected = infraredData?.IsTargetDetected ?? false;
|
||
|
||
// 如果还未探测到目标,进行首次探测
|
||
if (!isTargetDetected)
|
||
{
|
||
if (isRadiationDetected || isInfraredDetected)
|
||
{
|
||
// 获取传感器的角度数据
|
||
double? radiometerAngle = radiometerData?.TargetAngle;
|
||
double? infraredAngle = infraredData?.TargetAngle;
|
||
|
||
// 使用有效的角度数据
|
||
if (radiometerAngle.HasValue || infraredAngle.HasValue)
|
||
{
|
||
// 计算目标方位角
|
||
double targetAngle;
|
||
if (radiometerAngle.HasValue && infraredAngle.HasValue)
|
||
{
|
||
targetAngle = (radiometerAngle.Value + infraredAngle.Value) / 2;
|
||
}
|
||
else if (radiometerAngle.HasValue)
|
||
{
|
||
targetAngle = radiometerAngle.Value;
|
||
}
|
||
else
|
||
{
|
||
targetAngle = infraredAngle.Value;
|
||
}
|
||
|
||
// 记录首次探测信息
|
||
isTargetDetected = true;
|
||
lastDetectionTime = FlightTime;
|
||
firstDetectionAngle = targetAngle;
|
||
Console.WriteLine($"[DEBUG] 首次探测到目标,方位角: {firstDetectionAngle.Value * 180 / Math.PI:F2}°");
|
||
}
|
||
}
|
||
}
|
||
else // 已经探测到目标,等待转过一圈进行二次确认
|
||
{
|
||
double timeSinceLastDetection = FlightTime - lastDetectionTime.Value;
|
||
if (timeSinceLastDetection >= 0.75 * 2 * Math.PI / SpiralRotationSpeed) // 转过3/4圈以后
|
||
{
|
||
// 检查当前角度是否接近记录的目标方位角
|
||
double angleDiff = Math.Abs(spiralAngle - firstDetectionAngle.Value);
|
||
// 根据仿真步长和转速计算允许的角度误差
|
||
double allowedError = deltaTime * SpiralRotationSpeed / 2;
|
||
if (angleDiff <= allowedError)
|
||
{
|
||
if (isRadiationDetected || isInfraredDetected)
|
||
{
|
||
// 二次确认成功,进入攻击阶段
|
||
Console.WriteLine($"[DEBUG] 二次确认成功,进入攻击阶段,当前角度: {spiralAngle * 180 / Math.PI:F2}°");
|
||
currentStage = SubmunitionStage.Attack;
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
// 二次确认失败,重新开始扫描
|
||
Console.WriteLine($"[DEBUG] 二次确认失败,重新开始扫描");
|
||
isTargetDetected = false;
|
||
lastDetectionTime = null;
|
||
firstDetectionAngle = null;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 检查自毁条件
|
||
if (rangefinder.GetSensorData() is RangefinderSensorData rangefinderData &&
|
||
rangefinderData.Distance <= SelfDestructHeight)
|
||
{
|
||
currentStage = SubmunitionStage.SelfDestruct;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新攻击阶段状态
|
||
/// </summary>
|
||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||
/// <remarks>
|
||
/// 攻击阶段处理:
|
||
/// - 使用记录的攻击角度计算攻击方向
|
||
/// - 使用扫描方向作为攻击方向,弹丸没有传感器,只进行弹道运动
|
||
/// - 更新速度和位置
|
||
/// - 检查命中条件:使用纯几何计算
|
||
/// </remarks>
|
||
private void UpdateAttackStage(double deltaTime)
|
||
{
|
||
// 关闭传感器
|
||
if (radiometer.IsActive)
|
||
{
|
||
radiometer.Deactivate();
|
||
}
|
||
if (infraredDetector.IsActive)
|
||
{
|
||
infraredDetector.Deactivate();
|
||
}
|
||
|
||
// 使用当前的spiralAngle计算攻击方向
|
||
scanDirection = new Vector3D(
|
||
Math.Sin(spiralAngle) * Math.Sin(ScanAngle),
|
||
-Math.Cos(ScanAngle),
|
||
Math.Cos(spiralAngle) * Math.Sin(ScanAngle)
|
||
).Normalize();
|
||
|
||
// 使用 AttackSpeed 设置攻击速度
|
||
Velocity = scanDirection * AttackSpeed;
|
||
IsGuidance = false; // 明确声明这是无制导的直线运动
|
||
GuidanceAcceleration = Vector3D.Zero; // 清除任何可能的加速度
|
||
|
||
// 检查命中条件:使用纯几何计算
|
||
SimulationElement target = SimulationManager.GetEntityById(TargetId) as SimulationElement ?? throw new Exception("目标不存在");
|
||
if ((target.Position - Position).Magnitude() <= MissileProperties.ExplosionRadius)
|
||
{
|
||
currentStage = SubmunitionStage.Explode;
|
||
return;
|
||
}
|
||
|
||
// 检查自毁条件
|
||
if (Position.Y <= 0)
|
||
{
|
||
currentStage = SubmunitionStage.SelfDestruct;
|
||
return;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新爆炸阶段状态
|
||
/// </summary>
|
||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||
/// <remarks>
|
||
/// 爆炸阶段处理:
|
||
/// - 触发爆炸效果
|
||
/// - 结束子弹任务
|
||
/// </remarks>
|
||
private void UpdateExplodeStage(double deltaTime)
|
||
{
|
||
Explode();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新自毁阶段状态
|
||
/// </summary>
|
||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||
/// <remarks>
|
||
/// 自毁阶段处理:
|
||
/// - 触发自毁效果
|
||
/// - 结束子弹任务
|
||
/// </remarks>
|
||
private void UpdateSelfDestructStage(double deltaTime)
|
||
{
|
||
SelfDestruct();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检测目标是否在视场内
|
||
/// </summary>
|
||
/// <param name="fieldOfView">视场角,单位:度</param>
|
||
/// <returns>返回目标方位角。如果目标在视场内返回方位角,否则返回null</returns>
|
||
/// <remarks>
|
||
/// 检测过程:
|
||
/// - 获取目标位置
|
||
/// - 计算目标方向
|
||
/// - 判断是否在视场内
|
||
/// </remarks>
|
||
public double? DetectTarget(double fieldOfView)
|
||
{
|
||
// 获取目标对象
|
||
SimulationElement target = SimulationManager.GetEntityById(TargetId) as SimulationElement ?? throw new Exception("目标不存在");
|
||
|
||
// 获取目标的尺寸属性
|
||
double targetLength = (target as ITarget)?.Length ?? 0; // 目标长度
|
||
double targetWidth = (target as ITarget)?.Width ?? 0; // 目标宽度
|
||
|
||
// 获取目标的朝向向量
|
||
Vector3D targetForward = target.Orientation.ToVector();
|
||
Vector3D targetRight = Vector3D.CrossProduct(Vector3D.UnitY, targetForward).Normalize();
|
||
|
||
// 计算矩形四个顶点的位置
|
||
Vector3D targetPosition = target.Position;
|
||
Vector3D[] vertices = new Vector3D[4];
|
||
|
||
// 前后左右四个顶点
|
||
vertices[0] = targetPosition + (targetForward * (targetLength/2)) + (targetRight * (targetWidth/2)); // 右前
|
||
vertices[1] = targetPosition + (targetForward * (targetLength/2)) - (targetRight * (targetWidth/2)); // 左前
|
||
vertices[2] = targetPosition - (targetForward * (targetLength/2)) + (targetRight * (targetWidth/2)); // 右后
|
||
vertices[3] = targetPosition - (targetForward * (targetLength/2)) - (targetRight * (targetWidth/2)); // 左后
|
||
|
||
// 计算目标方位角(弧度值)
|
||
Vector3D toTarget = (targetPosition - Position).Normalize();
|
||
double targetAzimuth = Math.Atan2(toTarget.X, toTarget.Z); // 修改为 atan2(X, Z) 使正北为0度
|
||
if (targetAzimuth < 0)
|
||
{
|
||
targetAzimuth += 2 * Math.PI; // 转换到 [0, 2π]
|
||
}
|
||
|
||
// 视场检测
|
||
double cosFieldOfView = Math.Cos(fieldOfView * Math.PI / 180);
|
||
foreach(var vertex in vertices)
|
||
{
|
||
Vector3D toVertex = (vertex - Position).Normalize();
|
||
if(Vector3D.DotProduct(scanDirection, toVertex) > cosFieldOfView)
|
||
{
|
||
// 如果目标的任何一个顶点在视场角内,返回目标方位角
|
||
return targetAzimuth;
|
||
}
|
||
}
|
||
|
||
// 如果目标不在视场角内,返回null
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 激活子弹
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 激活过程:
|
||
/// - 调用基类激活方法
|
||
/// - 订阅目标辐射事件
|
||
/// - 准备传感器系统
|
||
/// </remarks>
|
||
public override void Activate()
|
||
{
|
||
base.Activate();
|
||
SimulationManager.SubscribeToEvent<TankRadiationEvent>(OnTankRadiationEvent);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 停用子弹
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 停用过程:
|
||
/// - 调用基类停用方法
|
||
/// - 停用所有传感器
|
||
/// - 清理制导状态
|
||
/// </remarks>
|
||
public override void Deactivate()
|
||
{
|
||
base.Deactivate();
|
||
infraredDetector.Deactivate();
|
||
radiometer.Deactivate();
|
||
altimeter.Deactivate();
|
||
rangefinder.Deactivate();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理坦克辐射事件
|
||
/// </summary>
|
||
/// <param name="evt">坦克辐射事件数据</param>
|
||
/// <remarks>
|
||
/// 处理过程:
|
||
/// - 验证目标ID
|
||
/// - 记录辐射信息
|
||
/// - 更新目标状态
|
||
/// </remarks>
|
||
private void OnTankRadiationEvent(TankRadiationEvent evt)
|
||
{
|
||
if (evt.SenderId == TargetId)
|
||
{
|
||
Console.WriteLine("检测到目标辐射");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取子弹状态信息
|
||
/// </summary>
|
||
/// <returns>包含子弹状态的详细描述</returns>
|
||
/// <remarks>
|
||
/// 返回信息包括:
|
||
/// - 基本状态信息
|
||
/// - 当前飞行阶段
|
||
/// - 扫描和检测状态
|
||
/// - 传感器工作状态
|
||
/// </remarks>
|
||
public override string GetStatus()
|
||
{
|
||
var status = $"{base.GetStatus()}\n" +
|
||
$"运行状态: {currentStage}\n" +
|
||
$"扫描角度: {spiralAngle * 180 / Math.PI:F2}°, 弧度值: {spiralAngle:F6}\n" +
|
||
$"目标检测: {lastDetectionTime != null}";
|
||
|
||
//var status = $"";
|
||
|
||
return status;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查传感器是否受到干扰
|
||
/// </summary>
|
||
/// <returns>如果当前阶段的关键传感器都被干扰返回true,否则返回false</returns>
|
||
/// <remarks>
|
||
/// 不同阶段的检查逻辑:
|
||
/// - Deceleration阶段:测高仪被干扰才返回true
|
||
/// - ParachuteDeployment阶段:测高仪被干扰才返回true
|
||
/// - StableScan阶段:激光测距仪被干扰才返回true
|
||
/// - Detection阶段:红外探测器和毫米波辐射计都被干扰才返回true
|
||
/// - Attack阶段:红外探测器和毫米波辐射计都被干扰才返回true
|
||
/// </remarks>
|
||
private bool IsSensorsJammed()
|
||
{
|
||
// 根据当前阶段检查相应传感器的干扰状态
|
||
switch (currentStage)
|
||
{
|
||
case SubmunitionStage.Deceleration:
|
||
// 减速阶段需要测高仪
|
||
return altimeter.IsJammed;
|
||
case SubmunitionStage.ParachuteDeployment:
|
||
// 开伞阶段需要测高仪
|
||
return altimeter.IsJammed;
|
||
case SubmunitionStage.StableScan:
|
||
// 稳定扫描阶段需要激光测距仪
|
||
return rangefinder.IsJammed;
|
||
case SubmunitionStage.Detection:
|
||
// 目标探测阶段需要红外探测器和毫米波辐射计
|
||
return infraredDetector.IsJammed && radiometer.IsJammed;
|
||
case SubmunitionStage.Attack:
|
||
// 攻击阶段需要红外探测器和毫米波辐射计
|
||
return infraredDetector.IsJammed && radiometer.IsJammed;
|
||
default:
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
}
|