ActiveProtect/Models/Missile.cs

315 lines
13 KiB
C#
Raw Blame History

using System;
using ActiveProtect.SimulationEnvironment;
namespace ActiveProtect.Models
{
/// <summary>
/// 表示仿真中的导弹
/// </summary>
public class Missile : SimulationElement
{
/// <summary>
/// 导弹类型
/// </summary>
public MissileType Type { get; protected set; }
/// <summary>
/// 导弹飞行的各个阶段
/// </summary>
public enum FlightStage
{
Launch, // 发射阶段
Acceleration, // 加速阶段
Cruise, // 巡航阶段
TerminalGuidance, // 终端制导阶段
Attack, // 攻击阶段
Explosion // 爆炸阶段
}
/// <summary>
/// 导弹飞行阶段的配置结构
/// </summary>
/// <remarks>
/// 初始化飞行阶段配置
/// </remarks>
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;
/// <summary>
/// 标准导弹的预设配置, 所有阶段都启用
/// </summary>
public static FlightStageConfig StandardMissile => new(enableLaunch: true, enableAcceleration: true, enableCruise: true, enableTerminalGuidance: true, enableAttack: true);
/// <summary>
/// 激光制导炮弹的预设配置, 没有加速阶段
/// </summary>
public static FlightStageConfig LaserGuidedShell => new(enableAcceleration: false);
/// <summary>
/// 短程导弹的预设配置,没有巡航阶段
/// </summary>
public static FlightStageConfig ShortRangeMissile => new(enableCruise: false);
/// <summary>
/// 激光半主动制导导弹的预设配置, 没有加速阶段
/// </summary>
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 ? "超出最大飞行距<E8A18C><E8B79D><EFBFBD>" :
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;
}
}