using System.Diagnostics;
using ThreatSource.Simulation;
using ThreatSource.Utils;
using System.Reflection;
namespace ThreatSource.Missile
{
///
/// 导弹基类,实现了导弹的基本功能和状态管理
///
///
/// 该类提供了导弹的核心功能:
/// - 运动状态计算和更新
/// - 制导系统管理
/// - 发动机控制
/// - 自毁和爆炸处理
/// - 状态监控和事件处理
/// 所有具体的导弹类型都继承自此基类
///
public class BaseMissile : SimulationElement, IMissile
{
///
/// 获取导弹的当前飞行时间
///
/// 飞行时间,单位:秒
///
/// 从发射时刻开始计时
/// 用于控制导弹的生命周期
///
public double FlightTime { get; protected set; }
///
/// 获取导弹的当前飞行距离
///
/// 飞行距离,单位:米
///
/// 从发射点到当前位置的累计飞行距离
/// 用于判断是否超出最大射程
///
public double FlightDistance { get; protected set; }
///
/// 获取发动机的当前燃烧时间
///
/// 发动机燃烧时间,单位:秒
///
/// 发动机工作的累计时间
/// 用于控制推力变化和燃料消耗
///
public double EngineBurnTime { get; protected set; }
///
/// 获取导弹是否处于制导状态
///
/// true表示导弹当前在制导,false表示导弹处于非制导状态
///
/// 影响导弹的运动学计算方法
/// 制导状态下使用制导律计算加速度
/// 非制导状态下使用弹道方程计算运动
///
public bool IsGuidance { get; protected set; }
///
/// 获取或设置前一个制导状态
///
/// 上一个时间步的制导状态
///
/// 用于检测制导状态变化
/// 当IsGuidance与此值不同时,表示制导状态发生了变化
///
protected bool PreviousIsGuidance { get; set; } = false;
///
/// 获取或设置导弹的最后已知速度向量
///
/// 三维速度向量
///
/// 用于在失去制导时保持导弹的运动状态
/// 作为弹道计算的参考数据
///
protected Vector3D LastKnownVelocity = Vector3D.Zero;
///
/// 获取或设置导弹的制导加速度
///
/// 三维加速度向量,单位:米/秒²
///
/// 由制导系统计算得出的期望加速度
/// 用于修正导弹的飞行路径
///
protected Vector3D GuidanceAcceleration { get; set; } = Vector3D.Zero;
///
/// 获取或设置导弹的推力加速度
///
/// 三维加速度向量,单位:米/秒²
///
/// 由发动机产生的推进加速度
/// 影响导弹的速度变化
///
protected Vector3D ThrustAcceleration { get; set; }
///
/// 获取或设置导弹的升力加速度
///
/// 三维加速度向量,单位:米/秒²
///
/// 由升力产生的加速度
/// 影响导弹的垂直运动
///
protected Vector3D LiftAcceleration { get; set; }
///
/// 重力加速度(北京标准值)
///
private static readonly Vector3D GravityAcceleration = new(0, -PhysicalConstants.BeijingGravity, 0);
///
/// 获取导弹的固定配置参数
///
/// 导弹属性配置对象
///
/// 包含导弹的所有基本属性和性能限制
/// 在导弹创建时设置,运行期间保持不变
///
public readonly MissileProperties Properties;
///
/// 标准导弹三段式飞行阶段
///
public enum MissileFlightStage
{
///
/// 发射阶段
///
Launch,
///
/// 巡航阶段
///
Cruise,
///
/// 制导阶段
///
Guidance
}
///
/// 当前飞行阶段
///
protected MissileFlightStage currentStage = MissileFlightStage.Launch;
///
/// 初始化导弹基类的新实例
///
/// 导弹ID
/// 导弹属性配置
/// 发射参数
/// 仿真管理器实例
///
/// 构造过程:
/// - 初始化基本属性
/// - 设置性能限制
/// - 配置运动参数
/// - 建立仿真管理器关联
///
protected BaseMissile(
string missileId,
MissileProperties properties,
KinematicState kinematicState,
ISimulationManager manager)
: base(missileId, kinematicState, manager)
{
// 设置性能限制
Properties = properties;
// 初始化状态
EngineBurnTime = 0;
FlightTime = 0;
FlightDistance = 0;
IsActive = false;
IsGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
LiftAcceleration = Vector3D.Zero;
// 计算初始推力加速度
Vector3D launchDirection = kinematicState.Orientation.ToVector().Normalize();
ThrustAcceleration = launchDirection * properties.LaunchAcceleration;
}
///
/// 判断是否为末敏弹类型
///
protected bool IsTerminalSensitiveType()
{
return Properties.Type == MissileType.TerminalSensitiveSubmunition;
}
///
/// 供末敏弹等特殊导弹重写的自定义阶段更新方法
///
protected virtual void UpdateCustomStages(double deltaTime) { }
///
/// 更新导弹的状态
///
/// 时间步长,单位:秒
///
/// 更新过程:
/// - 检查导弹是否处于活动状态
/// - 更新导弹的运动状态
/// - 更新计时器和计数器
///
public override void Update(double deltaTime)
{
if (!IsActive) return;
// 末敏弹等特殊类型走自定义流程
if (!IsTerminalSensitiveType())
{
// 标准三段式流程
switch (currentStage)
{
case MissileFlightStage.Launch:
OnLaunchStage(deltaTime);
break;
case MissileFlightStage.Cruise:
OnCruiseStage(deltaTime);
break;
case MissileFlightStage.Guidance:
OnGuidanceStage(deltaTime);
break;
}
}
// 公共运动学与生命周期管理
UpdateMotionState(deltaTime);
if (ShouldSelfDestruct())
{
SelfDestruct();
}
// 检测制导状态变化并发布相应事件
CheckGuidanceStatusChange();
}
///
/// 发射阶段默认实现
///
protected virtual void OnLaunchStage(double deltaTime)
{
// 发射阶段不使用制导
GuidanceAcceleration = Vector3D.Zero;
// 计算升力加速度。在发射阶段,升力加速度和攻角相关
LiftAcceleration = LiftModel.CalculateLiftAcceleration(KState.Orientation.Pitch * 180 / Math.PI);
// 发射阶段结束,进入巡航阶段
if (FlightTime >= Properties.MaxEngineBurnTime)
{
currentStage = MissileFlightStage.Cruise;
}
}
///
/// 巡航阶段默认实现
///
protected virtual void OnCruiseStage(double deltaTime)
{
// 巡航阶段不使用制导
GuidanceAcceleration = Vector3D.Zero;
// 调整速度方向为水平飞行
if (Math.Abs(KState.Velocity.Y) > 0.1) // 如果有明显的垂直速度分量
{
// 保持水平速度大小,消除垂直分量
double horizontalSpeed = Math.Sqrt(KState.Velocity.X * KState.Velocity.X + KState.Velocity.Z * KState.Velocity.Z);
if (horizontalSpeed > 0.1) // 确保有水平速度
{
Vector3D horizontalDirection = new Vector3D(KState.Velocity.X, 0, KState.Velocity.Z).Normalize();
KState.Velocity = horizontalDirection * KState.Speed;
}
}
// 设置巡航攻角(相对于水平面)
double cruiseAttackAngleRad = Properties.CruiseAttackAngle * Math.PI / 180.0;
KState.Orientation = new Orientation(KState.Orientation.Yaw, cruiseAttackAngleRad, KState.Orientation.Roll);
// 计算升力加速度:在巡航阶段,基于攻角计算升力
LiftAcceleration = LiftModel.CalculateLiftAcceleration(Properties.CruiseAttackAngle);
// 巡航阶段结束,进入制导阶段
if (FlightTime >= Properties.MaxEngineBurnTime + Properties.CruiseTime)
{
currentStage = MissileFlightStage.Guidance;
}
}
///
/// 制导阶段默认实现
///
protected virtual void OnGuidanceStage(double deltaTime)
{
// 计算升力加速度。在制导阶段,升力加速度和攻角相关;
LiftAcceleration = LiftModel.CalculateLiftAcceleration(KState.Orientation.Pitch * 180 / Math.PI);
}
///
/// 更新导弹的运动状态
///
/// 时间步长,单位:秒
///
/// 更新过程:
/// - 计算包含风影响的合加速度
/// - 根据制导状态选择运动更新方法
/// - 更新导弹的位置和速度
///
protected virtual void UpdateMotionState(double deltaTime)
{
// 检查发动机是否仍在提供推力
if (ThrustAcceleration != Vector3D.Zero)
{
EngineBurnTime += deltaTime; // 累加燃烧时间
if (EngineBurnTime >= Properties.MaxEngineBurnTime || KState.Speed >= Properties.MaxSpeed)
{
string reason = EngineBurnTime >= Properties.MaxEngineBurnTime ?
$"达到最大燃烧时间({Properties.MaxEngineBurnTime}s)" :
$"达到最大速度({KState.Speed:F2}m/s >= {Properties.MaxSpeed}m/s)";
Debug.WriteLine($"导弹 {Id}: 发动机推力已于飞行时间 {FlightTime:F2}s 关闭。原因: {reason}");
ThrustAcceleration = Vector3D.Zero; // 关闭推力
}
}
// 计算包含风影响的合加速度
Vector3D acceleration = CalculateAcceleration(KState.Velocity);
if (IsGuidance)
{
// 制导条件下,使用四阶龙格-库塔方法更新导弹的位置和速度
(KState.Position, KState.Velocity) = MotionAlgorithm.RungeKutta4(deltaTime, KState.Position, KState.Velocity, acceleration);
}
else
{
// 无制导条件下,使用运动学方程更新导弹的位置和速度
(KState.Position, KState.Velocity) = MotionAlgorithm.CalculateBallisticMotion(KState.Position, KState.Velocity, acceleration, deltaTime);
}
// 在制导阶段,根据是否获得制导来调整导弹朝向
if(currentStage == MissileFlightStage.Guidance)
{
if (!IsGuidance)
{
// 导引头搜索阶段:保持水平飞行,导弹朝向向下一个固定角度进行搜索
// 不改变速度向量,让导引头在下视角范围内搜索目标
double seekingAngleRad = Properties.GuidanceSeekingAngle * Math.PI / 180.0;
KState.Orientation = new Orientation(KState.Orientation.Yaw, -seekingAngleRad, KState.Orientation.Roll);
}
// 如果IsGuidance为true,制导系统会通过GuidanceAcceleration自动调整导弹的飞行轨迹和朝向
}
// 限制速度不超过最大速度
if (KState.Speed > Properties.MaxSpeed)
{
KState.Speed = Properties.MaxSpeed;
}
// 添加高斯噪声(测试用,用于测试运动中概率的影响)
// Position = MotionAlgorithm.AddRandomPerturbation(Position);
// Velocity = MotionAlgorithm.AddRandomPerturbation(Velocity);
FlightTime += deltaTime;
FlightDistance += KState.Speed * deltaTime;
}
///
/// 计算导弹的合加速度
///
/// 当前速度向量
/// 合加速度向量
///
/// 计算过程:
/// - 获取当前风速向量
/// - 计算空气阻力加速度(已考虑风)
/// - 合成总加速度(制导加速度 + 推力加速度 + 空气阻力加速度 + 重力加速度)
/// - 限制合加速度不超过最大值
///
private Vector3D CalculateAcceleration(Vector3D velocity)
{
// 获取当前风速向量
Vector3D windVector = GetWindVectorFromWeather();
// 计算空气阻力加速度(考虑风的影响)
Vector3D dragAcceleration = MotionAlgorithm.CalculateDragAcceleration(velocity, windVector, Properties.Mass);
// 合成总加速度(制导加速度 + 推力加速度 + 空气阻力加速度 + 升力加速度 + 重力加速度)
Vector3D totalAcceleration = GuidanceAcceleration + ThrustAcceleration + dragAcceleration + LiftAcceleration + GravityAcceleration;
Debug.WriteLine($"导弹 {Id} 的加速度: {totalAcceleration}, 制导: {GuidanceAcceleration}, " +
$"推力: {ThrustAcceleration}, 空阻(含风): {dragAcceleration}, 升力: {LiftAcceleration}, 重力: {GravityAcceleration}");
if (totalAcceleration.Magnitude() > Properties.MaxAcceleration)
{
totalAcceleration = totalAcceleration.Normalize() * Properties.MaxAcceleration;
}
return totalAcceleration;
}
///
/// 从天气系统获取当前的风速向量
///
/// 风速向量,单位:米/秒
protected Vector3D GetWindVectorFromWeather()
{
var weather = SimulationManager.CurrentWeather;
if (weather == null)
return Vector3D.Zero;
return MotionAlgorithm.CalculateWindVector(weather.WindSpeed, weather.WindDirection);
}
///
/// 发射导弹
///
///
/// 发射过程:
/// - 开始计时和计数
/// - 启动发动机
/// - 初始化运动状态
///
public virtual void Fire()
{
// 子类可以重写此方法来处理发射时的特殊逻辑
}
///
/// 检查是否应该自毁
///
/// true表示需要自毁,false表示可以继续飞行
///
/// 自毁条件:
/// - 超出最大飞行时间
/// - 超出最大飞行距离
/// - 有制导时:高度低于负爆炸半径(考虑仿真步长)
/// - 无制导时:高度低于安全阈值
///
protected bool ShouldSelfDestruct()
{
// 基本条件判断
if (FlightTime >= Properties.MaxFlightTime
|| FlightDistance >= Properties.MaxFlightDistance)
{
return true;
}
// 根据制导状态判断自毁高度
if (IsGuidance)
{
// 有制导时,在负爆炸半径高度自毁(考虑仿真步长)
return KState.Position.Y <= -Properties.ExplosionRadius;
}
else
{
// 无制导时,在自毁高度自毁
return KState.Position.Y <= Properties.SelfDestructHeight;
}
}
///
/// 导弹爆炸
///
///
/// 爆炸过程:
/// - 停止导弹运动
/// - 触发爆炸效果
/// - 发布爆炸事件
/// - 结束导弹任务
///
public virtual void Explode()
{
OnExplode();
Deactivate();
}
///
/// 爆炸后处理
///
///
/// 爆炸后处理:
/// - 设置导弹状态为非活动
/// - 触发爆炸事件
///
protected virtual void OnExplode()
{
// 发布导弹爆炸事件
var explodeEvent = new MissileExplodeEvent
{
SenderId = Id,
Position = KState.Position,
ExplosionRadius = Properties.ExplosionRadius,
TargetId = null // 这里可以根据需要设置目标ID,通常在子类中重写
};
SimulationManager.PublishEvent(explodeEvent);
// 子类可以重写此方法来处理爆炸时的特殊逻辑
}
///
/// 导弹自毁
///
///
/// 自毁过程:
/// - 记录自毁原因
/// - 停止导弹运动
/// - 触发自毁效果
/// - 结束导弹任务
///
public void SelfDestruct()
{
string reason;
if (FlightTime >= Properties.MaxFlightTime)
{
reason = "超出最大飞行时间";
}
else if (FlightDistance >= Properties.MaxFlightDistance)
{
reason = "超出最大飞行距离";
}
else if (IsGuidance && KState.Position.Y <= -Properties.ExplosionRadius)
{
reason = "有制导状态下高度低于负爆炸半径";
}
else if (!IsGuidance && KState.Position.Y <= Properties.SelfDestructHeight)
{
reason = "无制导状态下高度低于自毁高度";
}
else
{
reason = "未知原因触发自毁";
}
Trace.TraceInformation($"导弹 {Id} 自毁。原因: {reason}");
// 发布导弹自毁事件
var selfDestructEvent = new MissileSelfDestructEvent
{
SenderId = Id,
Reason = reason,
Position = KState.Position
};
SimulationManager.PublishEvent(selfDestructEvent);
OnSelfDestruct();
Deactivate();
}
///
/// 自毁后处理
///
///
/// 自毁后处理:
/// - 设置导弹状态为非活动
/// - 触发自毁事件
///
protected virtual void OnSelfDestruct()
{
// 子类可以重写此方法来处理自毁时的特殊逻辑
}
///
/// 激活导弹
///
///
/// 激活过程:
/// - 调用基类激活方法
/// - 订阅目标命中事件
///
public override void Activate()
{
base.Activate();
SimulationManager.SubscribeToEvent(OnTargetHitEvent);
}
///
/// 停用导弹
///
///
/// 停用过程:
/// - 调用基类停用方法
/// - 取消订阅目标命中事件
///
public override void Deactivate()
{
base.Deactivate();
SimulationManager.UnsubscribeFromEvent(OnTargetHitEvent);
}
private void OnTargetHitEvent(TargetHitEvent eventData)
{
if (eventData.MissileId == Id)
{
Explode();
}
}
///
/// 获取导弹状态信息
///
/// 导弹状态信息
///
/// 返回信息包括:
/// - 基本状态信息
/// - 导弹固有属性
/// - 导弹运行时状态
///
public override ElementStatusInfo GetStatusInfo()
{
// 获取基础状态信息
var statusInfo = base.GetStatusInfo();
// 使用反射动态添加来自 this.Properties 的导弹固有属性
if (Properties != null)
{
var propertiesType = Properties.GetType();
var props = propertiesType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var prop in props)
{
if (prop.CanRead)
{
object? propValue = prop.GetValue(Properties);
if (propValue != null)
{
statusInfo.ExtendedProperties[prop.Name] = propValue;
}
}
}
}
// 添加 BaseMissile 类的运行时状态参数
statusInfo.ExtendedProperties["FlightTime"] = FlightTime;
statusInfo.ExtendedProperties["FlightDistance"] = FlightDistance;
statusInfo.ExtendedProperties["EngineBurnTime"] = EngineBurnTime;
statusInfo.ExtendedProperties["CurrentStage"] = currentStage.ToString();
statusInfo.ExtendedProperties["IsGuidance"] = IsGuidance;
statusInfo.ExtendedProperties["GuidanceAcceleration"] = GuidanceAcceleration;
return statusInfo;
}
///
/// 检测制导状态变化并发布相应事件
///
///
/// 检测过程:
/// - 比较当前制导状态与前一个状态
/// - 如果状态发生变化,发布相应的制导获得或失去事件
/// - 更新前一个状态记录
///
protected virtual void CheckGuidanceStatusChange()
{
if (IsGuidance != PreviousIsGuidance)
{
if (IsGuidance)
{
// 获得制导
var guidanceAcquiredEvent = new MissileGuidanceAcquiredEvent
{
SenderId = Id,
GuidanceType = GetCurrentGuidanceType(),
GuidanceSystemId = GetCurrentGuidanceSystemId()
};
SimulationManager.PublishEvent(guidanceAcquiredEvent);
Trace.TraceInformation($"导弹 {Id} 获得制导");
}
else
{
// 失去制导
var guidanceLostEvent = new MissileGuidanceLostEvent
{
SenderId = Id,
Reason = GetGuidanceLostReason(),
GuidanceType = GetCurrentGuidanceType(),
};
SimulationManager.PublishEvent(guidanceLostEvent);
Trace.TraceInformation($"导弹 {Id} 失去制导,原因: {guidanceLostEvent.Reason}");
}
// 更新前一个状态
PreviousIsGuidance = IsGuidance;
}
}
///
/// 获取当前制导类型描述
///
/// 制导类型字符串
///
/// 子类可以重写此方法以提供更具体的制导类型信息
/// 基类默认根据导弹类型返回通用描述
///
protected virtual string GetCurrentGuidanceType()
{
return Properties.Type switch
{
MissileType.LaserSemiActiveGuidance => "激光半主动制导",
MissileType.LaserBeamRiderGuidance => "激光驾束制导",
MissileType.InfraredImagingTerminalGuidance => "红外成像制导",
MissileType.InfraredCommandGuidance => "红外指令制导",
MissileType.MillimeterWaveTerminalGuidance => "毫米波制导",
MissileType.CompositeGuidance => "复合制导",
_ => "未知制导类型"
};
}
///
/// 获取当前制导系统ID
///
/// 制导系统ID,基类返回null
///
/// 子类可以重写此方法以提供具体的制导系统ID
///
protected virtual string? GetCurrentGuidanceSystemId()
{
return null;
}
///
/// 获取失去制导的原因
///
/// 失去制导的原因描述
///
/// 子类可以重写此方法以提供更具体的失去制导原因
/// 基类默认返回通用描述
///
protected virtual string GetGuidanceLostReason()
{
return "制导系统失效或信号中断";
}
}
}