commit edfead8927b1dcd75cc55a2ef0ed1b7e94d89614 Author: Tian jianyong <11429339@qq.com> Date: Sun Oct 6 09:09:32 2024 +0800 创建项目,添加基础类 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2b97d60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +# 构建结果 +[Bb]in/ +[Oo]bj/ +[Ll]ib/ + +# Visual Studio 文件 +.vs/ +*.user +*.userosscache +*.suo +*.userprefs + +# 编译文件 +*.dll +*.exe +*.pdb + +# 日志文件 +*.log + +# 临时文件 +[Tt]emp/ +[Tt]mp/ + +# 缓存文件 +*.cache +*.bak + +# 测试结果 +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NuGet包 +*.nupkg +**/packages/* +!**/packages/build/ + +# Visual Studio Code 设置 +.vscode/ + +# Rider 设置 +.idea/ + +# 操作系统文件 +.DS_Store +Thumbs.db + +# 其他 +*.swp +*.*~ +project.lock.json \ No newline at end of file diff --git a/ActiveProtect.csproj b/ActiveProtect.csproj new file mode 100644 index 0000000..206b89a --- /dev/null +++ b/ActiveProtect.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/ActiveProtect.sln b/ActiveProtect.sln new file mode 100644 index 0000000..414cdb7 --- /dev/null +++ b/ActiveProtect.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ActiveProtect", "ActiveProtect.csproj", "{7F47A2C7-1087-440B-82F7-A1BF50D30A1B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7F47A2C7-1087-440B-82F7-A1BF50D30A1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {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 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {73773200-50D4-40ED-803B-FC16B131FFD2} + EndGlobalSection +EndGlobal diff --git a/Environment/ISimulatinManager.cs b/Environment/ISimulatinManager.cs new file mode 100644 index 0000000..2daa4a3 --- /dev/null +++ b/Environment/ISimulatinManager.cs @@ -0,0 +1,7 @@ +using ActiveProtect.Models; + +public interface ISimulationManager +{ + Vector3D GetElementPosition(string elementId); + // 添加其他必要的方法 +} diff --git a/Environment/SimulationConfig.cs b/Environment/SimulationConfig.cs new file mode 100644 index 0000000..290d687 --- /dev/null +++ b/Environment/SimulationConfig.cs @@ -0,0 +1,71 @@ +using ActiveProtect.Models; + +namespace ActiveProtect.SimulationEnvironment +{ + public class SimulationConfig + { + public List TankConfigs { get; set; } + public List MissileConfigs { get; set; } + public double SimulationTimeStep { get; set; } + + public SimulationConfig() + { + TankConfigs = []; + MissileConfigs = []; + SimulationTimeStep = 0.1; // 默认时间步长为0.1秒 + } + } + + public class TankConfig + { + public Vector3D InitialPosition { get; set; } + public Orientation InitialOrientation { get; set; } + public double InitialSpeed { get; set; } + public double MaxSpeed { get; set; } + public double MaxArmor { get; set; } + + public TankConfig() + { + InitialPosition = new Vector3D(0, 0, 0); + InitialOrientation = new Orientation(0, 0, 0); + } + } + + public class MissileConfig + { + public Vector3D InitialPosition { get; set; } + public Orientation InitialOrientation { get; set; } + public double InitialSpeed { get; set; } + public double MaxSpeed { get; set; } + public int TargetIndex { get; set; } + public double MaxFlightTime { get; set; } + public double MaxFlightDistance { get; set; } + public double MaxAcceleration { get; set; } + public double ProportionalNavigationCoefficient { get; set; } + public Missile.FlightStageConfig StageConfig { get; set; } + public MissileDistanceParams DistanceParams { get; set; } + public MissileType Type { get; set; } + + // 新增属性 + public double ThrustAcceleration { get; set; } + public double MaxEngineBurnTime { get; set; } + + public MissileConfig() + { + InitialPosition = new Vector3D(0, 0, 0); // 初始位置 + InitialOrientation = new Orientation(0, 0, 0); // 初始方向 + InitialSpeed = 0; // 初始速度 + MaxSpeed = 0; // 最大速度 + TargetIndex = 0; // 目标索引 + MaxFlightTime = 0; // 最大飞行时间 + MaxFlightDistance = 0; // 最大飞行距离 + StageConfig = Missile.FlightStageConfig.StandardMissile; // 飞行阶段配置 + ThrustAcceleration = 0; // 推力加速度 + MaxEngineBurnTime = 0; // 最大发动机燃烧时间 + MaxAcceleration = 0; // 最大加速度 + DistanceParams = new MissileDistanceParams(0, 0, 0); // 距离参数 + ProportionalNavigationCoefficient = 0; // 比例导引系数 + Type = MissileType.StandardMissile; // 导弹类型 + } + } +} diff --git a/Environment/SimulationElement.cs b/Environment/SimulationElement.cs new file mode 100644 index 0000000..f642c0b --- /dev/null +++ b/Environment/SimulationElement.cs @@ -0,0 +1,18 @@ +using ActiveProtect.Models; + +namespace ActiveProtect.SimulationEnvironment +{ + public abstract class SimulationElement(string id, Vector3D position, Orientation orientation) + { + public string Id { get; set; } = id; + public Vector3D Position { get; set; } = position; + public Orientation Orientation { get; set; } = orientation; + + public abstract void Update(double deltaTime); + + public virtual string GetStatus() + { + return $"{GetType().Name} {Id} at {Position}, Orientation: {Orientation}"; + } + } +} diff --git a/Environment/SimulationManager.cs b/Environment/SimulationManager.cs new file mode 100644 index 0000000..6929662 --- /dev/null +++ b/Environment/SimulationManager.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ActiveProtect.Models; + +namespace ActiveProtect.SimulationEnvironment +{ + 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; + + public SimulationManager(SimulationConfig config) + { + this.config = config; + Elements = []; + CurrentTime = 0; + IsSimulationEnded = false; + InitializeSimulation(); + } + + 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.InitialPosition, + tankConfig.InitialOrientation, + tankConfig.InitialSpeed, + tankConfig.MaxSpeed, + tankConfig.MaxArmor + )); + } + + // 创建导弹(修改这部分) + for (int i = 0; i < config.MissileConfigs.Count; i++) + { + var missileConfig = config.MissileConfigs[i]; + Missile missile = missileConfig.Type switch + { + MissileType.SemiActiveLaserGuidance => new LaserSemiActiveGuidedMissile( + $"LSGM_{i + 1}", + missileConfig.InitialPosition, + missileConfig.InitialOrientation, + missileConfig.InitialSpeed, + missileConfig.MaxSpeed, + $"Tank_{missileConfig.TargetIndex + 1}", + missileConfig.MaxFlightTime, + missileConfig.MaxFlightDistance, + missileConfig.DistanceParams, + missileConfig.StageConfig, + this, + missileConfig.ThrustAcceleration, + missileConfig.MaxEngineBurnTime, + missileConfig.MaxAcceleration, + missileConfig.ProportionalNavigationCoefficient + ), + _ => new Missile( + $"NM_{i + 1}", + missileConfig.InitialPosition, + missileConfig.InitialOrientation, + missileConfig.InitialSpeed, + missileConfig.MaxSpeed, + $"Tank_{missileConfig.TargetIndex + 1}", + missileConfig.MaxFlightTime, + missileConfig.MaxFlightDistance, + missileConfig.DistanceParams, + missileConfig.StageConfig, + this, + missileConfig.ThrustAcceleration, + missileConfig.MaxEngineBurnTime, + missileConfig.MaxAcceleration, + missileConfig.ProportionalNavigationCoefficient + ), + }; + Elements.Add(missile); + } + } + + public void Update() + { + if (IsSimulationEnded) return; + + CurrentTime += config.SimulationTimeStep; + + foreach (var element in Elements.ToList()) + { + element.Update(config.SimulationTimeStep); + } + + // 移除不活跃的元素 + Elements.RemoveAll(e => (e is Tank tank && !tank.IsActive) || (e is Missile missile && !missile.IsActive)); + + // 检查是否所有导弹都结束飞行 + if (!Elements.Any(e => e is Missile)) + { + EndSimulation(); + } + } + + public void PrintStatus() + { + Console.WriteLine($"仿真时间: {CurrentTime:F2}"); + foreach (var element in Elements) + { + Console.WriteLine(element.GetStatus()); + } + Console.WriteLine(); + } + + private void EndSimulation() + { + IsSimulationEnded = true; + Console.WriteLine("仿真结束"); + Console.WriteLine($"总仿真时间: {CurrentTime:F2} 秒"); + 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"); + } + } +} \ No newline at end of file diff --git a/Models/Common.cs b/Models/Common.cs new file mode 100644 index 0000000..c9ed4f8 --- /dev/null +++ b/Models/Common.cs @@ -0,0 +1,151 @@ +using System; + +namespace ActiveProtect.Models +{ + public class Vector3D(double x, double y, double z) + { + public double X { get; set; } = x; + public double Y { get; set; } = y; + public double Z { get; set; } = z; + + public static double Distance(Vector3D v1, Vector3D v2) + { + return Math.Sqrt(Math.Pow(v1.X - v2.X, 2) + Math.Pow(v1.Y - v2.Y, 2) + Math.Pow(v1.Z - v2.Z, 2)); + } + + public static Vector3D Zero => new(0, 0, 0); + + public override string ToString() + { + return $"({X:F2}, {Y:F2}, {Z:F2})"; + } + + public static Vector3D operator -(Vector3D a, Vector3D b) + { + return new Vector3D(a.X - b.X, a.Y - b.Y, a.Z - b.Z); + } + + public static Vector3D operator +(Vector3D a, Vector3D b) + { + return new Vector3D(a.X + b.X, a.Y + b.Y, a.Z + b.Z); + } + + public static Vector3D operator *(Vector3D a, double scalar) + { + return new Vector3D(a.X * scalar, a.Y * scalar, a.Z * scalar); + } + + public static Vector3D operator /(Vector3D a, double scalar) + { + return new Vector3D(a.X / scalar, a.Y / scalar, a.Z / scalar); + } + + public double Magnitude() + { + return Math.Sqrt(X * X + Y * Y + Z * Z); + } + + public double MagnitudeSquared() + { + return X * X + Y * Y + Z * Z; + } + + public Vector3D Normalize() + { + double mag = Magnitude(); + if (mag > 0) + { + return new Vector3D(X / mag, Y / mag, Z / mag); + } + return new Vector3D(0, 0, 0); + } + + public static Vector3D CrossProduct(Vector3D a, Vector3D b) + { + return new Vector3D( + a.Y * b.Z - a.Z * b.Y, + a.Z * b.X - a.X * b.Z, + a.X * b.Y - a.Y * b.X + ); + } + + public static double DotProduct(Vector3D a, Vector3D b) + { + return a.X * b.X + a.Y * b.Y + a.Z * b.Z; + } + } + + public struct Orientation(double yaw, double pitch, double roll) + { + public double Yaw { get; set; } = yaw; + public double Pitch { get; set; } = pitch; + public double Roll { get; set; } = roll; + + public override readonly string ToString() + { + return $"(Yaw: {Yaw:F2}, Pitch: {Pitch:F2}, Roll: {Roll:F2})"; + } + + public void Normalize() + { + Yaw = NormalizeAngle(Yaw); + Pitch = NormalizeAngle(Pitch); + Roll = NormalizeAngle(Roll); + } + + private static double NormalizeAngle(double angle) + { + while (angle > Math.PI) angle -= 2 * Math.PI; + while (angle <= -Math.PI) angle += 2 * Math.PI; + return angle; + } + + public static Orientation LookAt(Vector3D direction) + { + double yaw = Math.Atan2(direction.Z, direction.X); + double pitch = Math.Atan2(direction.Y, Math.Sqrt(direction.X * direction.X + direction.Z * direction.Z)); + return new Orientation(yaw, pitch, 0); + } + + public readonly Vector3D ToVector() + { + double cosYaw = Math.Cos(Yaw); + double sinYaw = Math.Sin(Yaw); + double cosPitch = Math.Cos(Pitch); + double sinPitch = Math.Sin(Pitch); + + return new Vector3D( + cosYaw * cosPitch, + sinPitch, + sinYaw * cosPitch + ); + } + + public static Orientation FromVector(Vector3D vector) + { + Vector3D normalized = vector.Normalize(); + double pitch = Math.Asin(normalized.Y); + double yaw; + if (Math.Abs(normalized.Y) > 0.9999) // 接近垂直 + { + yaw = 0; // 或者保持之前的偏航角 + } + else + { + yaw = Math.Atan2(normalized.Z, normalized.X); + } + return new Orientation(yaw, pitch, 0); + } + } + + public enum MissileType + { + StandardMissile, // 标准导弹 + SemiActiveLaserGuidance, // 半主动激光制导 + LaserBeamRiderGuidance, // 激光束制导 + InfraredCommandGuidance, // 红外指令制导 + ImagingInfraredTerminalGuidance, // 成像红外终端制导 + MillimeterWaveTerminalGuidance // 毫米波终端制导 + } + +} diff --git a/Models/LaserSemiActiveGuidedMissile.cs b/Models/LaserSemiActiveGuidedMissile.cs new file mode 100644 index 0000000..7337f64 --- /dev/null +++ b/Models/LaserSemiActiveGuidedMissile.cs @@ -0,0 +1,53 @@ +using ActiveProtect.SimulationEnvironment; + +namespace ActiveProtect.Models +{ + public class LaserSemiActiveGuidedMissile : Missile + { + // 激光半主动制导导弹的特殊属性 + public bool IsLaserLocked { get; private set; } = false; + + public LaserSemiActiveGuidedMissile( + string id, + Vector3D position, + Orientation orientation, + double initialSpeed, + double maxSpeed, + string targetId, + double maxFlightTime, + double maxFlightDistance, + MissileDistanceParams distanceParams, + FlightStageConfig stageConfig, + ISimulationManager simulationManager, + double thrustAcceleration, + double maxEngineBurnTime, + double maxAcceleration, + double proportionalNavigationCoefficient) + : base(id, position, orientation, initialSpeed, maxSpeed, targetId, maxFlightTime, maxFlightDistance, + distanceParams, stageConfig, simulationManager, thrustAcceleration, maxEngineBurnTime, maxAcceleration, proportionalNavigationCoefficient) + { + Type = MissileType.SemiActiveLaserGuidance; + } + + public override void Update(double deltaTime) + { + base.Update(deltaTime); + + // 激光半主动制导导弹的特殊更新逻辑 + UpdateLaserLock(); + } + + private void UpdateLaserLock() + { + // 这里实现激光锁定逻辑 + // 例如,根据距离和其他因素来决定是否锁定目标 + IsLaserLocked = DistanceToTarget < DistanceParams.TerminalGuidanceDistance; + } + + public override string GetStatus() + { + return base.GetStatus().Replace("导弹", "激光半主动制导导弹") + + $"\n 激光锁定: {(IsLaserLocked ? "是" : "否")}"; + } + } +} diff --git a/Models/Missile.cs b/Models/Missile.cs new file mode 100644 index 0000000..2e87931 --- /dev/null +++ b/Models/Missile.cs @@ -0,0 +1,315 @@ +using System; +using ActiveProtect.SimulationEnvironment; + +namespace ActiveProtect.Models +{ + /// + /// 表示仿真中的导弹 + /// + public class Missile : SimulationElement + { + /// + /// 导弹类型 + /// + public MissileType Type { get; protected set; } + + /// + /// 导弹飞行的各个阶段 + /// + 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 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; } + public string TargetId { get; protected set; } + public double MaxFlightTime { get; protected set; } + public double MaxFlightDistance { get; protected set; } + public double FlightTime { get; protected set; } + public double FlightDistance { get; protected set; } + 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 bool IsActive { get; protected set; } + + protected Vector3D Velocity; + private Vector3D LastTargetPosition; + private const double N = 3; // 比例导引系数 + + private readonly ISimulationManager _simulationManager; + + public double ThrustAcceleration { get; protected set; } + public double EngineBurnTime { get; protected set; } + public double MaxEngineBurnTime { get; protected set; } + + public double MaxAcceleration { get; protected set; } = 100; // m/s^2 + + public double ProportionalNavigationCoefficient { get; set; } + + public Missile(string id, Vector3D position, Orientation orientation, double initialSpeed, double maxSpeed, + string targetId, double maxFlightTime, double maxFlightDistance, + MissileDistanceParams distanceParams, + FlightStageConfig stageConfig, + ISimulationManager simulationManager, + double thrustAcceleration, double maxEngineBurnTime, double maxAcceleration, + double proportionalNavigationCoefficient) + : base(id, position, orientation) + { + Speed = initialSpeed; + MaxSpeed = maxSpeed; + TargetId = targetId; + MaxFlightTime = maxFlightTime; + MaxFlightDistance = maxFlightDistance; + DistanceParams = distanceParams; + StageConfig = stageConfig; + IsActive = true; + FlightTime = 0; + FlightDistance = 0; + _simulationManager = simulationManager; + ThrustAcceleration = thrustAcceleration; + EngineBurnTime = 0; + MaxEngineBurnTime = maxEngineBurnTime; + MaxAcceleration = maxAcceleration; + Vector3D horizontalDirection = new Vector3D(orientation.ToVector().X, 0, orientation.ToVector().Z).Normalize(); + Velocity = horizontalDirection * initialSpeed; + + // 设置初始阶段 + CurrentStage = StageConfig.EnableLaunch ? FlightStage.Launch : + StageConfig.EnableAcceleration ? FlightStage.Acceleration : + StageConfig.EnableCruise ? FlightStage.Cruise : + StageConfig.EnableTerminalGuidance ? FlightStage.TerminalGuidance : + StageConfig.EnableAttack ? FlightStage.Attack : FlightStage.Cruise; + + Console.WriteLine($"导弹 {Id} 的初始阶: {CurrentStage}"); + + LastTargetPosition = position; // 初始化 LastTargetPosition + ProportionalNavigationCoefficient = proportionalNavigationCoefficient; + } + + public override void Update(double deltaTime) + { + if (!IsActive) return; + + // 更新发动机燃烧时间 + UpdateEngineBurnTime(deltaTime); + + // 使用 RK4 方法更新导弹状态 + Vector3D k1, k2, k3, k4; + Vector3D v1, v2, v3, v4; + + (k1, v1) = CalculateDerivatives(Position, Velocity, deltaTime); + (k2, v2) = CalculateDerivatives(Position + k1 * (deltaTime / 2), Velocity + v1 * (deltaTime / 2), deltaTime / 2); + (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); + + // 更新其他状态 + Speed = Velocity.Magnitude(); + if (Speed > MaxSpeed) + { + Speed = MaxSpeed; + Velocity = Velocity.Normalize() * MaxSpeed; + } + + Orientation = Orientation.FromVector(Velocity); + FlightTime += deltaTime; + FlightDistance += Speed * deltaTime; + + UpdateDistanceToTarget(Vector3D.Distance(Position, _simulationManager.GetElementPosition(TargetId))); + + // 首先检查是否命中目标 + if (CheckHit()) + { + Explode(); + return; + } + + // 然后检查是否应该自毁 + if (ShouldSelfDestruct()) + { + SelfDestruct(); + return; + } + + // 更新飞行阶段 + UpdateFlightStage(); + } + + private bool CheckHit() + { + return DistanceToTarget <= DistanceParams.ExplosionDistance; + } + + private bool ShouldSelfDestruct() + { + return FlightTime >= MaxFlightTime || FlightDistance >= MaxFlightDistance || Position.Y <= 0; + } + + private void UpdateEngineBurnTime(double deltaTime) + { + if (CurrentStage == FlightStage.Acceleration && EngineBurnTime < MaxEngineBurnTime) + { + EngineBurnTime += deltaTime; + } + } + + private (Vector3D, Vector3D) CalculateDerivatives(Vector3D position, Vector3D velocity, double deltaTime) + { + Vector3D targetPosition = _simulationManager.GetElementPosition(TargetId); + Vector3D LOS = targetPosition - position; + Vector3D LOSRate = (targetPosition - LastTargetPosition) / deltaTime - velocity; + Vector3D guidanceAcceleration = Vector3D.CrossProduct(Vector3D.CrossProduct(LOS, LOSRate), LOS).Normalize() + * ProportionalNavigationCoefficient * velocity.Magnitude(); + 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; + } + } + + public void UpdateDistanceToTarget(double distance) + { + DistanceToTarget = distance; + } + + public void Explode() + { + IsActive = false; + Console.WriteLine($"导弹 {Id} 在 {Position} 爆炸,命中目标!"); + } + + public void SelfDestruct() + { + IsActive = false; + string reason = FlightTime >= MaxFlightTime ? "超出最大飞行时间" : + FlightDistance >= MaxFlightDistance ? "超出最大飞行距���" : + Position.Y <= 0 ? "高度小于等于0" : "未知原因"; + + Console.WriteLine($"导弹 {Id} 自毁。原因: {reason}"); + } + + 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}"; + } + + public void SetProportionalNavigationCoefficient(double newCoefficient) + { + ProportionalNavigationCoefficient = newCoefficient; + Console.WriteLine($"导弹 {Id} 的比例导引系数已更新为 {newCoefficient}"); + } + } + + public struct MissileDistanceParams(double terminalGuidanceDistance, double attackDistance, double explosionDistance) + { + public double TerminalGuidanceDistance { get; set; } = terminalGuidanceDistance; + public double AttackDistance { get; set; } = attackDistance; + public double ExplosionDistance { get; set; } = explosionDistance; + } +} \ No newline at end of file diff --git a/Models/Tank.cs b/Models/Tank.cs new file mode 100644 index 0000000..645fa8d --- /dev/null +++ b/Models/Tank.cs @@ -0,0 +1,40 @@ +using ActiveProtect.SimulationEnvironment; + +namespace ActiveProtect.Models +{ + public class Tank(string id, Vector3D position, Orientation orientation, double initialSpeed, double maxSpeed, double maxArmor) : SimulationElement(id, position, orientation) + { + public double Speed { get; set; } = initialSpeed; + public bool IsActive { get; private set; } = true; + public double MaxSpeed { get; private set; } = maxSpeed; + public double MaxArmor { get; private set; } = maxArmor; + public double Armor { get; private set; } = maxArmor; + public double CurrentArmor { get; private set; } = maxArmor; + + public override void Update(double deltaTime) + { + if (!IsActive) return; + + Position.X += Speed * Math.Cos(Orientation.Yaw) * Math.Cos(Orientation.Pitch) * deltaTime; + Position.Y += Speed * Math.Sin(Orientation.Pitch) * deltaTime; + Position.Z += Speed * Math.Sin(Orientation.Yaw) * Math.Cos(Orientation.Pitch) * deltaTime; + } + + public void TakeDamage(double damage) + { + CurrentArmor -= damage; + if (CurrentArmor <= 0) + { + CurrentArmor = 0; + IsActive = false; + } + } + + public override string GetStatus() + { + return $"坦克 {Id}:\n" + + $" 位置: X={Position.X:F2}, Y={Position.Y:F2}, Z={Position.Z:F2}\n" + + $" 装甲: {CurrentArmor:F2}"; + } + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..8bb23e0 --- /dev/null +++ b/Program.cs @@ -0,0 +1,114 @@ +using System; +using System.Threading; +using ActiveProtect.SimulationEnvironment; +using ActiveProtect.Models; + +namespace ActiveProtect +{ + class Program + { + static void Main(string[] args) + { + // 创建仿真配置 + var config = new SimulationConfig + { + TankConfigs = + [ + new() { + InitialPosition = new Vector3D(100, 0, 100), + InitialOrientation = new Orientation(0, 0, 0), + InitialSpeed = 0, + MaxSpeed = 20, + MaxArmor = 100 + } + ], + MissileConfigs = + [ + // 标准导弹配置 + new() { + InitialPosition = new Vector3D(1500, 200, 100), + InitialOrientation = new Orientation(Math.PI, -0.1, 0), + InitialSpeed = 10, + MaxSpeed = 400, + TargetIndex = 0, + MaxFlightTime = 0, + MaxFlightDistance = 5000, + ThrustAcceleration = 80, + MaxEngineBurnTime = 5, + MaxAcceleration = 100, + ProportionalNavigationCoefficient = 3, + StageConfig = Missile.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, + MaxFlightDistance = 5000, + ThrustAcceleration = 50, + MaxEngineBurnTime = 5, + MaxAcceleration = 100, + ProportionalNavigationCoefficient = 3, + StageConfig = Missile.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, + MaxSpeed = 300, + TargetIndex = 0, + MaxFlightTime = 0, + MaxFlightDistance = 3000, + ThrustAcceleration = 50, + MaxEngineBurnTime = 5, + MaxAcceleration = 100, + ProportionalNavigationCoefficient = 3, + StageConfig = Missile.FlightStageConfig.ShortRangeMissile, + DistanceParams = new MissileDistanceParams(400, 100, 20), + Type = MissileType.MillimeterWaveTerminalGuidance + }, + // 新增激光半主动制导导弹配置 + new() { + InitialPosition = new Vector3D(2000, 150, 100), + InitialOrientation = new Orientation(Math.PI, -0.12, 0), + InitialSpeed = 700, + MaxSpeed = 800, + TargetIndex = 0, + MaxFlightTime = 20, + MaxFlightDistance = 4500, + ThrustAcceleration = 50, + MaxEngineBurnTime = 5, + MaxAcceleration = 100, + ProportionalNavigationCoefficient = 3, + StageConfig = Missile.FlightStageConfig.LaserSemiActiveGuidedMissile, + DistanceParams = new MissileDistanceParams(500, 200, 20), + Type = MissileType.SemiActiveLaserGuidance + } + ], + SimulationTimeStep = 0.05 + }; + + // 创建仿真管理器 + var simulationManager = new SimulationManager(config); + + // 运行仿真 + while (!simulationManager.IsSimulationEnded) + { + simulationManager.Update(); + simulationManager.PrintStatus(); + Thread.Sleep(100); // 暂停100毫秒,使输出更易读 + } + + Console.WriteLine("仿真结束"); + } + + } +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c866420 --- /dev/null +++ b/README.md @@ -0,0 +1,169 @@ +# ActiveProtect 仿真系统 + +## 项目概述 + +ActiveProtect 是一个复杂的军事仿真系统,旨在模拟导弹和坦克之间的交互。该系统能够模拟三维空间中的运动,考虑天气、地形等环境因素,并评估防御系统的有效性。 + +## 主要功能 + +1. 三维空间仿真:使用 Vector3D 和 Orientation 结构精确模拟物体在三维空间中的位置和方向。 +2. 导弹和坦克模拟:包括运动、攻击和防御逻辑。 +3. 环境因素:考虑天气和地形对仿真的影响。 +4. 数据收集与分析:实时收集仿真数据,并进行后续分析。 +5. 评估模型:评估仿真结果,计算各种性能指标。 +6. 可视化和报告:生成数据可视化和评估报告。 + +## 核心组件 + +1. SimulationElement: 所有仿真元素的基类。 +2. Tank 和 Missile: 继承自 SimulationElement,实现具体的坦克和导弹逻辑。 +3. SimulationManager: 管理整个仿真过程。 +4. SimulationConfig: 用于配置仿真参数。 +5. DataCollector: 收集仿真数据。 +6. EvaluationModel: 评估仿真结果。 +7. Weather 和 Terrain: 模拟环境因素。 + +## 使用方法 + +1. 配置仿真参数: + ```csharp + var config = new SimulationConfig + { + // 设置坦克、导弹、环境等参数 + }; + ``` + +2. 创建并运行仿真: + ```csharp + var simulationManager = new SimulationManager(config); + simulationManager.RunSimulation(); + ``` + +3. 分析结果: + ```csharp + var evaluationResult = simulationManager.EvaluateSimulation(); + var report = ReportGenerator.GenerateReport(evaluationResult); + ``` + +## 未来改进 + +1. 实现更复杂的导弹追踪算法。 +2. 添加更多类型的防御系统。 +3. 改进环境模拟的真实性。 +4. 开发图形用户界面以便更直观地配置和运行仿真。 + +## 贡献 + +欢迎提交 Pull Requests 来改进这个项目。在提交之前,请确保您的代码符合项目的编码规范,并且通过了所有的单元测试。 + +## 许可证 + +本项目采用 MIT 许可证。详情请见 [LICENSE](LICENSE) 文件。 + +## 仿真运行流程(这个 Mermaid 图表会在支持 Mermaid 的 Markdown 查看器中渲染为一个流程图) + +```mermaid +graph TD + A[开始仿真] --> B[初始化SimulationManager] + B --> C[加载SimulationConfig] + C --> D[创建仿真元素] + D --> E[开始仿真循环] + E --> F{是否结束仿真?} + F -->|否| G[更新所有元素] + G --> H[收集数据] + H --> I[处理事件] + I --> E + F -->|是| J[结束仿真] + J --> K[评估结果] + K --> L[生成报告] + L --> M[结束] +``` + +# 反坦克导弹仿真系统 + +本项目旨在模拟反坦克导弹的飞行过程和攻击效果。 + +## 反坦克导弹飞行阶段 + +反坦克导弹的飞行过程通常可以分为以下几个主要阶段: + +1. 发射阶段 + - 导弹从发射装置或发射管中被推出 + - 火箭发动机点火,提供初始推力 + +2. 加速阶段 + - 导弹迅速加速到巡航速度 + - 可能会抛掉一些辅助推进装置(如有) + +3. 巡航阶段 + - 导弹保持相对稳定的速度飞向目标 + - 根据导引系统类型,可能会进行中途修正 + +4. 终端制导阶段 + - 导弹接近目标,进入最后的制导阶段 + - 可能会启动终端制导系统,如毫米波雷达或红外成像系统 + +5. 攻击阶段 + - 导弹进行最后的机动,以最佳角度接近目标 + - 可能会启动穿甲弹头或预制破片 + +6. 爆炸阶段 + - 导弹击中目标并引爆 + - 根据弹头类型,可能是穿甲、破片或破片-燃烧等效果 + +在仿真中,这些阶段被纳入计算,每个阶段可能有不同的物理特性和行为模式。例如,加速阶段可能有较大的加速度,而巡航阶段则保持恒定速度。终端制导阶段可能会有更频繁的方向调整。 + +## 项目结构 + +``` +ActiveProtect/ +├── Program.cs # 主程序入口 +├── SimulationEnvironment/ # 仿真环境相关类 +│ ├── SimulationManager.cs # 仿真管理器 +│ └── SimulationConfig.cs # 仿真配置 +├── Models/ # 模型类 +│ ├── Tank.cs # 坦克模型 +│ ├── Missile.cs # 导弹模型 +│ ├── Vector3D.cs # 3D向量 +│ └── Orientation.cs # 方向类 +└── ActiveProtect.csproj # 项目文件 +``` + +## 如何运行 + +1. 确保你的系统已安装 .NET 8.0 或更高版本。 +2. 在终端中导航到项目根目录。 +3. 运行以下命令来构建项目: + ``` + dotnet build + ``` +4. 运行以下命令来启动仿真: + ``` + dotnet run + ``` + +## 注意事项 + +- 当前仿真使用简化模型,可能无法完全反映真实世界的复杂性。 +- 仿真结果仅供参考,不应用于实际军事决策。 + +## 比例导引系数(N)的选择 + +在导弹制导系统中,比例导引系数(N)是一个关键参数,它直接影响导弹的性能和行为。在我们的仿真系统中,用户可以根据不同的场景需求调整这个参数。 + +### N 值的影响 + +- **N = 3**:这是一个较为保守的选择,适合大多数情况。它提供了良好的稳定性和能源效率,但可能在应对高机动性目标时表现不佳。 +- **N = 4**:这个值提供了更积极的制导,适合需要更高机动性的场景。它能更快地响应目标的变化,但可能会增加能源消耗。 +- **N = 5**:这是一个更激进的选择,提供最高的机动性,但也带来了更大的能源消耗和可能的过度修正。 + +### 选择 N 值的考虑因素 + +1. **导弹类型**:大型、长程导弹通常使用较小的 N 值,而小型、短程导弹可以使用较大的 N 值。 +2. **目标特性**:对付高速、高机动性目标时,可能需要较大的 N 值。 +3. **作战环境**:在复杂环境中,可能需要更大的 N 值来应对突发情况。 +4. **能源限制**:如果导弹燃料有限,较小的 N 值可以帮助节省能源。 +5. **制导系统精度**:精度较高的系统可以使用较小的 N 值,而精度较低的系统可能需要较大的 N 值来补偿误差。 +6. **任务要求**:精确打击任务可能需要较大的 N 值,而区域防御任务可能使用较小的 N 值。 + +在我们的仿真系统中,用户可以通过调整 `ProportionalNavigationCoefficient` 参数来设置不同的 N 值,以模拟各种实际情况下的导弹行为。我们建议用户尝试不同的 N 值,观察其对导弹性能的影响,以找到最适合特定场景的设置。