From db529f1bd143de6911510d142ec7bd76c9819bcd Mon Sep 17 00:00:00 2001 From: Tian jianyong <11429339@qq.com> Date: Wed, 9 Oct 2024 22:19:02 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E5=AF=BC=E5=BC=B9?= =?UTF-8?q?=E5=8A=A0=E9=80=9F=E9=98=B6=E6=AE=B5=E3=80=81=E7=9B=AE=E6=A0=87?= =?UTF-8?q?=E6=8C=87=E7=A4=BA=E5=99=A8=E7=9A=84=E7=BB=88=E6=AD=A2=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursorrules | 105 +++-- ActiveProtect.sln | 4 + Models/Common.cs | 10 +- Models/ILaserIlluminatable.cs | 1 - Models/LaserDesignator.cs | 14 +- Models/LaserJammer.cs | 15 +- Models/LaserSemiActiveGuidedMissile.cs | 24 +- Models/LaserWarner.cs | 2 + Models/Missile.cs | 471 ++++++++++++++------- Models/Tank.cs | 19 +- Program.cs | 98 +++-- SimulationEnvironment/SimulationConfig.cs | 95 +++-- SimulationEnvironment/SimulationEvents.cs | 11 + SimulationEnvironment/SimulationManager.cs | 35 +- 14 files changed, 576 insertions(+), 328 deletions(-) diff --git a/.cursorrules b/.cursorrules index b438a7f..bad2367 100644 --- a/.cursorrules +++ b/.cursorrules @@ -1,52 +1,69 @@ - 您是 C#、Unity 和可扩展游戏开发的专家。 + + # C 开发规则 - 关键原则 - - 编写清晰、技术性的响应,提供精确的 C# 和 Unity 示例。 - - 尽可能使用 Unity 的内置功能和工具,以充分利用其能力。 - - 优先考虑可读性和可维护性;遵循 C# 编码规范和 Unity 最佳实践。 - - 使用描述性的变量和函数名称;遵循命名约定(例如,公共成员使用 PascalCase,私有成员使用 camelCase)。 - - 以模块化的方式构建项目,使用 Unity 的基于组件的架构,以促进可重用性和关注点分离。 + 您是一名C#开发专家。 - C#/Unity - - 对于附加到 GameObject 的脚本组件,使用 MonoBehaviour;对于数据容器和共享资源,优先使用 ScriptableObjects。 - - 利用 Unity 的物理引擎和碰撞检测系统来实现游戏机制和交互。 - - 使用 Unity 的输入系统处理跨多个平台的玩家输入。 - - 利用 Unity 的 UI 系统(Canvas、UI 元素)创建用户界面。 - - 严格遵循组件模式,以实现关注点的清晰分离和模块化。 - - 在 Unity 的单线程环境中,使用协程处理基于时间的操作和异步任务。 + ## 代码风格和结构 + - 编写简洁、符合习惯的 C# 代码,并提供准确的示例。 + - 根据需要使用面向对象和函数式编程模式。 + - 优先使用 LINQ 和 lambda 表达式进行集合操作。 + - 使用描述性变量和方法名称(例如,'IsUserSignedIn', 'CalculateTotal')。 - 错误处理和调试 - - 在适当的地方使用 try-catch 块实现错误处理,特别是对于文件 I/O 和网络操作。 - - 使用 Unity 的 Debug 类进行日志记录和调试(例如,Debug.Log、Debug.LogWarning、Debug.LogError)。 - - 利用 Unity 的分析器和帧调试器识别和解决性能问题。 - - 实现自定义错误消息和调试可视化,以改善开发体验。 - - 使用 Unity 的断言系统(Debug.Assert)在开发过程中捕获逻辑错误。 + ## 命名约定 + - 类名、方法名和公共成员使用 PascalCase。 + - 局部变量和私有字段使用 camelCase。 + - 常量使用 UPPERCASE。 + - 接口名称以 "I" 开头(例如,'IUserService')。 - 依赖项 - - Unity 引擎 - - .NET 框架(与您的 Unity 版本兼容的版本) - - Unity 资产商店包(根据特定功能需要) - - 第三方插件(经过仔细审查以确保兼容性和性能) + ## C# 使用 + - 在适当的情况下使用 C# 10+ 特性(例如,记录类型、模式匹配、空合并赋值)。 + - 有效使用 Entity Framework Core 进行数据库操作。 + - 使用依赖注入实现松耦合和可测试性。 + - 类的构造函数使用主构造函数,成员变量使用属性初始化。 - Unity 特定指南 - - 使用预制件(Prefabs)创建可重用的游戏对象和 UI 元素。 - - 将游戏逻辑保留在脚本中;使用 Unity 编辑器进行场景组合和初始设置。 - - 利用 Unity 的动画系统(Animator、动画剪辑)进行角色和对象动画。 - - 应用 Unity 的内置光照和后处理效果以增强视觉效果。 - - 使用 Unity 的内置测试框架进行单元测试和集成测试。 - - 利用 Unity 的资源包系统进行高效的资源管理和加载。 - - 使用 Unity 的标签和层系统进行对象分类和碰撞过滤。 + ## 语法和格式 + - 遵循 C# 编码约定(https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions) + - 使用 C# 的表达式语法(例如,空条件运算符、字符串插值) + - 当类型明显时,使用 'var' 进行隐式类型声明。 - 性能优化 - - 对于频繁实例化和销毁的对象,使用对象池。 - - 通过批处理材质和使用精灵和 UI 元素的图集来优化绘制调用。 - - 实现细节层次(LOD)系统,以提高复杂 3D 模型的渲染性能。 - - 使用 Unity 的作业系统和 Burst 编译器进行 CPU 密集型操作。 - - 通过使用简化的碰撞网格和调整固定时间步长来优化物理性能。 + ## 错误处理和验证 + - 对于异常情况使用异常,而不是控制流。 + - 使用内置的 .NET 日志记录或第三方日志记录器实现适当的错误日志记录。 + - 使用数据注解或 Fluent Validation 进行模型验证。 + - 实现全局异常处理的中间件。 + - 返回适当的 HTTP 状态码和一致的错误响应。 - 关键约定 - 1. 遵循 Unity 的基于组件的架构,以实现模块化和可重用的游戏元素。 - 2. 在开发的每个阶段优先考虑性能优化和内存管理。 - 3. 维护清晰和逻辑的项目结构,以增强可读性和资产管理。 + ## API 设计 + - 遵循 RESTful API 设计原则。 + - 在控制器中使用属性路由。 + - 为您的 API 实现版本控制。 + - 使用操作过滤器处理跨切关注点。 - 请参考 Unity 文档和 C# 编程指南,以获取脚本、游戏架构和性能优化的最佳实践。 + ## 性能优化 + - 对于 I/O 密集型操作,使用 async/await 进行异步编程。 + - 使用 IMemoryCache 或分布式缓存实现缓存策略。 + - 使用高效的 LINQ 查询,避免 N+1 查询问题。 + - 对于大型数据集实现分页。 + + ## 关键约定 + - 使用依赖注入实现松耦合和可测试性。 + - 根据复杂性实现仓储模式或直接使用 Entity Framework Core。 + - 如有需要,使用 AutoMapper 进行对象到对象的映射。 + - 使用 IHostedService 或 BackgroundService 实现后台任务。 + + ## 测试 + - 使用 xUnit、NUnit 或 MSTest 编写单元测试。 + - 使用 Moq 或 NSubstitute 模拟依赖项。 + - 为 API 端点实现集成测试。 + + ## 安全性 + - 使用身份验证和授权中间件。 + - 实现 JWT 身份验证以进行无状态 API 身份验证。 + - 使用 HTTPS 并强制 SSL。 + - 实现适当的 CORS 策略。 + + ## API 文档 + - 使用 Swagger/OpenAPI 进行 API 文档(根据安装的 Swashbuckle.AspNetCore 包)。 + - 为控制器和模型提供 XML 注释,以增强 Swagger 文档。 + + 遵循官方 Microsoft 文档,以获取路由、控制器、模型和其他 API 组件的最佳实践。 diff --git a/ActiveProtect.sln b/ActiveProtect.sln index 414cdb7..99af9fe 100644 --- a/ActiveProtect.sln +++ b/ActiveProtect.sln @@ -15,6 +15,10 @@ Global {7F47A2C7-1087-440B-82F7-A1BF50D30A1B}.Debug|Any CPU.Build.0 = Debug|Any CPU {7F47A2C7-1087-440B-82F7-A1BF50D30A1B}.Release|Any CPU.ActiveCfg = Release|Any CPU {7F47A2C7-1087-440B-82F7-A1BF50D30A1B}.Release|Any CPU.Build.0 = Release|Any CPU + {644AFA6F-7DEE-4438-85C3-1D380B052E3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {644AFA6F-7DEE-4438-85C3-1D380B052E3D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {644AFA6F-7DEE-4438-85C3-1D380B052E3D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {644AFA6F-7DEE-4438-85C3-1D380B052E3D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Models/Common.cs b/Models/Common.cs index c9ed4f8..45a254d 100644 --- a/Models/Common.cs +++ b/Models/Common.cs @@ -138,14 +138,6 @@ namespace ActiveProtect.Models } } - public enum MissileType - { - StandardMissile, // 标准导弹 - SemiActiveLaserGuidance, // 半主动激光制导 - LaserBeamRiderGuidance, // 激光束制导 - InfraredCommandGuidance, // 红外指令制导 - ImagingInfraredTerminalGuidance, // 成像红外终端制导 - MillimeterWaveTerminalGuidance // 毫米波终端制导 - } + } diff --git a/Models/ILaserIlluminatable.cs b/Models/ILaserIlluminatable.cs index 693eebb..45e8962 100644 --- a/Models/ILaserIlluminatable.cs +++ b/Models/ILaserIlluminatable.cs @@ -6,7 +6,6 @@ namespace ActiveProtect.Models { bool IsIlluminated { get; } void Illuminate(); - // 移除重复的 Illuminate 方法(如果存在) void StopIllumination(); Vector3D Position { get; } } diff --git a/Models/LaserDesignator.cs b/Models/LaserDesignator.cs index 62f8467..9fb00af 100644 --- a/Models/LaserDesignator.cs +++ b/Models/LaserDesignator.cs @@ -6,18 +6,21 @@ namespace ActiveProtect.Models public class LaserDesignator : SimulationElement { public string TargetId { get; private set; } + public string MissileId { get; private set; } 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, string targetId, LaserDesignatorConfig config, ISimulationManager simulationManager) + public LaserDesignator(string id, string targetId, string missileId, LaserDesignatorConfig config, ISimulationManager simulationManager) : base(id, config.InitialPosition, new Orientation(), simulationManager) { TargetId = targetId; + MissileId = missileId; IsActive = true; MaxIlluminationRange = config.MaxIlluminationRange; SimulationManager.SubscribeToEvent(OnLaserJamming); + SimulationManager.SubscribeToEvent(OnEntityDeactivatedEvent); } public override void Update(double deltaTime) @@ -150,6 +153,15 @@ namespace ActiveProtect.Models }); } + private void OnEntityDeactivatedEvent(EntityDeactivatedEvent evt) + { + if (evt.DeactivatedEntityId == TargetId || evt.DeactivatedEntityId == MissileId) + { + DeactivateLaser(); + Deactivate(); + } + } + public override string GetStatus() { return $"激光目标指示器 {Id}:\n" + diff --git a/Models/LaserJammer.cs b/Models/LaserJammer.cs index a772620..ccb9acd 100644 --- a/Models/LaserJammer.cs +++ b/Models/LaserJammer.cs @@ -24,16 +24,15 @@ namespace ActiveProtect.Models maxJammingPower = config.MaxJammingPower; initialJammingPower = config.InitialJammingPower; powerIncreaseRate = config.PowerIncreaseRate; - SimulationManager.SubscribeToEvent(OnLaserIllumination); - SimulationManager.SubscribeToEvent(OnLaserIlluminationStop); + SimulationManager.SubscribeToEvent(OnLaserWarnerAlarmEvent); + SimulationManager.SubscribeToEvent(OnLaserWarnerAlarmStopEvent); } public override void Update(double deltaTime) { if (!IsActive) return; - var tank = SimulationManager.GetEntityById(MonitoredEntityId) as Tank; - if (tank != null) + if (SimulationManager.GetEntityById(MonitoredEntityId) is Tank tank) { Position = tank.Position; Orientation = tank.Orientation; @@ -62,7 +61,7 @@ namespace ActiveProtect.Models } } - private void OnLaserIllumination(LaserIlluminationEvent evt) + private void OnLaserWarnerAlarmEvent(LaserWarnerAlarmEvent evt) { if (evt.TargetId == MonitoredEntityId) { @@ -70,7 +69,7 @@ namespace ActiveProtect.Models } } - private void OnLaserIlluminationStop(LaserIlluminationStopEvent evt) + private void OnLaserWarnerAlarmStopEvent(LaserWarnerAlarmStopEvent evt) { if (evt.TargetId == MonitoredEntityId) { @@ -112,8 +111,8 @@ namespace ActiveProtect.Models protected override void Deactivate() { base.Deactivate(); - SimulationManager.UnsubscribeFromEvent(OnLaserIllumination); - SimulationManager.UnsubscribeFromEvent(OnLaserIlluminationStop); + SimulationManager.UnsubscribeFromEvent(OnLaserWarnerAlarmEvent); + SimulationManager.UnsubscribeFromEvent(OnLaserWarnerAlarmStopEvent); } } } \ No newline at end of file diff --git a/Models/LaserSemiActiveGuidedMissile.cs b/Models/LaserSemiActiveGuidedMissile.cs index ab85613..b054aaa 100644 --- a/Models/LaserSemiActiveGuidedMissile.cs +++ b/Models/LaserSemiActiveGuidedMissile.cs @@ -5,7 +5,7 @@ namespace ActiveProtect.Models { public class LaserSemiActiveGuidedMissile : Missile { - private const double LaserLockDistance = 2000; // 1公里,单位:米 + private const double LaserLockDistance = 1500; // 锁定距离,单位:米 public LaserSemiActiveGuidedMissile( string id, @@ -13,19 +13,15 @@ namespace ActiveProtect.Models ISimulationManager simulationManager) : base(id, missileConfig, simulationManager) { - Type = MissileType.SemiActiveLaserGuidance; + Type = MissileType.LaserSemiActiveGuidance; simulationManager.SubscribeToEvent(OnLaserIllumination); simulationManager.SubscribeToEvent(OnLaserIlluminationStop); } - public override void Update(double deltaTime) + protected override void UpdateGuidanceStatus() { - base.Update(deltaTime); - UpdateGuidanceStatus(); - } + bool previousHasGuidance = HasGuidance; - private void UpdateGuidanceStatus() - { if (SimulationManager.GetEntityById(TargetId) is ILaserIlluminatable target) { bool isIlluminated = target.IsIlluminated; @@ -37,12 +33,24 @@ namespace ActiveProtect.Models Console.WriteLine($" 距离目标: {DistanceToTarget:F2} m (最大锁定距离: {LaserLockDistance} m)"); Console.WriteLine($" 是否在锁定范围内: {isWithinRange}"); Console.WriteLine($" 引导状态: {(HasGuidance ? "有效" : "无效")}"); + + if (!HasGuidance && previousHasGuidance) + { + Console.WriteLine($"激光半主动制导导弹 {Id} 失去引导"); + LastKnownVelocity = Velocity; + } + else if (HasGuidance && !previousHasGuidance) + { + Console.WriteLine($"激光半主动制导导弹 {Id} 获得引导"); + } } else { HasGuidance = false; Console.WriteLine($"激光半主动制导导弹 {Id} 无法找到目标 {TargetId}"); } + + base.UpdateGuidanceStatus(); } private void OnLaserIllumination(LaserIlluminationEvent evt) diff --git a/Models/LaserWarner.cs b/Models/LaserWarner.cs index 97b66c0..f7a9236 100644 --- a/Models/LaserWarner.cs +++ b/Models/LaserWarner.cs @@ -63,6 +63,7 @@ namespace ActiveProtect.Models { IsAlarming = true; alarmTimer = 0; + PublishEvent(new LaserWarnerAlarmEvent() { TargetId = MonitoredEntityId }); Console.WriteLine($"激光告警器 {Id} 发出警报!"); } } @@ -73,6 +74,7 @@ namespace ActiveProtect.Models { IsAlarming = false; alarmTimer = 0; + PublishEvent(new LaserWarnerAlarmStopEvent() { TargetId = MonitoredEntityId }); Console.WriteLine($"激光告警器 {Id} 停止警报"); } } diff --git a/Models/Missile.cs b/Models/Missile.cs index 7f61319..c1dbb50 100644 --- a/Models/Missile.cs +++ b/Models/Missile.cs @@ -11,23 +11,7 @@ namespace ActiveProtect.Models /// /// 导弹类型 /// - public MissileType Type { get; protected set; } - - /// - /// 导弹飞行的各个阶段 - /// - public enum FlightStage - { - Launch, // 发射阶段 - Acceleration, // 加速阶段 - Cruise, // 巡航阶段 - TerminalGuidance, // 终端制导阶段 - Attack, // 攻击阶段 - Explosion // 爆炸阶段 - } - - - + public MissileType Type { get; protected set; } public double Speed { get; protected set; } public double MaxSpeed { get; protected set; } public string TargetId { get; protected set; } @@ -38,8 +22,7 @@ namespace ActiveProtect.Models public double DistanceToTarget { get; protected set; } public MissileDistanceParams DistanceParams { get; protected set; } public FlightStageConfig StageConfig { get; protected set; } - public FlightStage CurrentStage { get; protected set; } - + public FlightStage CurrentStage { get; protected set; } protected Vector3D Velocity; private Vector3D LastTargetPosition; private const double N = 3; // 比例导引系数 @@ -52,9 +35,17 @@ namespace ActiveProtect.Models public double ProportionalNavigationCoefficient { get; set; } - public bool HasGuidance { get; protected set; } = true; + public bool HasGuidance { get; protected set; } = false; protected double LostGuidanceTime { get; set; } = 0; - protected const double MaxLostGuidanceTime = 1.0; // 1秒后自毁 + protected Vector3D LastKnownVelocity = Vector3D.Zero; + public const double LAUNCH_SPEED = 10; // 发射速度,单位:m/s + public const double LAUNCH_DURATION = 0.5; // 发射阶持续时间,单位:秒 + + private IMissileStageStrategy currentStage; + private Dictionary stageStrategies; + + // 添加质量属性 + public double Mass { get; protected set; } = 100; // 默认质量为100kg,可以根据需要调整 public Missile(string id, MissileConfig missileConfig, ISimulationManager simulationManager) : base(id, missileConfig.InitialPosition, missileConfig.InitialOrientation, simulationManager) @@ -78,34 +69,191 @@ namespace ActiveProtect.Models Vector3D horizontalDirection = new Vector3D(Orientation.ToVector().X, 0, Orientation.ToVector().Z).Normalize(); Velocity = horizontalDirection * missileConfig.InitialSpeed; - // 设置初始阶段 - CurrentStage = StageConfig.EnableLaunch ? FlightStage.Launch : - StageConfig.EnableAcceleration ? FlightStage.Acceleration : - StageConfig.EnableCruise ? FlightStage.Cruise : - StageConfig.EnableTerminalGuidance ? FlightStage.TerminalGuidance : - StageConfig.EnableAttack ? FlightStage.Attack : FlightStage.Cruise; + // 初始化策略字典 + stageStrategies = new Dictionary + { + { FlightStage.Launch, new LaunchStageStrategy(this) }, + { FlightStage.Acceleration, new AccelerationStageStrategy(this) }, + { FlightStage.Cruise, new CruiseStageStrategy(this) }, + { FlightStage.TerminalGuidance, new TerminalGuidanceStageStrategy(this) }, + { FlightStage.Attack, new AttackStageStrategy(this) } + }; - Console.WriteLine($"导弹 {Id} 的初始阶: {CurrentStage}"); + // 设置初始阶段 + SetInitialStage(); + + currentStage = stageStrategies[CurrentStage]; LastTargetPosition = Position; // 初始化 LastTargetPosition + DistanceToTarget = Vector3D.Distance(Position, SimulationManager.GetEntityById(TargetId).Position); + } + + private void SetInitialStage() + { + if (StageConfig.EnableLaunch) CurrentStage = FlightStage.Launch; + else if (StageConfig.EnableAcceleration) CurrentStage = FlightStage.Acceleration; + else if (StageConfig.EnableCruise) CurrentStage = FlightStage.Cruise; + else if (StageConfig.EnableTerminalGuidance) CurrentStage = FlightStage.TerminalGuidance; + else if (StageConfig.EnableAttack) CurrentStage = FlightStage.Attack; + + Console.WriteLine($"导弹 {Id} 的初始阶段: {CurrentStage}"); } public override void Update(double deltaTime) { if (!IsActive) return; - // 首先检查是否应该自毁 if (ShouldSelfDestruct()) { SelfDestruct(); return; } - // 更新发动机燃烧时间 UpdateEngineBurnTime(deltaTime); + (Position, Velocity) = UpdatePositionAndVelocityRK4(deltaTime); - // 使用 RK4 方法更新导弹状态 + Speed = Velocity.Magnitude(); + Orientation = Orientation.FromVector(Velocity); + FlightTime += deltaTime; + FlightDistance += Speed * deltaTime; + DistanceToTarget = Vector3D.Distance(Position, SimulationManager.GetEntityById(TargetId).Position); + + if (CheckHit()) + { + Explode(); + return; + } + + UpdateGuidanceStatus(); + currentStage.Update(deltaTime); + } + + public void ChangeStage(FlightStage newStage) + { + if (stageStrategies.TryGetValue(newStage, out var strategy)) + { + if (IsStageEnabled(newStage)) + { + CurrentStage = newStage; + currentStage = strategy; + Console.WriteLine($"导弹 {Id} 切换到 {newStage} 阶段"); + } + else + { + // 如果目标阶段不可用,尝试切换到下一个可用阶段 + TryChangeToNextAvailableStage(newStage); + } + } + else + { + Console.WriteLine($"导弹 {Id} 无法切换到未知阶段 {newStage}"); + } + } + + private bool IsStageEnabled(FlightStage stage) + { + return stage switch + { + FlightStage.Launch => StageConfig.EnableLaunch, + FlightStage.Acceleration => StageConfig.EnableAcceleration, + FlightStage.Cruise => StageConfig.EnableCruise, + FlightStage.TerminalGuidance => StageConfig.EnableTerminalGuidance, + FlightStage.Attack => StageConfig.EnableAttack, + _ => false + }; + } + + private void TryChangeToNextAvailableStage(FlightStage startStage) + { + FlightStage[] stageOrder = [FlightStage.Launch, FlightStage.Acceleration, FlightStage.Cruise, FlightStage.TerminalGuidance, FlightStage.Attack]; + int startIndex = Array.IndexOf(stageOrder, startStage); + + for (int i = startIndex + 1; i < stageOrder.Length; i++) + { + if (IsStageEnabled(stageOrder[i])) + { + ChangeStage(stageOrder[i]); + return; + } + } + + // 如果没有可用的下一个阶段,导弹自毁 + Console.WriteLine($"导弹 {Id} 没有可用的下一个阶段,准备自毁"); + SelfDestruct(); + } + + private (Vector3D, Vector3D) CalculateDerivatives(Vector3D position, Vector3D velocity, double deltaTime) + { + Vector3D guidanceAcceleration = Vector3D.Zero; + Vector3D thrustAcceleration = Vector3D.Zero; + + switch (CurrentStage) + { + case FlightStage.Launch: + thrustAcceleration = Orientation.ToVector() * ThrustAcceleration; + break; + case FlightStage.Acceleration: + thrustAcceleration = Orientation.ToVector() * ThrustAcceleration; + guidanceAcceleration = CalculateProportionalNavigation(position); + break; + case FlightStage.Cruise: + thrustAcceleration = Orientation.ToVector() * (ThrustAcceleration * 0.1); + guidanceAcceleration = CalculateProportionalNavigation(position) * 0.5; + break; + case FlightStage.TerminalGuidance: + thrustAcceleration = Orientation.ToVector() * (ThrustAcceleration * 0.1); + guidanceAcceleration = CalculateProportionalNavigation(position) * 1.5; + break; + case FlightStage.Attack: + thrustAcceleration = Orientation.ToVector() * ThrustAcceleration; + guidanceAcceleration = CalculateProportionalNavigation(position) * 2; + break; + } + + if (!HasGuidance) + { + guidanceAcceleration = Vector3D.Zero; + if (velocity.Magnitude() > 0) + { + thrustAcceleration = velocity.Normalize() * ThrustAcceleration; + } + else + { + thrustAcceleration = Orientation.ToVector() * ThrustAcceleration; + } + } + + // 计算空气阻力的影响 + Vector3D dragAcceleration = velocity.Normalize() * -1 * CalculateDrag(velocity.Magnitude()) / Mass; + + // 计算重力加速度 + Vector3D gravityCompensation = new(0, 9.81, 0); + Vector3D gravityAcceleration = new(0, -9.81, 0); + + Vector3D totalAcceleration = guidanceAcceleration + thrustAcceleration + gravityCompensation + gravityAcceleration + dragAcceleration; + + if (totalAcceleration.Magnitude() > MaxAcceleration) + { + totalAcceleration = totalAcceleration.Normalize() * MaxAcceleration; + } + + return (velocity, totalAcceleration); + } + + private static double CalculateDrag(double speed) + { + // 修改空气阻力计算 + const double dragCoefficient = 0.1; // 减小阻力系数 + const double airDensity = 1.225; // 海平面空气密度,kg/m^3 + const double referenceArea = 0.01; // 减小导弹的参考面积,m^2 + + return 0.5 * dragCoefficient * airDensity * referenceArea * speed * speed; + } + + // 使用 Runge-Kutta 方法更新位置和速度 + private (Vector3D, Vector3D) UpdatePositionAndVelocityRK4(double deltaTime) + { Vector3D k1, k2, k3, k4; Vector3D v1, v2, v3, v4; @@ -114,53 +262,25 @@ namespace ActiveProtect.Models (k3, v3) = CalculateDerivatives(Position + k2 * (deltaTime / 2), Velocity + v2 * (deltaTime / 2), deltaTime / 2); (k4, v4) = CalculateDerivatives(Position + k3 * deltaTime, Velocity + v3 * deltaTime, deltaTime); - Position += (k1 + k2 * 2 + k3 * 2 + k4) * (deltaTime / 6); - Velocity += (v1 + v2 * 2 + v3 * 2 + v4) * (deltaTime / 6); + Vector3D newPosition = Position + (k1 + k2 * 2 + k3 * 2 + k4) * (deltaTime / 6); + Vector3D newVelocity = Velocity + (v1 + v2 * 2 + v3 * 2 + v4) * (deltaTime / 6); - // 更新其他状态 - Speed = Velocity.Magnitude(); - if (Speed > MaxSpeed) + // 限制速度不超过最大速度 + if (newVelocity.Magnitude() > MaxSpeed) { - Speed = MaxSpeed; - Velocity = Velocity.Normalize() * MaxSpeed; + newVelocity = newVelocity.Normalize() * MaxSpeed; } - Orientation = Orientation.FromVector(Velocity); - FlightTime += deltaTime; - FlightDistance += Speed * deltaTime; - DistanceToTarget = Vector3D.Distance(Position, SimulationManager.GetEntityById(TargetId).Position); - - // 检查是否命中目标 - if (CheckHit()) - { - Explode(); - return; - } - - // 更新飞行阶段 - UpdateFlightStage(); - - if (!HasGuidance) - { - HandleLostGuidance(deltaTime); - } - else - { - LostGuidanceTime = 0; - } - - // 发布事件示例 - if (CurrentStage == FlightStage.Launch) - { - PublishEvent(new MissileFireEvent { TargetId = TargetId }); - } + return (newPosition, newVelocity); } + // 检查是否命中目标 private bool CheckHit() { return DistanceToTarget <= DistanceParams.ExplosionDistance; } + // 检查是否应该自毁 private bool ShouldSelfDestruct() { if (FlightTime >= MaxFlightTime) @@ -181,6 +301,7 @@ namespace ActiveProtect.Models return false; } + // 更新发动机燃烧时间 private void UpdateEngineBurnTime(double deltaTime) { if (CurrentStage == FlightStage.Acceleration && EngineBurnTime < MaxEngineBurnTime) @@ -189,74 +310,20 @@ namespace ActiveProtect.Models } } - private (Vector3D, Vector3D) CalculateDerivatives(Vector3D position, Vector3D velocity, double deltaTime) + + // 计算比例导引加速度 + private Vector3D CalculateProportionalNavigation(Vector3D position) { 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() - * ProportionalNavigationCoefficient * velocity.Magnitude(); + Vector3D LOSRate = (targetPosition - LastTargetPosition) / FlightTime - Velocity; LastTargetPosition = targetPosition; - // 添加推力加速度 - Vector3D thrustAcceleration = (CurrentStage == FlightStage.Acceleration && EngineBurnTime < MaxEngineBurnTime) - ? Orientation.ToVector() * ThrustAcceleration - : Orientation.ToVector() * (ThrustAcceleration * 0.1); // 小的持续推力 - - // 添加重力补偿 - Vector3D gravityCompensation = new Vector3D(0, 9.81, 0); - guidanceAcceleration += gravityCompensation; - - Vector3D totalAcceleration = guidanceAcceleration + thrustAcceleration; - - // 添加重力加速度 - Vector3D gravityAcceleration = new(0, -9.81, 0); - totalAcceleration += gravityAcceleration; - - // 限制最大加速度 - if (totalAcceleration.Magnitude() > MaxAcceleration) - { - totalAcceleration = totalAcceleration.Normalize() * MaxAcceleration; - } - - return (velocity, totalAcceleration); - } - - private void UpdateFlightStage() - { - switch (CurrentStage) - { - case FlightStage.Launch: - if (StageConfig.EnableAcceleration) CurrentStage = FlightStage.Acceleration; - else if (StageConfig.EnableCruise) CurrentStage = FlightStage.Cruise; - else if (StageConfig.EnableTerminalGuidance) CurrentStage = FlightStage.TerminalGuidance; - else if (StageConfig.EnableAttack) CurrentStage = FlightStage.Attack; - break; - case FlightStage.Acceleration: - if (EngineBurnTime >= MaxEngineBurnTime || Speed >= MaxSpeed * 0.95) - { - if (StageConfig.EnableCruise) CurrentStage = FlightStage.Cruise; - else if (StageConfig.EnableTerminalGuidance) CurrentStage = FlightStage.TerminalGuidance; - else if (StageConfig.EnableAttack) CurrentStage = FlightStage.Attack; - } - break; - case FlightStage.Cruise: - if (StageConfig.EnableTerminalGuidance && DistanceToTarget <= DistanceParams.TerminalGuidanceDistance) - CurrentStage = FlightStage.TerminalGuidance; - else if (StageConfig.EnableAttack && DistanceToTarget <= DistanceParams.AttackDistance) - CurrentStage = FlightStage.Attack; - break; - case FlightStage.TerminalGuidance: - if (StageConfig.EnableAttack && DistanceToTarget <= DistanceParams.AttackDistance) - CurrentStage = FlightStage.Attack; - break; - case FlightStage.Attack: - if (DistanceToTarget <= DistanceParams.ExplosionDistance) - Explode(); - break; - } + return Vector3D.CrossProduct(Vector3D.CrossProduct(LOS, LOSRate), LOS).Normalize() + * ProportionalNavigationCoefficient * Velocity.Magnitude(); } + // 爆炸 public void Explode() { Deactivate(); @@ -264,6 +331,7 @@ namespace ActiveProtect.Models Console.WriteLine($"导弹 {Id} 在 {Position} 爆炸,命中目标!"); } + // 自毁 public void SelfDestruct() { if (IsActive) @@ -278,36 +346,141 @@ namespace ActiveProtect.Models } } - public override string GetStatus() - { - return $"导弹 {Id}:\n" + - $" 位置: {Position}\n" + - $" 速度: {Speed:F2} m/s\n" + - $" 当前阶段: {CurrentStage}\n" + - $" 飞行时间: {FlightTime:F2}/{MaxFlightTime:F2}\n" + - $" 飞行距离: {FlightDistance:F2}/{MaxFlightDistance:F2}\n" + - $" 距离目标: {DistanceToTarget:F2}\n" + - $" 发动机工作时间: {EngineBurnTime:F2}/{MaxEngineBurnTime:F2}\n" + - $" 有引导: {(HasGuidance ? "是" : "否")}\n" + - $" 失去引导时间: {LostGuidanceTime:F2}/{MaxLostGuidanceTime:F2}"; - } - + // 设置比例导引系数 public void SetProportionalNavigationCoefficient(double newCoefficient) { ProportionalNavigationCoefficient = newCoefficient; Console.WriteLine($"导弹 {Id} 的比例导引系数已更新为 {newCoefficient}"); } - protected virtual void HandleLostGuidance(double deltaTime) + // 获取导弹状态 + public override string GetStatus() { - LostGuidanceTime += deltaTime; - if (LostGuidanceTime >= MaxLostGuidanceTime) - { - Console.WriteLine($"导弹 {Id} 失去引导超过 {MaxLostGuidanceTime} 秒,自毁"); - SelfDestruct(); - } + return $"导弹 {Id}:\n" + + $" 位置: {Position}\n" + + $" 速度: {Speed:F2} m/s\n" + + $" 当前状态: {GetCurrentStateName()}\n" + + $" 飞行时间: {FlightTime:F2}/{MaxFlightTime:F2}\n" + + $" 飞行距离: {FlightDistance:F2}/{MaxFlightDistance:F2}\n" + + $" 距离目标: {DistanceToTarget:F2}\n" + + $" 发动机工作时间: {EngineBurnTime:F2}/{MaxEngineBurnTime:F2}\n" + + $" 有引导: {(HasGuidance ? "是" : "否")}\n" + + $" 失去引导时间: {LostGuidanceTime:F2}"; + } + + // 添加新的方法来更新引导状态 + protected virtual void UpdateGuidanceStatus() + { + // 基类中的默认实现 + } + + public string GetCurrentStateName() + { + return currentStage.GetType().Name; } } + public interface IMissileStageStrategy + { + void Update(double deltaTime); + } + + public class LaunchStageStrategy : IMissileStageStrategy + { + private readonly Missile missile; + private double launchTime = 0; + + public LaunchStageStrategy(Missile missile) + { + this.missile = missile; + } + + public void Update(double deltaTime) + { + launchTime += deltaTime; + if (launchTime >= Missile.LAUNCH_DURATION || missile.Speed >= missile.MaxSpeed * 0.1) + { + missile.ChangeStage(FlightStage.Acceleration); + } + } + } + + public class AccelerationStageStrategy(Missile missile) : IMissileStageStrategy + { + private readonly Missile missile = missile; + + public void Update(double deltaTime) + { + if (missile.EngineBurnTime >= missile.MaxEngineBurnTime || missile.Speed >= missile.MaxSpeed) + { + missile.ChangeStage(FlightStage.Cruise); + } + } + } + + public class CruiseStageStrategy(Missile missile) : IMissileStageStrategy + { + private readonly Missile missile = missile; + + public void Update(double deltaTime) + { + if (missile.DistanceToTarget <= missile.DistanceParams.TerminalGuidanceDistance) + { + missile.ChangeStage(FlightStage.TerminalGuidance); + } + } + } + + public class TerminalGuidanceStageStrategy(Missile missile) : IMissileStageStrategy + { + private readonly Missile missile = missile; + + public void Update(double deltaTime) + { + if (missile.DistanceToTarget <= missile.DistanceParams.AttackDistance) + { + missile.ChangeStage(FlightStage.Attack); + } + } + } + + public class AttackStageStrategy(Missile missile) : IMissileStageStrategy + { + private readonly Missile missile = missile; + + public void Update(double deltaTime) + { + if (missile.DistanceToTarget <= missile.DistanceParams.ExplosionDistance) + { + missile.Explode(); + } + } + } + + public class UnguidedStageStrategy(Missile missile) : IMissileStageStrategy + { + private readonly Missile missile = missile; + + public void Update(double deltaTime) + { + // 检查是否重新获得引导 + if (missile.HasGuidance) + { + Console.WriteLine($"导弹 {missile.Id} 重新获得引导,退出无制导阶段"); + if (missile.DistanceToTarget <= missile.DistanceParams.AttackDistance) + { + missile.ChangeStage(FlightStage.Attack); + } + else if (missile.DistanceToTarget <= missile.DistanceParams.TerminalGuidanceDistance) + { + missile.ChangeStage(FlightStage.TerminalGuidance); + } + else + { + missile.ChangeStage(FlightStage.Cruise); + } + } + } + } } \ No newline at end of file diff --git a/Models/Tank.cs b/Models/Tank.cs index f8b9d0f..235e979 100644 --- a/Models/Tank.cs +++ b/Models/Tank.cs @@ -3,23 +3,14 @@ using System; namespace ActiveProtect.Models { - public class Tank : SimulationElement, ILaserIlluminatable + public class Tank(string id, TankConfig tankConfig, ISimulationManager simulationManager) : SimulationElement(id, tankConfig.InitialPosition, tankConfig.InitialOrientation, simulationManager), ILaserIlluminatable { - public double Speed { get; set; } = 0; - public double MaxSpeed { get; private set; } - public double MaxArmor { get; private set; } - public double CurrentArmor { get; private set; } + public double Speed { get; set; } = tankConfig.InitialSpeed; + public double MaxSpeed { get; private set; } = tankConfig.MaxSpeed; + public double MaxArmor { get; private set; } = tankConfig.MaxArmor; + public double CurrentArmor { get; private set; } = tankConfig.MaxArmor; public bool IsIlluminated { get; private set; } = false; - public Tank(string id, TankConfig tankConfig, ISimulationManager simulationManager) - : base(id, tankConfig.InitialPosition, tankConfig.InitialOrientation, simulationManager) - { - Speed = tankConfig.InitialSpeed; - MaxSpeed = tankConfig.MaxSpeed; - MaxArmor = tankConfig.MaxArmor; - CurrentArmor = tankConfig.MaxArmor; - } - public override void Update(double deltaTime) { if (!IsActive) return; diff --git a/Program.cs b/Program.cs index 14e6c83..f09f5d2 100644 --- a/Program.cs +++ b/Program.cs @@ -20,7 +20,7 @@ namespace ActiveProtect InitialSpeed = 0, MaxSpeed = 20, MaxArmor = 100, - HasLaserWarner = true, + HasLaserWarner = false, HasLaserJammer = true } ], @@ -41,69 +41,73 @@ namespace ActiveProtect new() { InitialPosition = new Vector3D(1500, 200, 100), InitialOrientation = new Orientation(Math.PI, -0.1, 0), - InitialSpeed = 10, - MaxSpeed = 400, - TargetIndex = 0, - MaxFlightTime = 0.5, - MaxFlightDistance = 5000, - ThrustAcceleration = 80, - MaxEngineBurnTime = 5, - MaxAcceleration = 100, - ProportionalNavigationCoefficient = 3, - StageConfig = FlightStageConfig.StandardMissile, - DistanceParams = new MissileDistanceParams(500, 100, 20), - Type = MissileType.StandardMissile - }, - // 激光制导炮弹配置 - new() { - InitialPosition = new Vector3D(2000, 150, 100), - InitialOrientation = new Orientation(Math.PI, -0.15, 0), - InitialSpeed = 700, - MaxSpeed = 800, - TargetIndex = 0, - MaxFlightTime = 0.5, - MaxFlightDistance = 5000, - ThrustAcceleration = 50, - MaxEngineBurnTime = 5, - MaxAcceleration = 100, - ProportionalNavigationCoefficient = 3, - StageConfig = FlightStageConfig.LaserGuidedShell, - DistanceParams = new MissileDistanceParams(300, 100, 20), - Type = MissileType.InfraredCommandGuidance - }, - // 短程导弹配置 - new() { - InitialPosition = new Vector3D(1000, 50, 100), - InitialOrientation = new Orientation(Math.PI, -0.05, 0), - InitialSpeed = 10, + InitialSpeed = 0, MaxSpeed = 300, TargetIndex = 0, MaxFlightTime = 0.5, MaxFlightDistance = 3000, ThrustAcceleration = 50, - MaxEngineBurnTime = 5, + MaxEngineBurnTime = 10, MaxAcceleration = 100, ProportionalNavigationCoefficient = 3, - StageConfig = FlightStageConfig.ShortRangeMissile, - DistanceParams = new MissileDistanceParams(400, 100, 20), + StageConfig = FlightStageConfig.StandardMissile, + DistanceParams = new MissileDistanceParams(500, 100, 20), + Mass = 50, + Type = MissileType.StandardMissile, + }, + // 红外指令制导导弹配置 + new() { + InitialPosition = new Vector3D(2000, 150, 100), + InitialOrientation = new Orientation(Math.PI, -0.15, 0), + InitialSpeed = 0, + MaxSpeed = 300, + TargetIndex = 0, + MaxFlightTime = 1, + MaxFlightDistance = 5000, + ThrustAcceleration = 50, + MaxEngineBurnTime = 10, + MaxAcceleration = 100, + ProportionalNavigationCoefficient = 3, + StageConfig = FlightStageConfig.InfraredCommandGuidance, + DistanceParams = new MissileDistanceParams(500, 100, 20), + Mass = 50, + Type = MissileType.InfraredCommandGuidance + }, + // 毫米波终端制导导弹配置 + new() { + InitialPosition = new Vector3D(2000, 50, 100), + InitialOrientation = new Orientation(Math.PI, -0.05, 0), + InitialSpeed = 0, + MaxSpeed = 300, + TargetIndex = 0, + MaxFlightTime = 0.5, + MaxFlightDistance = 3000, + ThrustAcceleration = 50, + MaxEngineBurnTime = 10, + MaxAcceleration = 100, + ProportionalNavigationCoefficient = 3, + StageConfig = FlightStageConfig.MillimeterWaveTerminalGuidance, + DistanceParams = new MissileDistanceParams(500, 100, 20), + Mass = 50, Type = MissileType.MillimeterWaveTerminalGuidance }, - // 新增激光半主动制导导弹配置 + // 激光半主动制导导弹配置 new() { InitialPosition = new Vector3D(2000, 150, 100), InitialOrientation = new Orientation(Math.PI, -0.12, 0), InitialSpeed = 700, - MaxSpeed = 800, + MaxSpeed = 700, TargetIndex = 0, - MaxFlightTime = 5, - MaxFlightDistance = 4500, - ThrustAcceleration = 50, - MaxEngineBurnTime = 5, + MaxFlightTime = 10, + MaxFlightDistance = 5000, + ThrustAcceleration = 0, + MaxEngineBurnTime = 0, MaxAcceleration = 100, ProportionalNavigationCoefficient = 3, StageConfig = FlightStageConfig.LaserSemiActiveGuidedMissile, DistanceParams = new MissileDistanceParams(500, 200, 20), - Type = MissileType.SemiActiveLaserGuidance + Mass = 50, + Type = MissileType.LaserSemiActiveGuidance } ], LaserDesignatorConfigs = @@ -114,7 +118,7 @@ namespace ActiveProtect MaxIlluminationRange = 1000 } ], - SimulationTimeStep = 0.05 + SimulationTimeStep = 0.25 }; // 创建仿真管理器 diff --git a/SimulationEnvironment/SimulationConfig.cs b/SimulationEnvironment/SimulationConfig.cs index f83dc7e..f47e184 100644 --- a/SimulationEnvironment/SimulationConfig.cs +++ b/SimulationEnvironment/SimulationConfig.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using ActiveProtect.Models; namespace ActiveProtect.SimulationEnvironment @@ -55,9 +56,9 @@ namespace ActiveProtect.SimulationEnvironment public MissileDistanceParams DistanceParams { get; set; } public double ThrustAcceleration { get; set; } public double MaxEngineBurnTime { get; set; } + public double Mass { get; set; } public MissileType Type { get; set; } - public MissileConfig() { InitialPosition = new Vector3D(0, 0, 0); // 初始位 @@ -88,6 +89,16 @@ namespace ActiveProtect.SimulationEnvironment } } + public enum MissileType + { + StandardMissile, // 标准导弹 + LaserSemiActiveGuidance, // 激光半主动制导 + LaserBeamRiderGuidance, // 激光驾束制导 + InfraredCommandGuidance, // 红外指令制导 + InfraredImagingTerminalGuidance, // 红外成像末制导 + MillimeterWaveTerminalGuidance // 毫米波末制导 + } + public struct MissileDistanceParams(double terminalGuidanceDistance, double attackDistance, double explosionDistance) { public double TerminalGuidanceDistance { get; set; } = terminalGuidanceDistance; @@ -96,40 +107,62 @@ namespace ActiveProtect.SimulationEnvironment } /// - /// 导弹飞行阶段的配置结构 - /// - /// - /// 初始化飞行阶段配置 - /// - public struct FlightStageConfig(bool enableLaunch = true, bool enableAcceleration = true, bool enableCruise = true, + /// 导弹飞行的各个阶段 + /// + public enum FlightStage + { + Launch, // 发射阶段 + Acceleration, // 加速阶段 + Cruise, // 巡航阶段 + TerminalGuidance, // 终端制导阶段 + Attack, // 攻击阶段 + 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 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 StandardMissile => new(true, true, true, true, true); - /// - /// 激光制导炮弹的预设配置, 没有加速阶段 - /// - public static FlightStageConfig LaserGuidedShell => new(enableAcceleration: false); + /// + /// 激光半主动制导导弹的预设配置, 没有加速阶段 + /// + public static FlightStageConfig LaserSemiActiveGuidedMissile => new(true, false, true, true, true); - /// - /// 短程导弹的预设配置,没有巡航阶段 - /// - public static FlightStageConfig ShortRangeMissile => new(enableCruise: false); + /// + /// 激光驾束制导导弹的预设配置,没有巡航阶段 + /// + public static FlightStageConfig LaserBeamRiderGuidance => new(true, true, false, true, true); - /// - /// 激光半主动制导导弹的预设配置, 没有加速阶段 - /// - public static FlightStageConfig LaserSemiActiveGuidedMissile => new(enableAcceleration: false); - } + /// + /// 红外指令制导导弹的预设配置,没有巡航阶段 + /// + public static FlightStageConfig InfraredCommandGuidance => new(true, true, false, true, true); + + /// + /// 红外成像末制导导弹的预设配置 + /// + public static FlightStageConfig InfraredImagingTerminalGuidance => new(true, true, true, true, true); + + /// + /// 毫米波末制导导弹的预设配置 + /// + public static FlightStageConfig MillimeterWaveTerminalGuidance => new(true, true, true, true, true); } public class LaserWarnerConfig @@ -156,5 +189,5 @@ namespace ActiveProtect.SimulationEnvironment InitialJammingPower = 4000.0; PowerIncreaseRate = 2000.0; // 每秒增加的功率 } - + } } diff --git a/SimulationEnvironment/SimulationEvents.cs b/SimulationEnvironment/SimulationEvents.cs index 22520d1..1cc5bde 100644 --- a/SimulationEnvironment/SimulationEvents.cs +++ b/SimulationEnvironment/SimulationEvents.cs @@ -32,6 +32,17 @@ namespace ActiveProtect.SimulationEnvironment public string? TargetId { get; set; } } + public class LaserWarnerAlarmEvent : SimulationEvent + { + public string? TargetId { get; set; } + } + + public class LaserWarnerAlarmStopEvent : SimulationEvent + { + public string? TargetId { get; set; } + } + + public class EntityActivatedEvent : SimulationEvent { public string? ActivatedEntityId { get; set; } diff --git a/SimulationEnvironment/SimulationManager.cs b/SimulationEnvironment/SimulationManager.cs index 5f79ff8..ecd48c7 100644 --- a/SimulationEnvironment/SimulationManager.cs +++ b/SimulationEnvironment/SimulationManager.cs @@ -12,7 +12,6 @@ namespace ActiveProtect.SimulationEnvironment 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; @@ -89,7 +88,7 @@ namespace ActiveProtect.SimulationEnvironment Missile missile = missileConfig.Type switch { - MissileType.SemiActiveLaserGuidance => new LaserSemiActiveGuidedMissile( + MissileType.LaserSemiActiveGuidance => new LaserSemiActiveGuidedMissile( $"LSGM_{i + 1}", missileConfig, this @@ -107,7 +106,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}", "Tank_1", laserDesignatorConfig, this); + var laserDesignator = new LaserDesignator($"LD_{i + 1}", "Tank_1", "LSGM_4",laserDesignatorConfig, this); Elements.Add(laserDesignator); laserDesignator.ActivateLaser(); // 激活激光目标指示器 } @@ -128,37 +127,41 @@ namespace ActiveProtect.SimulationEnvironment public void SubscribeToEvent(Action handler) where T : SimulationEvent { var eventType = typeof(T); - if (!eventHandlers.ContainsKey(eventType)) + if (!eventHandlers.TryGetValue(eventType, out List? value)) { - eventHandlers[eventType] = new List(); + value = []; + eventHandlers[eventType] = value; } - eventHandlers[eventType].Add(handler); + + value.Add(handler); // 记录订阅关系 var element = Elements.FirstOrDefault(e => e.GetType().GetMethods().Any(m => m.Name == handler.Method.Name)); if (element != null) { - if (!elementSubscriptions.ContainsKey(element)) + if (!elementSubscriptions.TryGetValue(element, out List<(Type, Delegate)>? subscriptions)) { - elementSubscriptions[element] = new List<(Type, Delegate)>(); + subscriptions = []; + elementSubscriptions[element] = subscriptions; } - elementSubscriptions[element].Add((eventType, handler)); + + subscriptions.Add((eventType, handler as Delegate)); } } public void UnsubscribeFromEvent(Action handler) where T : SimulationEvent { var eventType = typeof(T); - if (eventHandlers.ContainsKey(eventType)) + if (eventHandlers.TryGetValue(eventType, out List? value)) { - eventHandlers[eventType].Remove(handler); + value.Remove(handler); } // 移除订阅关系记录 var element = Elements.FirstOrDefault(e => e.GetType().GetMethods().Any(m => m.Name == handler.Method.Name)); - if (element != null && elementSubscriptions.ContainsKey(element)) + if (element != null && elementSubscriptions.TryGetValue(element, out List<(Type, Delegate)>? subscriptions)) { - elementSubscriptions[element].RemoveAll(s => Delegate.Equals(s.Item2, handler)); + subscriptions.RemoveAll(s => Delegate.Equals(s.Item2, handler)); } } @@ -168,9 +171,9 @@ namespace ActiveProtect.SimulationEnvironment { foreach (var subscription in elementSubscriptions[element]) { - if (eventHandlers.ContainsKey(subscription.Item1)) + if (eventHandlers.TryGetValue(subscription.Item1, out List? value)) { - eventHandlers[subscription.Item1].Remove(subscription.Item2); + value.Remove(subscription.Item2); } } elementSubscriptions.Remove(element); @@ -247,7 +250,7 @@ namespace ActiveProtect.SimulationEnvironment { // 这里可以根据导弹类型、速度等因素计算伤害 // 现在我们简单地返回一个固定值 - return 100; + return 50; } private static void LogHitEvent(string targetId, string missileId, double damage)