342 lines
14 KiB
C#
342 lines
14 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 // 爆炸阶段
|
|
}
|
|
|
|
|
|
|
|
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; // 比例导引系数
|
|
|
|
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 bool IsGuidanceLost { get; protected set; } = false;
|
|
protected double LostGuidanceTime { get; set; } = 0;
|
|
protected const double MaxLostGuidanceTime = 1.0; // 1秒后自毁
|
|
|
|
public Missile(string id, MissileConfig missileConfig, ISimulationManager simulationManager)
|
|
: base(id, missileConfig.InitialPosition, missileConfig.InitialOrientation, simulationManager)
|
|
{
|
|
Speed = missileConfig.InitialSpeed;
|
|
MaxSpeed = missileConfig.MaxSpeed;
|
|
MaxFlightTime = missileConfig.MaxFlightTime;
|
|
MaxFlightDistance = missileConfig.MaxFlightDistance;
|
|
DistanceParams = missileConfig.DistanceParams;
|
|
StageConfig = missileConfig.StageConfig;
|
|
IsActive = true;
|
|
FlightTime = 0;
|
|
FlightDistance = 0;
|
|
SimulationManager = simulationManager;
|
|
ThrustAcceleration = missileConfig.ThrustAcceleration;
|
|
EngineBurnTime = 0;
|
|
MaxEngineBurnTime = missileConfig.MaxEngineBurnTime;
|
|
MaxAcceleration = missileConfig.MaxAcceleration;
|
|
ProportionalNavigationCoefficient = missileConfig.ProportionalNavigationCoefficient;
|
|
TargetId = $"Tank_{missileConfig.TargetIndex + 1}";
|
|
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;
|
|
|
|
Console.WriteLine($"导弹 {Id} 的初始阶: {CurrentStage}");
|
|
|
|
LastTargetPosition = Position; // 初始化 LastTargetPosition
|
|
|
|
// 订阅相关事件
|
|
simulationManager.SubscribeToEvent<LaserIlluminationEvent>(OnLaserIllumination);
|
|
simulationManager.SubscribeToEvent<LaserIlluminationStopEvent>(OnLaserIlluminationStop);
|
|
}
|
|
|
|
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.GetEntityById(TargetId).Position));
|
|
|
|
// 首先检查是否命中目标
|
|
if (CheckHit())
|
|
{
|
|
Explode();
|
|
return;
|
|
}
|
|
|
|
// 然后检查是否应该自毁
|
|
if (ShouldSelfDestruct())
|
|
{
|
|
SelfDestruct();
|
|
return;
|
|
}
|
|
|
|
// 更新飞行阶段
|
|
UpdateFlightStage();
|
|
|
|
if (IsGuidanceLost)
|
|
{
|
|
HandleLostGuidance(deltaTime);
|
|
}
|
|
else
|
|
{
|
|
// 重置失去引导的时间
|
|
LostGuidanceTime = 0;
|
|
}
|
|
|
|
// 发布事件示例
|
|
if (CurrentStage == FlightStage.Launch)
|
|
{
|
|
PublishEvent(new MissileFireEvent { TargetId = TargetId });
|
|
}
|
|
}
|
|
|
|
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.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();
|
|
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;
|
|
SimulationManager.HandleTargetHit(TargetId, Id);
|
|
Console.WriteLine($"导弹 {Id} 在 {Position} 爆炸,命中目标!");
|
|
}
|
|
|
|
public void SelfDestruct()
|
|
{
|
|
IsActive = false;
|
|
string reason = FlightTime >= MaxFlightTime ? "超出最大飞行时间" :
|
|
FlightDistance >= MaxFlightDistance ? "超出最大飞行距" :
|
|
Position.Y <= 0 ? "高度小于等于0" :
|
|
IsGuidanceLost ? "失去引导" : "未知原因";
|
|
|
|
Console.WriteLine($"导弹 {Id} 自毁。原因: {reason}");
|
|
}
|
|
|
|
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" +
|
|
$" 失去引导: {(IsGuidanceLost ? "是" : "否")}\n" +
|
|
$" 失去引导时间: {LostGuidanceTime:F2}/{MaxLostGuidanceTime:F2}";
|
|
}
|
|
|
|
public void SetProportionalNavigationCoefficient(double newCoefficient)
|
|
{
|
|
ProportionalNavigationCoefficient = newCoefficient;
|
|
Console.WriteLine($"导弹 {Id} 的比例导引系数已更新为 {newCoefficient}");
|
|
}
|
|
|
|
protected virtual void LoseGuidance()
|
|
{
|
|
if (!IsGuidanceLost)
|
|
{
|
|
Console.WriteLine($"导弹 {Id} 失去引导");
|
|
IsGuidanceLost = true;
|
|
}
|
|
}
|
|
|
|
protected virtual void HandleLostGuidance(double deltaTime)
|
|
{
|
|
LostGuidanceTime += deltaTime;
|
|
if (LostGuidanceTime >= MaxLostGuidanceTime)
|
|
{
|
|
Console.WriteLine($"导弹 {Id} 失去引导超过 {MaxLostGuidanceTime} 秒,自毁");
|
|
SelfDestruct();
|
|
}
|
|
}
|
|
|
|
private void OnLaserIllumination(LaserIlluminationEvent evt)
|
|
{
|
|
if (evt.TargetId == TargetId)
|
|
{
|
|
Console.WriteLine($"导弹 {Id} 检测到目标 {TargetId} 被激光照射");
|
|
RegainGuidance();
|
|
}
|
|
}
|
|
|
|
private void OnLaserIlluminationStop(LaserIlluminationStopEvent evt)
|
|
{
|
|
if (evt.TargetId == TargetId)
|
|
{
|
|
Console.WriteLine($"导弹 {Id} 检测到目标 {TargetId} 激光照射停止");
|
|
LoseGuidance();
|
|
}
|
|
}
|
|
|
|
protected virtual void RegainGuidance()
|
|
{
|
|
if (IsGuidanceLost)
|
|
{
|
|
Console.WriteLine($"导弹 {Id} 重新获得引导");
|
|
IsGuidanceLost = false;
|
|
LostGuidanceTime = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
} |