diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000..b438a7f --- /dev/null +++ b/.cursorrules @@ -0,0 +1,52 @@ + 您是 C#、Unity 和可扩展游戏开发的专家。 + + 关键原则 + - 编写清晰、技术性的响应,提供精确的 C# 和 Unity 示例。 + - 尽可能使用 Unity 的内置功能和工具,以充分利用其能力。 + - 优先考虑可读性和可维护性;遵循 C# 编码规范和 Unity 最佳实践。 + - 使用描述性的变量和函数名称;遵循命名约定(例如,公共成员使用 PascalCase,私有成员使用 camelCase)。 + - 以模块化的方式构建项目,使用 Unity 的基于组件的架构,以促进可重用性和关注点分离。 + + C#/Unity + - 对于附加到 GameObject 的脚本组件,使用 MonoBehaviour;对于数据容器和共享资源,优先使用 ScriptableObjects。 + - 利用 Unity 的物理引擎和碰撞检测系统来实现游戏机制和交互。 + - 使用 Unity 的输入系统处理跨多个平台的玩家输入。 + - 利用 Unity 的 UI 系统(Canvas、UI 元素)创建用户界面。 + - 严格遵循组件模式,以实现关注点的清晰分离和模块化。 + - 在 Unity 的单线程环境中,使用协程处理基于时间的操作和异步任务。 + + 错误处理和调试 + - 在适当的地方使用 try-catch 块实现错误处理,特别是对于文件 I/O 和网络操作。 + - 使用 Unity 的 Debug 类进行日志记录和调试(例如,Debug.Log、Debug.LogWarning、Debug.LogError)。 + - 利用 Unity 的分析器和帧调试器识别和解决性能问题。 + - 实现自定义错误消息和调试可视化,以改善开发体验。 + - 使用 Unity 的断言系统(Debug.Assert)在开发过程中捕获逻辑错误。 + + 依赖项 + - Unity 引擎 + - .NET 框架(与您的 Unity 版本兼容的版本) + - Unity 资产商店包(根据特定功能需要) + - 第三方插件(经过仔细审查以确保兼容性和性能) + + Unity 特定指南 + - 使用预制件(Prefabs)创建可重用的游戏对象和 UI 元素。 + - 将游戏逻辑保留在脚本中;使用 Unity 编辑器进行场景组合和初始设置。 + - 利用 Unity 的动画系统(Animator、动画剪辑)进行角色和对象动画。 + - 应用 Unity 的内置光照和后处理效果以增强视觉效果。 + - 使用 Unity 的内置测试框架进行单元测试和集成测试。 + - 利用 Unity 的资源包系统进行高效的资源管理和加载。 + - 使用 Unity 的标签和层系统进行对象分类和碰撞过滤。 + + 性能优化 + - 对于频繁实例化和销毁的对象,使用对象池。 + - 通过批处理材质和使用精灵和 UI 元素的图集来优化绘制调用。 + - 实现细节层次(LOD)系统,以提高复杂 3D 模型的渲染性能。 + - 使用 Unity 的作业系统和 Burst 编译器进行 CPU 密集型操作。 + - 通过使用简化的碰撞网格和调整固定时间步长来优化物理性能。 + + 关键约定 + 1. 遵循 Unity 的基于组件的架构,以实现模块化和可重用的游戏元素。 + 2. 在开发的每个阶段优先考虑性能优化和内存管理。 + 3. 维护清晰和逻辑的项目结构,以增强可读性和资产管理。 + + 请参考 Unity 文档和 C# 编程指南,以获取脚本、游戏架构和性能优化的最佳实践。 diff --git a/Models/LaserDesignator.cs b/Models/LaserDesignator.cs index 06b894b..62f8467 100644 --- a/Models/LaserDesignator.cs +++ b/Models/LaserDesignator.cs @@ -6,54 +6,70 @@ namespace ActiveProtect.Models public class LaserDesignator : SimulationElement { public string TargetId { get; private set; } - public bool IsActive { get; private set; } - public double JammingThreshold { get; private set; } = 0.0; // 将阈值调整为 0 dB + public double JammingThreshold { get; private set; } = 0.0; // 调整干扰阈值 public bool IsJammed { get; private set; } = false; public double MaxIlluminationRange { get; private set; } + private bool IsIlluminating { get; set; } = false; - public LaserDesignator(string id, LaserDesignatorConfig config, ISimulationManager simulationManager) + public LaserDesignator(string id, string targetId, LaserDesignatorConfig config, ISimulationManager simulationManager) : base(id, config.InitialPosition, new Orientation(), simulationManager) { - TargetId = config.TargetId; + TargetId = targetId; IsActive = true; MaxIlluminationRange = config.MaxIlluminationRange; - simulationManager.SubscribeToEvent(OnLaserJamming); + SimulationManager.SubscribeToEvent(OnLaserJamming); } public override void Update(double deltaTime) { if (IsActive && !IsJammed) { - IlluminateTarget(); + UpdateIllumination(); } - else + else if (IsIlluminating) { StopIllumination(); } } - private void IlluminateTarget() + private void UpdateIllumination() { if (SimulationManager.GetEntityById(TargetId) is ILaserIlluminatable target) { double distanceToTarget = Vector3D.Distance(Position, target.Position); - if (distanceToTarget <= MaxIlluminationRange) - { - target.Illuminate(); - Console.WriteLine($"激光目标指示器 {Id} 正在照射目标 {TargetId}"); + bool shouldIlluminate = distanceToTarget <= MaxIlluminationRange; - // 发布LaserIlluminationEvent - PublishEvent(new LaserIlluminationEvent - { - TargetId = TargetId - }); + Console.WriteLine($"激光目标指示器 {Id} 状态更新:"); + Console.WriteLine($" 目标: {TargetId}"); + Console.WriteLine($" 距离目标: {distanceToTarget:F2} m (最大照射范围: {MaxIlluminationRange} m)"); + Console.WriteLine($" 是否应该照射: {shouldIlluminate}"); + Console.WriteLine($" 当前照射状态: {IsIlluminating}"); + + if (shouldIlluminate && !IsIlluminating) + { + StartIllumination(target); } - else + else if (!shouldIlluminate && IsIlluminating) { StopIllumination(); - Console.WriteLine($"激光目标指示器 {Id} 超出照射范围,停止照射目标 {TargetId}"); } } + else + { + Console.WriteLine($"激光目标指示器 {Id} 无法找到目标 {TargetId}"); + if (IsIlluminating) + { + StopIllumination(); + } + } + } + + private void StartIllumination(ILaserIlluminatable target) + { + target.Illuminate(); + IsIlluminating = true; + Console.WriteLine($"激光目标指示器 {Id} 开始照射目标 {TargetId}"); + PublishIlluminationEvent(); } private void StopIllumination() @@ -61,22 +77,22 @@ namespace ActiveProtect.Models if (SimulationManager.GetEntityById(TargetId) is ILaserIlluminatable target) { target.StopIllumination(); - Console.WriteLine($"激光目标指示器 {Id} 停止照射目标 {TargetId}"); - PublishIlluminationStopEvent(); } + IsIlluminating = false; + Console.WriteLine($"激光目标指示器 {Id} 停止照射目标 {TargetId}"); + PublishIlluminationStopEvent(); } private void OnLaserJamming(LaserJammingEvent evt) { if (evt.TargetId == TargetId) { - if (SimulationManager.GetEntityById(TargetId) is Tank target) + var tank = SimulationManager.GetEntityById(TargetId) as Tank; + if (tank != null) { - double distanceToTarget = Vector3D.Distance(Position, target.Position); - - // 调整干扰效果计算方法 + double distanceToTarget = Vector3D.Distance(Position, tank.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) @@ -85,7 +101,7 @@ namespace ActiveProtect.Models { Console.WriteLine($"激光目标指示器 {Id} 被干扰,停止工作"); IsJammed = true; - DeactivateLaser(); + StopIllumination(); } } else @@ -94,7 +110,6 @@ namespace ActiveProtect.Models { Console.WriteLine($"激光目标指示器 {Id} 干扰解除,恢复工作"); IsJammed = false; - ActivateLaser(); } } } @@ -106,7 +121,7 @@ namespace ActiveProtect.Models IsActive = true; IsJammed = false; Console.WriteLine($"激光目标指示器 {Id} 已激活"); - IlluminateTarget(); // 立即开始照射目标 + UpdateIllumination(); } public void DeactivateLaser() @@ -119,6 +134,14 @@ namespace ActiveProtect.Models } } + private void PublishIlluminationEvent() + { + PublishEvent(new LaserIlluminationEvent + { + TargetId = TargetId + }); + } + private void PublishIlluminationStopEvent() { PublishEvent(new LaserIlluminationStopEvent @@ -133,6 +156,7 @@ namespace ActiveProtect.Models $" 位置: {Position}\n" + $" 目标: {TargetId}\n" + $" 激活状态: {(IsActive ? "激活" : "未激活")}\n" + + $" 照射状态: {(IsIlluminating ? "正在照射" : "未照射")}\n" + $" 干扰状态: {(IsJammed ? "被干扰" : "正常")}\n" + $" 最大照射范围: {MaxIlluminationRange}"; } diff --git a/Models/LaserJammer.cs b/Models/LaserJammer.cs index 88953d5..a772620 100644 --- a/Models/LaserJammer.cs +++ b/Models/LaserJammer.cs @@ -3,52 +3,90 @@ using ActiveProtect.SimulationEnvironment; namespace ActiveProtect.Models { - public class LaserJammer + public class LaserJammer : SimulationElement { - 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; // 每秒增加的功率 + private readonly double maxJammingCooldown; + private readonly double maxJammingPower; + private readonly double initialJammingPower; + private readonly double powerIncreaseRate; + public string MonitoredEntityId { get; private set; } - public LaserJammer(Tank tank) + public LaserJammer(string id, Vector3D position, Orientation orientation, ISimulationManager simulationManager, string monitoredEntityId, LaserJammerConfig config) + : base(id, position, orientation, simulationManager) { - this.tank = tank; + MonitoredEntityId = monitoredEntityId; IsJamming = false; JammingPower = 0; - tank.SimulationManager.SubscribeToEvent(OnLaserIlluminationStop); + maxJammingCooldown = config.MaxJammingCooldown; + maxJammingPower = config.MaxJammingPower; + initialJammingPower = config.InitialJammingPower; + powerIncreaseRate = config.PowerIncreaseRate; + SimulationManager.SubscribeToEvent(OnLaserIllumination); + SimulationManager.SubscribeToEvent(OnLaserIlluminationStop); } - public void Update(double deltaTime) + public override void Update(double deltaTime) { + if (!IsActive) return; + + var tank = SimulationManager.GetEntityById(MonitoredEntityId) as Tank; + if (tank != null) + { + Position = tank.Position; + Orientation = tank.Orientation; + } + if (IsJamming) { - // 逐渐增加干扰功率 - JammingPower = Math.Min(JammingPower + PowerIncreaseRate * deltaTime, MaxJammingPower); + JammingPower = Math.Min(JammingPower + powerIncreaseRate * deltaTime, maxJammingPower); jammingCooldown += deltaTime; - if (jammingCooldown >= MaxJammingCooldown) + if (jammingCooldown >= maxJammingCooldown) { StopJamming(); } + else + { + // 发布干扰事件 + PublishEvent(new LaserJammingEvent + { + TargetId = MonitoredEntityId, + JammingPower = JammingPower + }); + } - Console.WriteLine($"坦克 {tank.Id} 的激光干扰器正在工作,当前功率: {JammingPower:F2}"); + Console.WriteLine($"激光干扰器 {Id} 正在工作,当前功率: {JammingPower:F2}"); } - else if (tank.LaserWarner.IsAlarming) + } + + private void OnLaserIllumination(LaserIlluminationEvent evt) + { + if (evt.TargetId == MonitoredEntityId) { StartJamming(); } } + private void OnLaserIlluminationStop(LaserIlluminationStopEvent evt) + { + if (evt.TargetId == MonitoredEntityId) + { + StopJamming(); + } + } + private void StartJamming() { - IsJamming = true; - JammingPower = InitialJammingPower; // 从初始功率开始 - jammingCooldown = 0; - Console.WriteLine($"坦克 {tank.Id} 的激光干扰器开始工作,初始功率: {JammingPower:F2}"); + if (!IsJamming) + { + IsJamming = true; + JammingPower = initialJammingPower; + jammingCooldown = 0; + Console.WriteLine($"激光干扰器 {Id} 开始工作,初始功率: {JammingPower:F2}"); + } } private void StopJamming() @@ -58,17 +96,24 @@ namespace ActiveProtect.Models IsJamming = false; JammingPower = 0; jammingCooldown = 0; - Console.WriteLine($"坦克 {tank.Id} 的激光干扰器停止工作"); + Console.WriteLine($"激光干扰器 {Id} 停止工作"); } } - private void OnLaserIlluminationStop(LaserIlluminationStopEvent evt) + public override string GetStatus() { - if (evt.TargetId == tank.Id) - { - Console.WriteLine($"坦克 {tank.Id} 接收到激光照射停止事件,停止干扰"); - StopJamming(); - } + return $"激光干扰器 {Id}:\n" + + $" 监视实体: {MonitoredEntityId}\n" + + $" 干扰状态: {(IsJamming ? "干扰中" : "未干扰")}\n" + + $" 当前功率: {JammingPower:F2}/{maxJammingPower:F2}\n" + + $" 冷却时间: {jammingCooldown:F2}/{maxJammingCooldown:F2}"; + } + + protected override void Deactivate() + { + base.Deactivate(); + SimulationManager.UnsubscribeFromEvent(OnLaserIllumination); + SimulationManager.UnsubscribeFromEvent(OnLaserIlluminationStop); } } } \ No newline at end of file diff --git a/Models/LaserSemiActiveGuidedMissile.cs b/Models/LaserSemiActiveGuidedMissile.cs index 5865420..ab85613 100644 --- a/Models/LaserSemiActiveGuidedMissile.cs +++ b/Models/LaserSemiActiveGuidedMissile.cs @@ -5,9 +5,7 @@ namespace ActiveProtect.Models { public class LaserSemiActiveGuidedMissile : Missile { - public bool IsLaserDetected { get; private set; } = false; - public bool IsLaserLocked { get; private set; } = false; - private const double LaserLockDistance = 1000; // 1公里,单位:米 + private const double LaserLockDistance = 2000; // 1公里,单位:米 public LaserSemiActiveGuidedMissile( string id, @@ -16,68 +14,67 @@ namespace ActiveProtect.Models : base(id, missileConfig, simulationManager) { Type = MissileType.SemiActiveLaserGuidance; + simulationManager.SubscribeToEvent(OnLaserIllumination); + simulationManager.SubscribeToEvent(OnLaserIlluminationStop); } public override void Update(double deltaTime) { base.Update(deltaTime); - UpdateLaserDetection(); - if (IsLaserDetected) + UpdateGuidanceStatus(); + } + + private void UpdateGuidanceStatus() + { + if (SimulationManager.GetEntityById(TargetId) is ILaserIlluminatable target) { - UpdateLaserLock(); - IsGuidanceLost = false; + bool isIlluminated = target.IsIlluminated; + bool isWithinRange = DistanceToTarget <= LaserLockDistance; + HasGuidance = isIlluminated && isWithinRange; + + Console.WriteLine($"激光半主动制导导弹 {Id} 状态更新:"); + Console.WriteLine($" 目标 {TargetId} 是否被照射: {isIlluminated}"); + Console.WriteLine($" 距离目标: {DistanceToTarget:F2} m (最大锁定距离: {LaserLockDistance} m)"); + Console.WriteLine($" 是否在锁定范围内: {isWithinRange}"); + Console.WriteLine($" 引导状态: {(HasGuidance ? "有效" : "无效")}"); } else { - LoseGuidance(); + HasGuidance = false; + Console.WriteLine($"激光半主动制导导弹 {Id} 无法找到目标 {TargetId}"); } } - private void UpdateLaserDetection() + private void OnLaserIllumination(LaserIlluminationEvent evt) { - var target = SimulationManager.GetEntityById(TargetId) as ILaserIlluminatable; - if (target != null) + if (evt.TargetId == TargetId) { - IsLaserDetected = target.IsIlluminated && DistanceToTarget <= LaserLockDistance; - } - else - { - IsLaserDetected = false; + Console.WriteLine($"激光半主动制导导弹 {Id} 检测到目标 {TargetId} 被激光照射"); + UpdateGuidanceStatus(); } } - private void UpdateLaserLock() + private void OnLaserIlluminationStop(LaserIlluminationStopEvent evt) { - IsLaserLocked = IsLaserDetected; - - if (IsLaserLocked) + if (evt.TargetId == TargetId) { - AdjustTrajectoryBasedOnLaserGuidance(); - } - } - - private void AdjustTrajectoryBasedOnLaserGuidance() - { - // 实现基于激光导引的轨迹调整 - // 这里可以添加更精确的导引逻辑 - } - - protected override void LoseGuidance() - { - if (!IsLaserDetected) - { - base.LoseGuidance(); - IsLaserLocked = false; - Console.WriteLine($"激光半主动制导导弹 {Id} 失去激光引导"); + Console.WriteLine($"激光半主动制导导弹 {Id} 检测到目标 {TargetId} 激光照射停止"); + UpdateGuidanceStatus(); } } public override string GetStatus() { string baseStatus = base.GetStatus().Replace("导弹", "激光半主动制导导弹"); - string additionalStatus = $"\n 激光检测: {(IsLaserDetected ? "是" : "否")}" + - $"\n 激光锁定: {(IsLaserLocked ? "是" : "否")}"; + string additionalStatus = $"\n 激光引导: {(HasGuidance ? "有效" : "无效")}"; return baseStatus + additionalStatus; } + + protected override void Deactivate() + { + base.Deactivate(); + SimulationManager.UnsubscribeFromEvent(OnLaserIllumination); + SimulationManager.UnsubscribeFromEvent(OnLaserIlluminationStop); + } } -} +} \ No newline at end of file diff --git a/Models/LaserWarner.cs b/Models/LaserWarner.cs index f63de96..97b66c0 100644 --- a/Models/LaserWarner.cs +++ b/Models/LaserWarner.cs @@ -3,23 +3,34 @@ using System; namespace ActiveProtect.Models { - public class LaserWarner + public class LaserWarner : SimulationElement { - private readonly Tank tank; public bool IsAlarming { get; private set; } - private double alarmDuration = 5.0; // 警报持续5秒 + private readonly double alarmDuration; private double alarmTimer = 0; + public string MonitoredEntityId { get; private set; } - public LaserWarner(Tank tank) + public LaserWarner(string id, Vector3D position, Orientation orientation, ISimulationManager simulationManager, string monitoredEntityId, LaserWarnerConfig config) + : base(id, position, orientation, simulationManager) { - this.tank = tank; + MonitoredEntityId = monitoredEntityId; IsAlarming = false; - tank.SimulationManager.SubscribeToEvent(OnLaserIllumination); - tank.SimulationManager.SubscribeToEvent(OnLaserIlluminationStop); + alarmDuration = config.AlarmDuration; + SimulationManager.SubscribeToEvent(OnLaserIllumination); + SimulationManager.SubscribeToEvent(OnLaserIlluminationStop); } - public void Update(double deltaTime) + public override void Update(double deltaTime) { + if (!IsActive) return; + + var tank = SimulationManager.GetEntityById(MonitoredEntityId) as Tank; + if (tank != null) + { + Position = tank.Position; + Orientation = tank.Orientation; + } + if (IsAlarming) { alarmTimer += deltaTime; @@ -32,7 +43,7 @@ namespace ActiveProtect.Models private void OnLaserIllumination(LaserIlluminationEvent evt) { - if (evt.TargetId == tank.Id) + if (evt.TargetId == MonitoredEntityId) { TriggerAlarm(); } @@ -40,7 +51,7 @@ namespace ActiveProtect.Models private void OnLaserIlluminationStop(LaserIlluminationStopEvent evt) { - if (evt.TargetId == tank.Id) + if (evt.TargetId == MonitoredEntityId) { StopAlarm(); } @@ -52,7 +63,7 @@ namespace ActiveProtect.Models { IsAlarming = true; alarmTimer = 0; - Console.WriteLine($"坦克 {tank.Id} 的激光告警器发出警报!"); + Console.WriteLine($"激光告警器 {Id} 发出警报!"); } } @@ -62,8 +73,23 @@ namespace ActiveProtect.Models { IsAlarming = false; alarmTimer = 0; - Console.WriteLine($"坦克 {tank.Id} 的激光告警器停止警报"); + Console.WriteLine($"激光告警器 {Id} 停止警报"); } } + + public override string GetStatus() + { + return $"激光告警器 {Id}:\n" + + $" 监视实体: {MonitoredEntityId}\n" + + $" 警报状态: {(IsAlarming ? "警报中" : "正常")}\n" + + $" 警报持续时间: {(IsAlarming ? alarmTimer : 0):F2}/{alarmDuration:F2}"; + } + + protected override void Deactivate() + { + base.Deactivate(); + SimulationManager.UnsubscribeFromEvent(OnLaserIllumination); + SimulationManager.UnsubscribeFromEvent(OnLaserIlluminationStop); + } } } \ No newline at end of file diff --git a/Models/Missile.cs b/Models/Missile.cs index 3862fa9..7f61319 100644 --- a/Models/Missile.cs +++ b/Models/Missile.cs @@ -39,7 +39,6 @@ namespace ActiveProtect.Models public MissileDistanceParams DistanceParams { get; protected set; } public FlightStageConfig StageConfig { get; protected set; } public FlightStage CurrentStage { get; protected set; } - public bool IsActive { get; protected set; } protected Vector3D Velocity; private Vector3D LastTargetPosition; @@ -53,7 +52,7 @@ namespace ActiveProtect.Models public double ProportionalNavigationCoefficient { get; set; } - public bool IsGuidanceLost { get; protected set; } = false; + public bool HasGuidance { get; protected set; } = true; protected double LostGuidanceTime { get; set; } = 0; protected const double MaxLostGuidanceTime = 1.0; // 1秒后自毁 @@ -90,15 +89,19 @@ namespace ActiveProtect.Models LastTargetPosition = Position; // 初始化 LastTargetPosition - // 订阅相关事件 - simulationManager.SubscribeToEvent(OnLaserIllumination); - simulationManager.SubscribeToEvent(OnLaserIlluminationStop); } public override void Update(double deltaTime) { if (!IsActive) return; + // 首先检查是否应该自毁 + if (ShouldSelfDestruct()) + { + SelfDestruct(); + return; + } + // 更新发动机燃烧时间 UpdateEngineBurnTime(deltaTime); @@ -125,33 +128,24 @@ namespace ActiveProtect.Models Orientation = Orientation.FromVector(Velocity); FlightTime += deltaTime; FlightDistance += Speed * deltaTime; + DistanceToTarget = Vector3D.Distance(Position, SimulationManager.GetEntityById(TargetId).Position); - UpdateDistanceToTarget(Vector3D.Distance(Position, SimulationManager.GetEntityById(TargetId).Position)); - - // 首先检查是否命中目标 + // 检查是否命中目标 if (CheckHit()) { Explode(); return; } - // 然后检查是否应该自毁 - if (ShouldSelfDestruct()) - { - SelfDestruct(); - return; - } - // 更新飞行阶段 UpdateFlightStage(); - if (IsGuidanceLost) + if (!HasGuidance) { HandleLostGuidance(deltaTime); } else { - // 重置失去引导的时间 LostGuidanceTime = 0; } @@ -169,7 +163,22 @@ namespace ActiveProtect.Models private bool ShouldSelfDestruct() { - return FlightTime >= MaxFlightTime || FlightDistance >= MaxFlightDistance || Position.Y <= 0; + if (FlightTime >= MaxFlightTime) + { + Console.WriteLine($"导弹 {Id} 超出最大飞行时间 ({FlightTime:F2}/{MaxFlightTime:F2}),准备自毁"); + return true; + } + if (FlightDistance >= MaxFlightDistance) + { + Console.WriteLine($"导弹 {Id} 超出最大飞行距离 ({FlightDistance:F2}/{MaxFlightDistance:F2}),准备自毁"); + return true; + } + if (Position.Y <= 0) + { + Console.WriteLine($"导弹 {Id} 高度小于等于0 ({Position.Y:F2}),准备自毁"); + return true; + } + return false; } private void UpdateEngineBurnTime(double deltaTime) @@ -248,27 +257,25 @@ namespace ActiveProtect.Models } } - public void UpdateDistanceToTarget(double distance) - { - DistanceToTarget = distance; - } - public void Explode() { - IsActive = false; + Deactivate(); SimulationManager.HandleTargetHit(TargetId, Id); Console.WriteLine($"导弹 {Id} 在 {Position} 爆炸,命中目标!"); } public void SelfDestruct() { - IsActive = false; - string reason = FlightTime >= MaxFlightTime ? "超出最大飞行时间" : - FlightDistance >= MaxFlightDistance ? "超出最大飞行距" : - Position.Y <= 0 ? "高度小于等于0" : - IsGuidanceLost ? "失去引导" : "未知原因"; - - Console.WriteLine($"导弹 {Id} 自毁。原因: {reason}"); + if (IsActive) + { + string reason = FlightTime >= MaxFlightTime ? "超出最大飞行时间" : + FlightDistance >= MaxFlightDistance ? "超出最大飞行距离" : + Position.Y <= 0 ? "高度小于等于0" : + !HasGuidance ? "失去引导" : "未知原因"; + + Console.WriteLine($"导弹 {Id} 自毁。原因: {reason}"); + Deactivate(); + } } public override string GetStatus() @@ -281,7 +288,7 @@ namespace ActiveProtect.Models $" 飞行距离: {FlightDistance:F2}/{MaxFlightDistance:F2}\n" + $" 距离目标: {DistanceToTarget:F2}\n" + $" 发动机工作时间: {EngineBurnTime:F2}/{MaxEngineBurnTime:F2}\n" + - $" 失去引导: {(IsGuidanceLost ? "是" : "否")}\n" + + $" 有引导: {(HasGuidance ? "是" : "否")}\n" + $" 失去引导时间: {LostGuidanceTime:F2}/{MaxLostGuidanceTime:F2}"; } @@ -291,15 +298,6 @@ namespace ActiveProtect.Models Console.WriteLine($"导弹 {Id} 的比例导引系数已更新为 {newCoefficient}"); } - protected virtual void LoseGuidance() - { - if (!IsGuidanceLost) - { - Console.WriteLine($"导弹 {Id} 失去引导"); - IsGuidanceLost = true; - } - } - protected virtual void HandleLostGuidance(double deltaTime) { LostGuidanceTime += deltaTime; @@ -310,33 +308,6 @@ namespace ActiveProtect.Models } } - 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 7f8a13e..f8b9d0f 100644 --- a/Models/Tank.cs +++ b/Models/Tank.cs @@ -6,13 +6,10 @@ namespace ActiveProtect.Models public class Tank : SimulationElement, ILaserIlluminatable { public double Speed { get; 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) @@ -21,10 +18,6 @@ namespace ActiveProtect.Models MaxSpeed = tankConfig.MaxSpeed; MaxArmor = tankConfig.MaxArmor; CurrentArmor = tankConfig.MaxArmor; - LaserWarner = new LaserWarner(this); - LaserJammer = new LaserJammer(this); - - // 移除事件订阅,因为现在由LaserWarner直接处理 } public override void Update(double deltaTime) @@ -32,18 +25,7 @@ namespace ActiveProtect.Models 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) @@ -63,23 +45,28 @@ namespace ActiveProtect.Models CurrentArmor = Math.Max(0, CurrentArmor - damage); if (CurrentArmor <= 0) { - IsActive = false; - PublishEvent(new EntityDestroyedEvent { DestroyedEntityId = Id }); + Deactivate(); } } public void Illuminate() { - IsIlluminated = true; + if (!IsIlluminated) + { + IsIlluminated = true; + Console.WriteLine($"坦克 {Id} 被激光照射"); + } } public void StopIllumination() { - IsIlluminated = false; + if (IsIlluminated) + { + IsIlluminated = false; + Console.WriteLine($"坦克 {Id} 激光照射停止"); + } } - // 移除OnLaserIllumination和OnLaserIlluminationStop方法,因为现在由LaserWarner直接处理 - public override string GetStatus() { return $"坦克 {Id}:\n" + @@ -87,9 +74,7 @@ namespace ActiveProtect.Models $" 速度: {Speed:F2}/{MaxSpeed:F2}\n" + $" 装甲: {CurrentArmor:F2}/{MaxArmor:F2}\n" + $" 状态: {(IsActive ? "活动" : "已销毁")}\n" + - $" 激光照射: {(IsIlluminated ? "是" : "否")}\n" + - $" 激光报警: {(LaserWarner.IsAlarming ? "警报中" : "正常")}\n" + - $" 激光干扰: {(LaserJammer.IsJamming ? $"干扰中 (功率: {LaserJammer.JammingPower:F2})" : "未干扰")}"; + $" 激光照射: {(IsIlluminated ? "是" : "否")}\n"; } } } \ No newline at end of file diff --git a/Program.cs b/Program.cs index 5247af4..14e6c83 100644 --- a/Program.cs +++ b/Program.cs @@ -19,9 +19,22 @@ namespace ActiveProtect InitialOrientation = new Orientation(0, 0, 0), InitialSpeed = 0, MaxSpeed = 20, - MaxArmor = 100 + MaxArmor = 100, + HasLaserWarner = true, + HasLaserJammer = true } ], + LaserWarnerConfig = new LaserWarnerConfig + { + AlarmDuration = 5.0 + }, + LaserJammerConfig = new LaserJammerConfig + { + MaxJammingCooldown = 5.0, + MaxJammingPower = 10000.0, + InitialJammingPower = 4000.0, + PowerIncreaseRate = 2000.0 + }, MissileConfigs = [ // 标准导弹配置 @@ -31,7 +44,7 @@ namespace ActiveProtect InitialSpeed = 10, MaxSpeed = 400, TargetIndex = 0, - MaxFlightTime = 0, + MaxFlightTime = 0.5, MaxFlightDistance = 5000, ThrustAcceleration = 80, MaxEngineBurnTime = 5, @@ -48,7 +61,7 @@ namespace ActiveProtect InitialSpeed = 700, MaxSpeed = 800, TargetIndex = 0, - MaxFlightTime = 0, + MaxFlightTime = 0.5, MaxFlightDistance = 5000, ThrustAcceleration = 50, MaxEngineBurnTime = 5, @@ -65,7 +78,7 @@ namespace ActiveProtect InitialSpeed = 10, MaxSpeed = 300, TargetIndex = 0, - MaxFlightTime = 0, + MaxFlightTime = 0.5, MaxFlightDistance = 3000, ThrustAcceleration = 50, MaxEngineBurnTime = 5, @@ -82,7 +95,7 @@ namespace ActiveProtect InitialSpeed = 700, MaxSpeed = 800, TargetIndex = 0, - MaxFlightTime = 20, + MaxFlightTime = 5, MaxFlightDistance = 4500, ThrustAcceleration = 50, MaxEngineBurnTime = 5, @@ -98,7 +111,6 @@ namespace ActiveProtect new LaserDesignatorConfig { InitialPosition = new Vector3D(500, 150, 100), - TargetId = "Tank_1", MaxIlluminationRange = 1000 } ], @@ -109,7 +121,7 @@ namespace ActiveProtect var simulationManager = new SimulationManager(config); // 运行仿真 - int maxIterations = 1000; // 增加最大迭代次数 + int maxIterations = 1000; int iteration = 0; while (!simulationManager.IsSimulationEnded && iteration < maxIterations) { @@ -121,6 +133,5 @@ namespace ActiveProtect Console.WriteLine("仿真结束"); } - } } \ No newline at end of file diff --git a/SimulationEnvironment/SimulationConfig.cs b/SimulationEnvironment/SimulationConfig.cs index fdaf0ff..f83dc7e 100644 --- a/SimulationEnvironment/SimulationConfig.cs +++ b/SimulationEnvironment/SimulationConfig.cs @@ -7,6 +7,8 @@ namespace ActiveProtect.SimulationEnvironment public List TankConfigs { get; set; } public List MissileConfigs { get; set; } public List LaserDesignatorConfigs { get; set; } + public LaserWarnerConfig LaserWarnerConfig { get; set; } + public LaserJammerConfig LaserJammerConfig { get; set; } public double SimulationTimeStep { get; set; } public SimulationConfig() @@ -14,6 +16,8 @@ namespace ActiveProtect.SimulationEnvironment TankConfigs = []; MissileConfigs = []; LaserDesignatorConfigs = []; + LaserWarnerConfig = new LaserWarnerConfig(); + LaserJammerConfig = new LaserJammerConfig(); SimulationTimeStep = 0.1; // 默认时间步长为0.1秒 } } @@ -26,6 +30,9 @@ namespace ActiveProtect.SimulationEnvironment public double MaxSpeed { get; set; } public double MaxArmor { get; set; } + public bool HasLaserWarner { get; set; } + public bool HasLaserJammer { get; set; } + public TankConfig() { InitialPosition = new Vector3D(0, 0, 0); @@ -53,7 +60,7 @@ namespace ActiveProtect.SimulationEnvironment public MissileConfig() { - InitialPosition = new Vector3D(0, 0, 0); // 初始位�� + InitialPosition = new Vector3D(0, 0, 0); // 初始位 InitialOrientation = new Orientation(0, 0, 0); // 初始方向 InitialSpeed = 0; // 初始速度 MaxSpeed = 0; // 最大速度 @@ -73,12 +80,10 @@ namespace ActiveProtect.SimulationEnvironment public class LaserDesignatorConfig { 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; } } @@ -125,4 +130,31 @@ namespace ActiveProtect.SimulationEnvironment /// public static FlightStageConfig LaserSemiActiveGuidedMissile => new(enableAcceleration: false); } + } + + public class LaserWarnerConfig + { + public double AlarmDuration { get; set; } + + public LaserWarnerConfig() + { + AlarmDuration = 5.0; // 默认警报持续5秒 + } + } + + public class LaserJammerConfig + { + public double MaxJammingCooldown { get; set; } + public double MaxJammingPower { get; set; } + public double InitialJammingPower { get; set; } + public double PowerIncreaseRate { get; set; } + + public LaserJammerConfig() + { + MaxJammingCooldown = 5.0; + MaxJammingPower = 10000.0; + InitialJammingPower = 4000.0; + PowerIncreaseRate = 2000.0; // 每秒增加的功率 + } + } diff --git a/SimulationEnvironment/SimulationElement.cs b/SimulationEnvironment/SimulationElement.cs index 1bcd14e..92fcc89 100644 --- a/SimulationEnvironment/SimulationElement.cs +++ b/SimulationEnvironment/SimulationElement.cs @@ -8,12 +8,13 @@ namespace ActiveProtect.SimulationEnvironment public Vector3D Position { get; set; } = position; public Orientation Orientation { get; set; } = orientation; public ISimulationManager SimulationManager { get; set; } = simulationManager; + public bool IsActive { get; protected set; } = true; public abstract void Update(double deltaTime); public virtual string GetStatus() { - return $"{GetType().Name} {Id} at {Position}, Orientation: {Orientation}"; + return $"{GetType().Name} {Id} at {Position}, Orientation: {Orientation}, Active: {IsActive}"; } protected void PublishEvent(SimulationEvent evt) @@ -22,5 +23,17 @@ namespace ActiveProtect.SimulationEnvironment evt.Timestamp = SimulationManager.CurrentTime; SimulationManager.PublishEvent(evt); } + + protected virtual void Activate() + { + IsActive = true; + PublishEvent(new EntityActivatedEvent { ActivatedEntityId = Id }); + } + + protected virtual void Deactivate() + { + IsActive = false; + PublishEvent(new EntityDeactivatedEvent { DeactivatedEntityId = Id }); + } } } diff --git a/SimulationEnvironment/SimulationEvents.cs b/SimulationEnvironment/SimulationEvents.cs index a28eb22..22520d1 100644 --- a/SimulationEnvironment/SimulationEvents.cs +++ b/SimulationEnvironment/SimulationEvents.cs @@ -31,4 +31,14 @@ namespace ActiveProtect.SimulationEnvironment { public string? TargetId { get; set; } } + + public class EntityActivatedEvent : SimulationEvent + { + public string? ActivatedEntityId { get; set; } + } + + public class EntityDeactivatedEvent : SimulationEvent + { + public string? DeactivatedEntityId { get; set; } + } } \ No newline at end of file diff --git a/SimulationEnvironment/SimulationManager.cs b/SimulationEnvironment/SimulationManager.cs index 87804c5..5f79ff8 100644 --- a/SimulationEnvironment/SimulationManager.cs +++ b/SimulationEnvironment/SimulationManager.cs @@ -9,12 +9,14 @@ namespace ActiveProtect.SimulationEnvironment { double CurrentTime { get; } + void AddElement(SimulationElement element); 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; + void UnsubscribeAllEvents(SimulationElement element); } public class SimulationManager : ISimulationManager @@ -24,6 +26,7 @@ namespace ActiveProtect.SimulationEnvironment public bool IsSimulationEnded { get; private set; } private readonly SimulationConfig config; private Dictionary> eventHandlers = new Dictionary>(); + private Dictionary> elementSubscriptions = new Dictionary>(); public SimulationManager(SimulationConfig config) { @@ -36,17 +39,54 @@ namespace ActiveProtect.SimulationEnvironment private void InitializeSimulation() { - // 创建坦克(保持不变) + // 创建坦克 for (int i = 0; i < config.TankConfigs.Count; i++) { var tankConfig = config.TankConfigs[i]; - Elements.Add(new Tank($"Tank_{i + 1}", tankConfig, this)); + var tank = new Tank($"Tank_{i + 1}", tankConfig, this); + Elements.Add(tank); + + // 为坦克创建激光告警器 + if (tankConfig.HasLaserWarner) + { + var laserWarner = new LaserWarner( + $"LaserWarner_{tank.Id}", + tank.Position, + tank.Orientation, + this, + tank.Id, + config.LaserWarnerConfig + ); + Elements.Add(laserWarner); + } + + // 为坦克创建激光干扰机 + if (tankConfig.HasLaserJammer) + { + var laserJammer = new LaserJammer( + $"LaserJammer_{tank.Id}", + tank.Position, + tank.Orientation, + this, + tank.Id, + config.LaserJammerConfig + ); + Elements.Add(laserJammer); + } } // 创建导弹(修改这部分) for (int i = 0; i < config.MissileConfigs.Count; i++) { var missileConfig = config.MissileConfigs[i]; + + // 确保 MaxFlightTime 设置合理 + if (missileConfig.MaxFlightTime <= 0) + { + missileConfig.MaxFlightTime = 300; // 设置一个默认值,比如 300 秒 + Console.WriteLine($"警告:导弹配置 {i} 的 MaxFlightTime 无效,已设置为默认值 300 秒"); + } + Missile missile = missileConfig.Type switch { MissileType.SemiActiveLaserGuidance => new LaserSemiActiveGuidedMissile( @@ -67,7 +107,7 @@ namespace ActiveProtect.SimulationEnvironment for (int i = 0; i < config.LaserDesignatorConfigs.Count; i++) { var laserDesignatorConfig = config.LaserDesignatorConfigs[i]; - var laserDesignator = new LaserDesignator($"LD_{i + 1}", laserDesignatorConfig, this); + var laserDesignator = new LaserDesignator($"LD_{i + 1}", "Tank_1", laserDesignatorConfig, this); Elements.Add(laserDesignator); laserDesignator.ActivateLaser(); // 激活激光目标指示器 } @@ -93,6 +133,17 @@ namespace ActiveProtect.SimulationEnvironment eventHandlers[eventType] = new List(); } eventHandlers[eventType].Add(handler); + + // 记录订阅关系 + var element = Elements.FirstOrDefault(e => e.GetType().GetMethods().Any(m => m.Name == handler.Method.Name)); + if (element != null) + { + if (!elementSubscriptions.ContainsKey(element)) + { + elementSubscriptions[element] = new List<(Type, Delegate)>(); + } + elementSubscriptions[element].Add((eventType, handler)); + } } public void UnsubscribeFromEvent(Action handler) where T : SimulationEvent @@ -102,6 +153,28 @@ namespace ActiveProtect.SimulationEnvironment { eventHandlers[eventType].Remove(handler); } + + // 移除订阅关系记录 + var element = Elements.FirstOrDefault(e => e.GetType().GetMethods().Any(m => m.Name == handler.Method.Name)); + if (element != null && elementSubscriptions.ContainsKey(element)) + { + elementSubscriptions[element].RemoveAll(s => Delegate.Equals(s.Item2, handler)); + } + } + + public void UnsubscribeAllEvents(SimulationElement element) + { + if (elementSubscriptions.ContainsKey(element)) + { + foreach (var subscription in elementSubscriptions[element]) + { + if (eventHandlers.ContainsKey(subscription.Item1)) + { + eventHandlers[subscription.Item1].Remove(subscription.Item2); + } + } + elementSubscriptions.Remove(element); + } } public void Update() @@ -112,14 +185,21 @@ namespace ActiveProtect.SimulationEnvironment foreach (var element in Elements.ToList()) { - element.Update(config.SimulationTimeStep); + if (element.IsActive) + { + element.Update(config.SimulationTimeStep); + } + else + { + UnsubscribeAllEvents(element); + } } // 移除不活跃的元素 - Elements.RemoveAll(e => (e is Tank tank && !tank.IsActive) || (e is Missile missile && !missile.IsActive)); + Elements.RemoveAll(e => !e.IsActive); // 检查是否所有导弹都结束飞行 - if (!Elements.Any(e => e is Missile)) + if (!Elements.Any(e => e is Missile && e.IsActive)) { EndSimulation(); } @@ -158,19 +238,11 @@ namespace ActiveProtect.SimulationEnvironment // 对坦克造成伤害 tank.TakeDamage(damage, true); - // 移除已爆炸的导弹 - RemoveEntity(missileId); - // 记录击中事件 LogHitEvent(targetId, missileId, damage); } } - private void RemoveEntity(string missileId) - { - Elements.Remove(GetEntityById(missileId)); - } - private double CalculateMissileDamage(Missile missile) { // 这里可以根据导弹类型、速度等因素计算伤害 @@ -178,9 +250,14 @@ namespace ActiveProtect.SimulationEnvironment return 100; } - private void LogHitEvent(string targetId, string missileId, double damage) + private static void LogHitEvent(string targetId, string missileId, double damage) { Console.WriteLine($"目标 {targetId} 被导弹 {missileId} 击中,造成 {damage} 点伤害"); } + + public void AddElement(SimulationElement element) + { + Elements.Add(element); + } } } \ No newline at end of file