315 lines
13 KiB
C#
315 lines
13 KiB
C#
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;
|
||
}
|
||
} |