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 "制导系统失效或信号中断"; } } }