From d9975acd3caf2fd3db8ca5b401d7052ed6473397 Mon Sep 17 00:00:00 2001 From: Tian jianyong <11429339@qq.com> Date: Mon, 7 Oct 2024 00:41:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=BF=80=E5=85=89=E6=8A=A5?= =?UTF-8?q?=E8=AD=A6=E5=99=A8=E5=92=8C=E6=BF=80=E5=85=89=E5=B9=B2=E6=89=B0?= =?UTF-8?q?=E6=9C=BA,=20=E4=BB=BF=E7=9C=9F=E8=BF=87=E7=A8=8B=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E4=BA=8B=E4=BB=B6=E9=A9=B1=E5=8A=A8=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Design.md | 121 +++++++++++++++++++++ Models/LaserDesignator.cs | 118 +++++++++++++++++--- Models/LaserJammer.cs | 74 +++++++++++++ Models/LaserSemiActiveGuidedMissile.cs | 36 +++--- Models/LaserWarner.cs | 69 ++++++++++++ Models/Missile.cs | 121 ++++++++++++++------- Models/Tank.cs | 108 +++++++++--------- Program.cs | 20 ++-- SimulationEnvironment/ISimulatinManager.cs | 12 -- SimulationEnvironment/SimulationConfig.cs | 43 +++++++- SimulationEnvironment/SimulationElement.cs | 7 ++ SimulationEnvironment/SimulationEvents.cs | 34 ++++++ SimulationEnvironment/SimulationManager.cs | 93 ++++++++++++++-- 13 files changed, 697 insertions(+), 159 deletions(-) create mode 100644 Design.md create mode 100644 Models/LaserJammer.cs create mode 100644 Models/LaserWarner.cs delete mode 100644 SimulationEnvironment/ISimulatinManager.cs create mode 100644 SimulationEnvironment/SimulationEvents.cs diff --git a/Design.md b/Design.md new file mode 100644 index 0000000..629efda --- /dev/null +++ b/Design.md @@ -0,0 +1,121 @@ +# 导弹仿真系统设计文档 + +## 系统架构设计思路 + +在处理导弹、坦克、告警设备、干扰设备等复杂交互关系时,我们采用了以下几种程序架构和设计模式的组合: + +### 1. 事件驱动架构(Event-Driven Architecture) + +事件驱动架构非常适合处理复杂的交互关系。每个实体(如导弹、坦克等)可以发布事件,其他实体可以订阅这些事件并作出反应。 + +``csharp +public class EventManager +{ +private Dictionary>> eventSubscribers = new Dictionary>>(); +public void Subscribe(string eventName, Action listener) { ... } +public void Publish(string eventName, object eventData) { ... } +} +`` + +### 2. 组件系统(Component System) + +将每个实体分解为多个组件,每个组件负责特定的功能。这样可以更灵活地组合不同的功能。 + +``csharp +public class Entity +{ +public PositionComponent Position { get; set; } +public VelocityComponent Velocity { get; set; } +public HealthComponent Health { get; set; } +} +`` + +### 3. 观察者模式(Observer Pattern) + +类似于事件驱动架构,但更加面向对象。每个实体可以作为观察者或被观察者。 + +``csharp +public interface IObserver +{ + void Update(ISubject subject); +} + +public interface ISubject +{ + void Attach(IObserver observer); + void Detach(IObserver observer); + void Notify(); +} +`` + +### 4. 状态机(State Machine) + +对于有明确状态转换的实体(如导弹的飞行阶段),使用状态机可以更清晰地管理状态转换。 + +``csharp +public enum MissileState +{ + Idle, + Tracking, + Locking, + Firing, + Exploding +} + +public class Missile +{ + public MissileState State { get; set; } + public void ChangeState(MissileState newState) { ... } +} + +``csharp +public interface IState +{ + void Enter(); + void Update(); + void Exit(); +} +public class MissileStateMachine +{ + private IState currentState; + public void ChangeState(IState newState) { ... } + public void Update() { ... } +} +`` + +### 5. 命令模式(Command Pattern) + +用于封装各种操作,使得可以轻松地添加新的交互行为。 + +``csharp +public interface ICommand +{ + void Execute(); +} + +public class FireMissileCommand : ICommand +{ + public void Execute() { ... } +} +`` + +## 架构组合使用 + +在实际应用中,我们将这些模式组合使用: + +1. 使用事件驱动架构作为整体框架,处理系统中的各种事件。 +2. 采用组件系统来构建各个实体(如导弹、坦克、告警设备等)。 +3. 使用状态机来管理导弹的飞行阶段。 +4. 应用观察者模式来处理告警设备的通知机制。 +5. 使用命令模式来封装各种交互操作,如发射导弹、激活干扰设备等。 + +这种组合架构允许我们灵活地处理复杂的交互关系,同时保持代码的可维护性和可扩展性。 + +## 下一步计划 + +- 实现核心实体(导弹、坦克、告警设备、干扰设备)的基本功能。 +- 设计并实现事件系统,处理实体间的交互。 +- 开发状态机,管理导弹的飞行阶段。 +- 实现观察者模式,处理告警通知。 +- 使用命令模式封装关键操作。 +- 进行单元测试和集成测试,确保系统的正确性和稳定性。 diff --git a/Models/LaserDesignator.cs b/Models/LaserDesignator.cs index dce516b..06b894b 100644 --- a/Models/LaserDesignator.cs +++ b/Models/LaserDesignator.cs @@ -1,56 +1,140 @@ using ActiveProtect.SimulationEnvironment; +using System; namespace ActiveProtect.Models { - public class LaserDesignator(string id, LaserDesignatorConfig laserDesignatorConfig, ISimulationManager simulationManager) : SimulationElement(id, laserDesignatorConfig.InitialPosition, new Orientation(), simulationManager) + public class LaserDesignator : SimulationElement { - public string TargetId { get; private set; } = laserDesignatorConfig.TargetId; - public bool IsActive { get; private set; } = true; - private const double MaxIlluminationRange = 1000; // 1公里,单位:米 + public string TargetId { get; private set; } + public bool IsActive { get; private set; } + public double JammingThreshold { get; private set; } = 0.0; // 将阈值调整为 0 dB + public bool IsJammed { get; private set; } = false; + public double MaxIlluminationRange { get; private set; } - public void ActivateLaser() + public LaserDesignator(string id, LaserDesignatorConfig config, ISimulationManager simulationManager) + : base(id, config.InitialPosition, new Orientation(), simulationManager) { + TargetId = config.TargetId; IsActive = true; - } - - public void DeactivateLaser() - { - IsActive = false; + MaxIlluminationRange = config.MaxIlluminationRange; + simulationManager.SubscribeToEvent(OnLaserJamming); } public override void Update(double deltaTime) { - - if (IsActive) + if (IsActive && !IsJammed) { IlluminateTarget(); } + else + { + StopIllumination(); + } } private void IlluminateTarget() { - var target = SimulationManager.GetEntityById(TargetId) as ILaserIlluminatable; - if (target != null) + if (SimulationManager.GetEntityById(TargetId) is ILaserIlluminatable target) { double distanceToTarget = Vector3D.Distance(Position, target.Position); if (distanceToTarget <= MaxIlluminationRange) { target.Illuminate(); + Console.WriteLine($"激光目标指示器 {Id} 正在照射目标 {TargetId}"); + + // 发布LaserIlluminationEvent + PublishEvent(new LaserIlluminationEvent + { + TargetId = TargetId + }); } else { - target.StopIllumination(); + StopIllumination(); + Console.WriteLine($"激光目标指示器 {Id} 超出照射范围,停止照射目标 {TargetId}"); } } } + private void StopIllumination() + { + if (SimulationManager.GetEntityById(TargetId) is ILaserIlluminatable target) + { + target.StopIllumination(); + Console.WriteLine($"激光目标指示器 {Id} 停止照射目标 {TargetId}"); + PublishIlluminationStopEvent(); + } + } + + private void OnLaserJamming(LaserJammingEvent evt) + { + if (evt.TargetId == TargetId) + { + if (SimulationManager.GetEntityById(TargetId) is Tank target) + { + double distanceToTarget = Vector3D.Distance(Position, target.Position); + + // 调整干扰效果计算方法 + double jammingEffectiveness = 20 * Math.Log10(evt.JammingPower) - 20 * Math.Log10(distanceToTarget) - 20 * Math.Log10(4 * Math.PI); + + Console.WriteLine($"激光目标指示器 {Id} 收到干扰事件,干扰功率: {evt.JammingPower:F2}, 距离: {distanceToTarget:F2}, 干扰效果: {jammingEffectiveness:F2} dB, 阈值: {JammingThreshold:F2} dB"); + + if (jammingEffectiveness > JammingThreshold) + { + if (!IsJammed) + { + Console.WriteLine($"激光目标指示器 {Id} 被干扰,停止工作"); + IsJammed = true; + DeactivateLaser(); + } + } + else + { + if (IsJammed) + { + Console.WriteLine($"激光目标指示器 {Id} 干扰解除,恢复工作"); + IsJammed = false; + ActivateLaser(); + } + } + } + } + } + + public void ActivateLaser() + { + IsActive = true; + IsJammed = false; + Console.WriteLine($"激光目标指示器 {Id} 已激活"); + IlluminateTarget(); // 立即开始照射目标 + } + + public void DeactivateLaser() + { + if (IsActive) + { + IsActive = false; + StopIllumination(); + Console.WriteLine($"激光目标指示器 {Id} 已停用"); + } + } + + private void PublishIlluminationStopEvent() + { + PublishEvent(new LaserIlluminationStopEvent + { + TargetId = TargetId + }); + } + public override string GetStatus() { return $"激光目标指示器 {Id}:\n" + $" 位置: {Position}\n" + $" 目标: {TargetId}\n" + - $" 激活状态: {(IsActive ? "激活" : "未激活")}"; + $" 激活状态: {(IsActive ? "激活" : "未激活")}\n" + + $" 干扰状态: {(IsJammed ? "被干扰" : "正常")}\n" + + $" 最大照射范围: {MaxIlluminationRange}"; } } - } \ No newline at end of file diff --git a/Models/LaserJammer.cs b/Models/LaserJammer.cs new file mode 100644 index 0000000..88953d5 --- /dev/null +++ b/Models/LaserJammer.cs @@ -0,0 +1,74 @@ +using System; +using ActiveProtect.SimulationEnvironment; + +namespace ActiveProtect.Models +{ + public class LaserJammer + { + private readonly Tank tank; + public bool IsJamming { get; private set; } + public double JammingPower { get; private set; } + private double jammingCooldown = 0; + private const double MaxJammingCooldown = 5.0; + private const double MaxJammingPower = 10000.0; // 降低最大干扰功率 + private const double InitialJammingPower = 4000.0; // 设置初始干扰功率 + private const double PowerIncreaseRate = 2000.0; // 每秒增加的功率 + + public LaserJammer(Tank tank) + { + this.tank = tank; + IsJamming = false; + JammingPower = 0; + tank.SimulationManager.SubscribeToEvent(OnLaserIlluminationStop); + } + + public void Update(double deltaTime) + { + if (IsJamming) + { + // 逐渐增加干扰功率 + JammingPower = Math.Min(JammingPower + PowerIncreaseRate * deltaTime, MaxJammingPower); + + jammingCooldown += deltaTime; + if (jammingCooldown >= MaxJammingCooldown) + { + StopJamming(); + } + + Console.WriteLine($"坦克 {tank.Id} 的激光干扰器正在工作,当前功率: {JammingPower:F2}"); + } + else if (tank.LaserWarner.IsAlarming) + { + StartJamming(); + } + } + + private void StartJamming() + { + IsJamming = true; + JammingPower = InitialJammingPower; // 从初始功率开始 + jammingCooldown = 0; + Console.WriteLine($"坦克 {tank.Id} 的激光干扰器开始工作,初始功率: {JammingPower:F2}"); + } + + private void StopJamming() + { + if (IsJamming) + { + IsJamming = false; + JammingPower = 0; + jammingCooldown = 0; + Console.WriteLine($"坦克 {tank.Id} 的激光干扰器停止工作"); + } + } + + private void OnLaserIlluminationStop(LaserIlluminationStopEvent evt) + { + if (evt.TargetId == tank.Id) + { + Console.WriteLine($"坦克 {tank.Id} 接收到激光照射停止事件,停止干扰"); + StopJamming(); + } + } + } +} \ No newline at end of file diff --git a/Models/LaserSemiActiveGuidedMissile.cs b/Models/LaserSemiActiveGuidedMissile.cs index ebed8b9..5865420 100644 --- a/Models/LaserSemiActiveGuidedMissile.cs +++ b/Models/LaserSemiActiveGuidedMissile.cs @@ -1,15 +1,13 @@ using ActiveProtect.SimulationEnvironment; +using System; namespace ActiveProtect.Models { public class LaserSemiActiveGuidedMissile : Missile { - // 添加新的属性 public bool IsLaserDetected { get; private set; } = false; - private const double LaserLockDistance = 1000; // 1公里,单位:米 - - // 激光半主动制导导弹的特殊属性 public bool IsLaserLocked { get; private set; } = false; + private const double LaserLockDistance = 1000; // 1公里,单位:米 public LaserSemiActiveGuidedMissile( string id, @@ -23,18 +21,20 @@ namespace ActiveProtect.Models public override void Update(double deltaTime) { base.Update(deltaTime); - - // 更新激光检测和锁定逻辑 UpdateLaserDetection(); if (IsLaserDetected) { UpdateLaserLock(); + IsGuidanceLost = false; + } + else + { + LoseGuidance(); } } private void UpdateLaserDetection() { - // 检查是否有激光照射目标 var target = SimulationManager.GetEntityById(TargetId) as ILaserIlluminatable; if (target != null) { @@ -48,13 +48,10 @@ namespace ActiveProtect.Models private void UpdateLaserLock() { - // 如果检测到激光,则锁定目标 IsLaserLocked = IsLaserDetected; if (IsLaserLocked) { - // 根据激光照射的光斑进行导引 - // 这里可以添加更精确的导引逻辑 AdjustTrajectoryBasedOnLaserGuidance(); } } @@ -62,14 +59,25 @@ namespace ActiveProtect.Models private void AdjustTrajectoryBasedOnLaserGuidance() { // 实现基于激光导引的轨迹调整 - // 这里可以添加更复杂的导引算法 + // 这里可以添加更精确的导引逻辑 + } + + protected override void LoseGuidance() + { + if (!IsLaserDetected) + { + base.LoseGuidance(); + IsLaserLocked = false; + Console.WriteLine($"激光半主动制导导弹 {Id} 失去激光引导"); + } } public override string GetStatus() { - return base.GetStatus().Replace("导弹", "激光半主动制导导弹") + - $"\n 激光检测: {(IsLaserDetected ? "是" : "否")}" + - $"\n 激光锁定: {(IsLaserLocked ? "是" : "否")}"; + string baseStatus = base.GetStatus().Replace("导弹", "激光半主动制导导弹"); + string additionalStatus = $"\n 激光检测: {(IsLaserDetected ? "是" : "否")}" + + $"\n 激光锁定: {(IsLaserLocked ? "是" : "否")}"; + return baseStatus + additionalStatus; } } } diff --git a/Models/LaserWarner.cs b/Models/LaserWarner.cs new file mode 100644 index 0000000..f63de96 --- /dev/null +++ b/Models/LaserWarner.cs @@ -0,0 +1,69 @@ +using ActiveProtect.SimulationEnvironment; +using System; + +namespace ActiveProtect.Models +{ + public class LaserWarner + { + private readonly Tank tank; + public bool IsAlarming { get; private set; } + private double alarmDuration = 5.0; // 警报持续5秒 + private double alarmTimer = 0; + + public LaserWarner(Tank tank) + { + this.tank = tank; + IsAlarming = false; + tank.SimulationManager.SubscribeToEvent(OnLaserIllumination); + tank.SimulationManager.SubscribeToEvent(OnLaserIlluminationStop); + } + + public void Update(double deltaTime) + { + if (IsAlarming) + { + alarmTimer += deltaTime; + if (alarmTimer >= alarmDuration) + { + StopAlarm(); + } + } + } + + private void OnLaserIllumination(LaserIlluminationEvent evt) + { + if (evt.TargetId == tank.Id) + { + TriggerAlarm(); + } + } + + private void OnLaserIlluminationStop(LaserIlluminationStopEvent evt) + { + if (evt.TargetId == tank.Id) + { + StopAlarm(); + } + } + + public void TriggerAlarm() + { + if (!IsAlarming) + { + IsAlarming = true; + alarmTimer = 0; + Console.WriteLine($"坦克 {tank.Id} 的激光告警器发出警报!"); + } + } + + public void StopAlarm() + { + if (IsAlarming) + { + IsAlarming = false; + alarmTimer = 0; + Console.WriteLine($"坦克 {tank.Id} 的激光告警器停止警报"); + } + } + } +} \ No newline at end of file diff --git a/Models/Missile.cs b/Models/Missile.cs index e6a95f0..3862fa9 100644 --- a/Models/Missile.cs +++ b/Models/Missile.cs @@ -26,41 +26,7 @@ namespace ActiveProtect.Models Explosion // 爆炸阶段 } - /// - /// 导弹飞行阶段的配置结构 - /// - /// - /// 初始化飞行阶段配置 - /// - public struct FlightStageConfig(bool enableLaunch = true, bool enableAcceleration = true, bool enableCruise = true, - bool enableTerminalGuidance = true, bool enableAttack = true) - { - public bool EnableLaunch = enableLaunch; - public bool EnableAcceleration = enableAcceleration; - public bool EnableCruise = enableCruise; - public bool EnableTerminalGuidance = enableTerminalGuidance; - public bool EnableAttack = enableAttack; - - /// - /// 标准导弹的预设配置, 所有阶段都启用 - /// - public static FlightStageConfig StandardMissile => new(enableLaunch: true, enableAcceleration: true, enableCruise: true, enableTerminalGuidance: true, enableAttack: true); - - /// - /// 激光制导炮弹的预设配置, 没有加速阶段 - /// - public static FlightStageConfig LaserGuidedShell => new(enableAcceleration: false); - - /// - /// 短程导弹的预设配置,没有巡航阶段 - /// - public static FlightStageConfig ShortRangeMissile => new(enableCruise: false); - - /// - /// 激光半主动制导导弹的预设配置, 没有加速阶段 - /// - public static FlightStageConfig LaserSemiActiveGuidedMissile => new(enableAcceleration: false); - } + public double Speed { get; protected set; } public double MaxSpeed { get; protected set; } @@ -87,6 +53,10 @@ namespace ActiveProtect.Models public double ProportionalNavigationCoefficient { get; set; } + public bool IsGuidanceLost { get; protected set; } = false; + protected double LostGuidanceTime { get; set; } = 0; + protected const double MaxLostGuidanceTime = 1.0; // 1秒后自毁 + public Missile(string id, MissileConfig missileConfig, ISimulationManager simulationManager) : base(id, missileConfig.InitialPosition, missileConfig.InitialOrientation, simulationManager) { @@ -119,6 +89,10 @@ namespace ActiveProtect.Models Console.WriteLine($"导弹 {Id} 的初始阶: {CurrentStage}"); LastTargetPosition = Position; // 初始化 LastTargetPosition + + // 订阅相关事件 + simulationManager.SubscribeToEvent(OnLaserIllumination); + simulationManager.SubscribeToEvent(OnLaserIlluminationStop); } public override void Update(double deltaTime) @@ -152,7 +126,7 @@ namespace ActiveProtect.Models FlightTime += deltaTime; FlightDistance += Speed * deltaTime; - UpdateDistanceToTarget(Vector3D.Distance(Position, SimulationManager.GetElementPosition(TargetId))); + UpdateDistanceToTarget(Vector3D.Distance(Position, SimulationManager.GetEntityById(TargetId).Position)); // 首先检查是否命中目标 if (CheckHit()) @@ -170,6 +144,22 @@ namespace ActiveProtect.Models // 更新飞行阶段 UpdateFlightStage(); + + if (IsGuidanceLost) + { + HandleLostGuidance(deltaTime); + } + else + { + // 重置失去引导的时间 + LostGuidanceTime = 0; + } + + // 发布事件示例 + if (CurrentStage == FlightStage.Launch) + { + PublishEvent(new MissileFireEvent { TargetId = TargetId }); + } } private bool CheckHit() @@ -192,7 +182,7 @@ namespace ActiveProtect.Models private (Vector3D, Vector3D) CalculateDerivatives(Vector3D position, Vector3D velocity, double deltaTime) { - Vector3D targetPosition = SimulationManager.GetElementPosition(TargetId); + Vector3D targetPosition = SimulationManager.GetEntityById(TargetId).Position; Vector3D LOS = targetPosition - position; Vector3D LOSRate = (targetPosition - LastTargetPosition) / deltaTime - velocity; Vector3D guidanceAcceleration = Vector3D.CrossProduct(Vector3D.CrossProduct(LOS, LOSRate), LOS).Normalize() @@ -266,6 +256,7 @@ namespace ActiveProtect.Models public void Explode() { IsActive = false; + SimulationManager.HandleTargetHit(TargetId, Id); Console.WriteLine($"导弹 {Id} 在 {Position} 爆炸,命中目标!"); } @@ -273,8 +264,9 @@ namespace ActiveProtect.Models { IsActive = false; string reason = FlightTime >= MaxFlightTime ? "超出最大飞行时间" : - FlightDistance >= MaxFlightDistance ? "超出最大飞行距���" : - Position.Y <= 0 ? "高度小于等于0" : "未知原因"; + FlightDistance >= MaxFlightDistance ? "超出最大飞行距" : + Position.Y <= 0 ? "高度小于等于0" : + IsGuidanceLost ? "失去引导" : "未知原因"; Console.WriteLine($"导弹 {Id} 自毁。原因: {reason}"); } @@ -288,7 +280,9 @@ namespace ActiveProtect.Models $" 飞行时间: {FlightTime:F2}/{MaxFlightTime:F2}\n" + $" 飞行距离: {FlightDistance:F2}/{MaxFlightDistance:F2}\n" + $" 距离目标: {DistanceToTarget:F2}\n" + - $" 发动机工作时间: {EngineBurnTime:F2}/{MaxEngineBurnTime:F2}"; + $" 发动机工作时间: {EngineBurnTime:F2}/{MaxEngineBurnTime:F2}\n" + + $" 失去引导: {(IsGuidanceLost ? "是" : "否")}\n" + + $" 失去引导时间: {LostGuidanceTime:F2}/{MaxLostGuidanceTime:F2}"; } public void SetProportionalNavigationCoefficient(double newCoefficient) @@ -296,6 +290,53 @@ namespace ActiveProtect.Models ProportionalNavigationCoefficient = newCoefficient; Console.WriteLine($"导弹 {Id} 的比例导引系数已更新为 {newCoefficient}"); } + + protected virtual void LoseGuidance() + { + if (!IsGuidanceLost) + { + Console.WriteLine($"导弹 {Id} 失去引导"); + IsGuidanceLost = true; + } + } + + protected virtual void HandleLostGuidance(double deltaTime) + { + LostGuidanceTime += deltaTime; + if (LostGuidanceTime >= MaxLostGuidanceTime) + { + Console.WriteLine($"导弹 {Id} 失去引导超过 {MaxLostGuidanceTime} 秒,自毁"); + SelfDestruct(); + } + } + + private void OnLaserIllumination(LaserIlluminationEvent evt) + { + if (evt.TargetId == TargetId) + { + Console.WriteLine($"导弹 {Id} 检测到目标 {TargetId} 被激光照射"); + RegainGuidance(); + } + } + + private void OnLaserIlluminationStop(LaserIlluminationStopEvent evt) + { + if (evt.TargetId == TargetId) + { + Console.WriteLine($"导弹 {Id} 检测到目标 {TargetId} 激光照射停止"); + LoseGuidance(); + } + } + + protected virtual void RegainGuidance() + { + if (IsGuidanceLost) + { + Console.WriteLine($"导弹 {Id} 重新获得引导"); + IsGuidanceLost = false; + LostGuidanceTime = 0; + } + } } } \ No newline at end of file diff --git a/Models/Tank.cs b/Models/Tank.cs index 809c0f9..7f8a13e 100644 --- a/Models/Tank.cs +++ b/Models/Tank.cs @@ -1,39 +1,70 @@ using ActiveProtect.SimulationEnvironment; +using System; namespace ActiveProtect.Models { public class Tank : SimulationElement, ILaserIlluminatable { public double Speed { get; set; } = 0; - public bool IsActive { get; private set; } = false; - public double MaxSpeed { get; private set; } = 0; - public double MaxArmor { get; private set; } = 0; - public double Armor { get; private set; } = 0; - public double CurrentArmor { get; private set; } = 0; + public bool IsActive { get; private set; } = true; + public double MaxSpeed { get; private set; } + public double MaxArmor { get; private set; } + public double CurrentArmor { get; private set; } public bool IsIlluminated { get; private set; } = false; + public LaserWarner LaserWarner { get; private set; } + public LaserJammer LaserJammer { get; private set; } public Tank(string id, TankConfig tankConfig, ISimulationManager simulationManager) : base(id, tankConfig.InitialPosition, tankConfig.InitialOrientation, simulationManager) { - Position = tankConfig.InitialPosition; - Orientation = tankConfig.InitialOrientation; Speed = tankConfig.InitialSpeed; - IsActive = true; MaxSpeed = tankConfig.MaxSpeed; MaxArmor = tankConfig.MaxArmor; - Armor = tankConfig.MaxArmor; CurrentArmor = tankConfig.MaxArmor; - IsIlluminated = false; - SimulationManager = simulationManager; + LaserWarner = new LaserWarner(this); + LaserJammer = new LaserJammer(this); + + // 移除事件订阅,因为现在由LaserWarner直接处理 } - public void TakeDamage(double damage) + public override void Update(double deltaTime) { - CurrentArmor -= damage; + if (!IsActive) return; + + UpdatePosition(deltaTime); + LaserWarner.Update(deltaTime); + LaserJammer.Update(deltaTime); + + // 如果激光干扰器正在工作,发布LaserJammingEvent + if (LaserJammer.IsJamming) + { + PublishEvent(new LaserJammingEvent + { + TargetId = Id, + JammingPower = LaserJammer.JammingPower + }); + } + } + + private void UpdatePosition(double deltaTime) + { + Vector3D direction = Orientation.ToVector(); + Vector3D movement = direction * Speed * deltaTime; + Position += movement; + } + + public void TakeDamage(double damage, bool isMissileDamage = false) + { + if (isMissileDamage) + { + damage = CurrentArmor * 0.5; + } + + CurrentArmor = Math.Max(0, CurrentArmor - damage); if (CurrentArmor <= 0) { - CurrentArmor = 0; IsActive = false; + PublishEvent(new EntityDestroyedEvent { DestroyedEntityId = Id }); } } @@ -47,49 +78,18 @@ namespace ActiveProtect.Models IsIlluminated = false; } - public override void Update(double deltaTime) - { - // 移除对基类抽象方法的调用 - // 实现坦克特定的更新逻辑 - UpdatePosition(deltaTime); - UpdateArmor(); - CheckIlluminationStatus(); - } - - private void UpdatePosition(double deltaTime) - { - // 根据速度更新坦克位置 - Vector3D direction = Orientation.ToVector(); - Vector3D movement = direction * Speed * deltaTime; - Position += movement; - } - - private void UpdateArmor() - { - // 可能的装甲恢复逻辑 - if (CurrentArmor < MaxArmor) - { - CurrentArmor = Math.Min(CurrentArmor + 10, MaxArmor); - } - } - - private void CheckIlluminationStatus() - { - // 检查激光照射状态,可能会影响坦克的其他属性 - if (IsIlluminated) - { - // 实现被激光照射时的效果 - } - } + // 移除OnLaserIllumination和OnLaserIlluminationStop方法,因为现在由LaserWarner直接处理 public override string GetStatus() { - return base.GetStatus() + - $"\n 速度: {Speed}" + - $"\n 最大速度: {MaxSpeed}" + - $"\n 装甲: {CurrentArmor}/{MaxArmor}" + - $"\n 状态: {(IsActive ? "活动" : "已销毁")}" + - $"\n 激光照射: {(IsIlluminated ? "是" : "否")}"; + return $"坦克 {Id}:\n" + + $" 位置: {Position}\n" + + $" 速度: {Speed:F2}/{MaxSpeed:F2}\n" + + $" 装甲: {CurrentArmor:F2}/{MaxArmor:F2}\n" + + $" 状态: {(IsActive ? "活动" : "已销毁")}\n" + + $" 激光照射: {(IsIlluminated ? "是" : "否")}\n" + + $" 激光报警: {(LaserWarner.IsAlarming ? "警报中" : "正常")}\n" + + $" 激光干扰: {(LaserJammer.IsJamming ? $"干扰中 (功率: {LaserJammer.JammingPower:F2})" : "未干扰")}"; } } } \ No newline at end of file diff --git a/Program.cs b/Program.cs index d72efbe..5247af4 100644 --- a/Program.cs +++ b/Program.cs @@ -37,7 +37,7 @@ namespace ActiveProtect MaxEngineBurnTime = 5, MaxAcceleration = 100, ProportionalNavigationCoefficient = 3, - StageConfig = Missile.FlightStageConfig.StandardMissile, + StageConfig = FlightStageConfig.StandardMissile, DistanceParams = new MissileDistanceParams(500, 100, 20), Type = MissileType.StandardMissile }, @@ -54,7 +54,7 @@ namespace ActiveProtect MaxEngineBurnTime = 5, MaxAcceleration = 100, ProportionalNavigationCoefficient = 3, - StageConfig = Missile.FlightStageConfig.LaserGuidedShell, + StageConfig = FlightStageConfig.LaserGuidedShell, DistanceParams = new MissileDistanceParams(300, 100, 20), Type = MissileType.InfraredCommandGuidance }, @@ -71,13 +71,13 @@ namespace ActiveProtect MaxEngineBurnTime = 5, MaxAcceleration = 100, ProportionalNavigationCoefficient = 3, - StageConfig = Missile.FlightStageConfig.ShortRangeMissile, + StageConfig = FlightStageConfig.ShortRangeMissile, DistanceParams = new MissileDistanceParams(400, 100, 20), Type = MissileType.MillimeterWaveTerminalGuidance }, // 新增激光半主动制导导弹配置 new() { - InitialPosition = new Vector3D(1500, 150, 100), + InitialPosition = new Vector3D(2000, 150, 100), InitialOrientation = new Orientation(Math.PI, -0.12, 0), InitialSpeed = 700, MaxSpeed = 800, @@ -88,7 +88,7 @@ namespace ActiveProtect MaxEngineBurnTime = 5, MaxAcceleration = 100, ProportionalNavigationCoefficient = 3, - StageConfig = Missile.FlightStageConfig.LaserSemiActiveGuidedMissile, + StageConfig = FlightStageConfig.LaserSemiActiveGuidedMissile, DistanceParams = new MissileDistanceParams(500, 200, 20), Type = MissileType.SemiActiveLaserGuidance } @@ -97,8 +97,9 @@ namespace ActiveProtect [ new LaserDesignatorConfig { - InitialPosition = new Vector3D(500, 50, 100), - TargetId = "Tank_1" + InitialPosition = new Vector3D(500, 150, 100), + TargetId = "Tank_1", + MaxIlluminationRange = 1000 } ], SimulationTimeStep = 0.05 @@ -108,11 +109,14 @@ namespace ActiveProtect var simulationManager = new SimulationManager(config); // 运行仿真 - while (!simulationManager.IsSimulationEnded) + int maxIterations = 1000; // 增加最大迭代次数 + int iteration = 0; + while (!simulationManager.IsSimulationEnded && iteration < maxIterations) { simulationManager.Update(); simulationManager.PrintStatus(); Thread.Sleep(100); // 暂停100毫秒,使输出更易读 + iteration++; } Console.WriteLine("仿真结束"); diff --git a/SimulationEnvironment/ISimulatinManager.cs b/SimulationEnvironment/ISimulatinManager.cs deleted file mode 100644 index a79181a..0000000 --- a/SimulationEnvironment/ISimulatinManager.cs +++ /dev/null @@ -1,12 +0,0 @@ -using ActiveProtect.Models; -using ActiveProtect.SimulationEnvironment; - -namespace ActiveProtect.SimulationEnvironment -{ - public interface ISimulationManager - { - Vector3D GetElementPosition(string elementId); - - SimulationElement GetEntityById(string id); - } -} \ No newline at end of file diff --git a/SimulationEnvironment/SimulationConfig.cs b/SimulationEnvironment/SimulationConfig.cs index 19e7165..fdaf0ff 100644 --- a/SimulationEnvironment/SimulationConfig.cs +++ b/SimulationEnvironment/SimulationConfig.cs @@ -44,7 +44,7 @@ namespace ActiveProtect.SimulationEnvironment public double MaxFlightDistance { get; set; } public double MaxAcceleration { get; set; } public double ProportionalNavigationCoefficient { get; set; } - public Missile.FlightStageConfig StageConfig { get; set; } + public FlightStageConfig StageConfig { get; set; } public MissileDistanceParams DistanceParams { get; set; } public double ThrustAcceleration { get; set; } public double MaxEngineBurnTime { get; set; } @@ -60,7 +60,7 @@ namespace ActiveProtect.SimulationEnvironment TargetIndex = 0; // 目标索引 MaxFlightTime = 0; // 最大飞行时间 MaxFlightDistance = 0; // 最大飞行距离 - StageConfig = Missile.FlightStageConfig.StandardMissile; // 飞行阶段配置 + StageConfig = FlightStageConfig.StandardMissile; // 飞行阶段配置 ThrustAcceleration = 0; // 推力加速度 MaxEngineBurnTime = 0; // 最大发动机燃烧时间 MaxAcceleration = 0; // 最大加速度 @@ -74,11 +74,12 @@ namespace ActiveProtect.SimulationEnvironment { public Vector3D InitialPosition { get; set; } public string TargetId { get; set; } - + public double MaxIlluminationRange { get; set; } public LaserDesignatorConfig() { InitialPosition = new Vector3D(0, 0, 0); TargetId = ""; + MaxIlluminationRange = 1000; } } @@ -88,4 +89,40 @@ namespace ActiveProtect.SimulationEnvironment public double AttackDistance { get; set; } = attackDistance; public double ExplosionDistance { get; set; } = explosionDistance; } + + /// + /// 导弹飞行阶段的配置结构 + /// + /// + /// 初始化飞行阶段配置 + /// + public struct FlightStageConfig(bool enableLaunch = true, bool enableAcceleration = true, bool enableCruise = true, + bool enableTerminalGuidance = true, bool enableAttack = true) + { + public bool EnableLaunch = enableLaunch; + public bool EnableAcceleration = enableAcceleration; + public bool EnableCruise = enableCruise; + public bool EnableTerminalGuidance = enableTerminalGuidance; + public bool EnableAttack = enableAttack; + + /// + /// 标准导弹的预设配置, 所有阶段都启用 + /// + public static FlightStageConfig StandardMissile => new(enableLaunch: true, enableAcceleration: true, enableCruise: true, enableTerminalGuidance: true, enableAttack: true); + + /// + /// 激光制导炮弹的预设配置, 没有加速阶段 + /// + public static FlightStageConfig LaserGuidedShell => new(enableAcceleration: false); + + /// + /// 短程导弹的预设配置,没有巡航阶段 + /// + public static FlightStageConfig ShortRangeMissile => new(enableCruise: false); + + /// + /// 激光半主动制导导弹的预设配置, 没有加速阶段 + /// + public static FlightStageConfig LaserSemiActiveGuidedMissile => new(enableAcceleration: false); + } } diff --git a/SimulationEnvironment/SimulationElement.cs b/SimulationEnvironment/SimulationElement.cs index 9a3e92f..1bcd14e 100644 --- a/SimulationEnvironment/SimulationElement.cs +++ b/SimulationEnvironment/SimulationElement.cs @@ -15,5 +15,12 @@ namespace ActiveProtect.SimulationEnvironment { return $"{GetType().Name} {Id} at {Position}, Orientation: {Orientation}"; } + + protected void PublishEvent(SimulationEvent evt) + { + evt.SenderId = Id; + evt.Timestamp = SimulationManager.CurrentTime; + SimulationManager.PublishEvent(evt); + } } } diff --git a/SimulationEnvironment/SimulationEvents.cs b/SimulationEnvironment/SimulationEvents.cs new file mode 100644 index 0000000..a28eb22 --- /dev/null +++ b/SimulationEnvironment/SimulationEvents.cs @@ -0,0 +1,34 @@ +namespace ActiveProtect.SimulationEnvironment +{ + public class SimulationEvent + { + public string? SenderId { get; set; } + public double Timestamp { get; set; } + } + + public class MissileFireEvent : SimulationEvent + { + public string? TargetId { get; set; } + } + + public class LaserIlluminationEvent : SimulationEvent + { + public string? TargetId { get; set; } + } + + public class LaserJammingEvent : SimulationEvent + { + public string? TargetId { get; set; } + public double JammingPower { get; set; } + } + + public class EntityDestroyedEvent : SimulationEvent + { + public string? DestroyedEntityId { get; set; } + } + + public class LaserIlluminationStopEvent : SimulationEvent + { + public string? TargetId { get; set; } + } +} \ No newline at end of file diff --git a/SimulationEnvironment/SimulationManager.cs b/SimulationEnvironment/SimulationManager.cs index 7f1ccc8..87804c5 100644 --- a/SimulationEnvironment/SimulationManager.cs +++ b/SimulationEnvironment/SimulationManager.cs @@ -5,12 +5,25 @@ using ActiveProtect.Models; namespace ActiveProtect.SimulationEnvironment { + public interface ISimulationManager + { + double CurrentTime { get; } + + SimulationElement GetEntityById(string id); + void HandleTargetHit(string targetId, string missileId); + + void PublishEvent(SimulationEvent evt); + void SubscribeToEvent(Action handler) where T : SimulationEvent; + void UnsubscribeFromEvent(Action handler) where T : SimulationEvent; + } + public class SimulationManager : ISimulationManager { public List Elements { get; private set; } public double CurrentTime { get; private set; } public bool IsSimulationEnded { get; private set; } private readonly SimulationConfig config; + private Dictionary> eventHandlers = new Dictionary>(); public SimulationManager(SimulationConfig config) { @@ -54,7 +67,40 @@ namespace ActiveProtect.SimulationEnvironment for (int i = 0; i < config.LaserDesignatorConfigs.Count; i++) { var laserDesignatorConfig = config.LaserDesignatorConfigs[i]; - Elements.Add(new LaserDesignator($"LD_{i + 1}", laserDesignatorConfig, this)); + var laserDesignator = new LaserDesignator($"LD_{i + 1}", laserDesignatorConfig, this); + Elements.Add(laserDesignator); + laserDesignator.ActivateLaser(); // 激活激光目标指示器 + } + } + + public void PublishEvent(SimulationEvent evt) + { + var eventType = evt.GetType(); + if (eventHandlers.TryGetValue(eventType, out var handlers)) + { + foreach (var handler in handlers) + { + handler.DynamicInvoke(evt); + } + } + } + + public void SubscribeToEvent(Action handler) where T : SimulationEvent + { + var eventType = typeof(T); + if (!eventHandlers.ContainsKey(eventType)) + { + eventHandlers[eventType] = new List(); + } + eventHandlers[eventType].Add(handler); + } + + public void UnsubscribeFromEvent(Action handler) where T : SimulationEvent + { + var eventType = typeof(T); + if (eventHandlers.ContainsKey(eventType)) + { + eventHandlers[eventType].Remove(handler); } } @@ -97,19 +143,44 @@ namespace ActiveProtect.SimulationEnvironment Console.WriteLine($"剩余坦克数量: {Elements.Count(e => e is Tank)}"); } - public Vector3D GetElementPosition(string elementId) - { - var element = Elements.FirstOrDefault(e => e.Id == elementId); - if (element != null) - { - return element.Position; - } - throw new ArgumentException($"Element with id {elementId} not found"); - } - public SimulationElement GetEntityById(string id) { return Elements.FirstOrDefault(e => e.Id == id) ?? throw new InvalidOperationException($"Entity with id {id} not found"); } + + public void HandleTargetHit(string targetId, string missileId) + { + if (GetEntityById(targetId) is Tank tank && GetEntityById(missileId) is Missile missile) + { + // 计算导弹造成的伤害 + double damage = CalculateMissileDamage(missile); + + // 对坦克造成伤害 + tank.TakeDamage(damage, true); + + // 移除已爆炸的导弹 + RemoveEntity(missileId); + + // 记录击中事件 + LogHitEvent(targetId, missileId, damage); + } + } + + private void RemoveEntity(string missileId) + { + Elements.Remove(GetEntityById(missileId)); + } + + private double CalculateMissileDamage(Missile missile) + { + // 这里可以根据导弹类型、速度等因素计算伤害 + // 现在我们简单地返回一个固定值 + return 100; + } + + private void LogHitEvent(string targetId, string missileId, double damage) + { + Console.WriteLine($"目标 {targetId} 被导弹 {missileId} 击中,造成 {damage} 点伤害"); + } } } \ No newline at end of file