增加激光报警器和激光干扰机, 仿真过程改为事件驱动机制

This commit is contained in:
Tian jianyong 2024-10-07 00:41:17 +08:00
parent e94e94e031
commit d9975acd3c
13 changed files with 697 additions and 159 deletions

121
Design.md Normal file
View File

@ -0,0 +1,121 @@
# 导弹仿真系统设计文档
## 系统架构设计思路
在处理导弹、坦克、告警设备、干扰设备等复杂交互关系时,我们采用了以下几种程序架构和设计模式的组合:
### 1. 事件驱动架构Event-Driven Architecture
事件驱动架构非常适合处理复杂的交互关系。每个实体(如导弹、坦克等)可以发布事件,其他实体可以订阅这些事件并作出反应。
``csharp
public class EventManager
{
private Dictionary<string, List<Action<object>>> eventSubscribers = new Dictionary<string, List<Action<object>>>();
public void Subscribe(string eventName, Action<object> listener) { ... }
public void Publish(string eventName, object eventData) { ... }
}
``
### 2. 组件系统Component System
将每个实体分解为多个组件,每个组件负责特定的功能。这样可以更灵活地组合不同的功能。
``csharp
public class Entity
{
public PositionComponent Position { get; set; }
public VelocityComponent Velocity { get; set; }
public HealthComponent Health { get; set; }
}
``
### 3. 观察者模式Observer Pattern
类似于事件驱动架构,但更加面向对象。每个实体可以作为观察者或被观察者。
``csharp
public interface IObserver
{
void Update(ISubject subject);
}
public interface ISubject
{
void Attach(IObserver observer);
void Detach(IObserver observer);
void Notify();
}
``
### 4. 状态机State Machine
对于有明确状态转换的实体(如导弹的飞行阶段),使用状态机可以更清晰地管理状态转换。
``csharp
public enum MissileState
{
Idle,
Tracking,
Locking,
Firing,
Exploding
}
public class Missile
{
public MissileState State { get; set; }
public void ChangeState(MissileState newState) { ... }
}
``csharp
public interface IState
{
void Enter();
void Update();
void Exit();
}
public class MissileStateMachine
{
private IState currentState;
public void ChangeState(IState newState) { ... }
public void Update() { ... }
}
``
### 5. 命令模式Command Pattern
用于封装各种操作,使得可以轻松地添加新的交互行为。
``csharp
public interface ICommand
{
void Execute();
}
public class FireMissileCommand : ICommand
{
public void Execute() { ... }
}
``
## 架构组合使用
在实际应用中,我们将这些模式组合使用:
1. 使用事件驱动架构作为整体框架,处理系统中的各种事件。
2. 采用组件系统来构建各个实体(如导弹、坦克、告警设备等)。
3. 使用状态机来管理导弹的飞行阶段。
4. 应用观察者模式来处理告警设备的通知机制。
5. 使用命令模式来封装各种交互操作,如发射导弹、激活干扰设备等。
这种组合架构允许我们灵活地处理复杂的交互关系,同时保持代码的可维护性和可扩展性。
## 下一步计划
- 实现核心实体(导弹、坦克、告警设备、干扰设备)的基本功能。
- 设计并实现事件系统,处理实体间的交互。
- 开发状态机,管理导弹的飞行阶段。
- 实现观察者模式,处理告警通知。
- 使用命令模式封装关键操作。
- 进行单元测试和集成测试,确保系统的正确性和稳定性。

View File

@ -1,56 +1,140 @@
using ActiveProtect.SimulationEnvironment;
using System;
namespace ActiveProtect.Models
{
public class LaserDesignator(string id, LaserDesignatorConfig laserDesignatorConfig, ISimulationManager simulationManager) : SimulationElement(id, laserDesignatorConfig.InitialPosition, new Orientation(), simulationManager)
public class LaserDesignator : SimulationElement
{
public string TargetId { get; private set; } = laserDesignatorConfig.TargetId;
public bool IsActive { get; private set; } = true;
private const double MaxIlluminationRange = 1000; // 1公里单位
public string TargetId { get; private set; }
public bool IsActive { get; private set; }
public double JammingThreshold { get; private set; } = 0.0; // 将阈值调整为 0 dB
public bool IsJammed { get; private set; } = false;
public double MaxIlluminationRange { get; private set; }
public void ActivateLaser()
public LaserDesignator(string id, LaserDesignatorConfig config, ISimulationManager simulationManager)
: base(id, config.InitialPosition, new Orientation(), simulationManager)
{
TargetId = config.TargetId;
IsActive = true;
}
public void DeactivateLaser()
{
IsActive = false;
MaxIlluminationRange = config.MaxIlluminationRange;
simulationManager.SubscribeToEvent<LaserJammingEvent>(OnLaserJamming);
}
public override void Update(double deltaTime)
{
if (IsActive)
if (IsActive && !IsJammed)
{
IlluminateTarget();
}
else
{
StopIllumination();
}
}
private void IlluminateTarget()
{
var target = SimulationManager.GetEntityById(TargetId) as ILaserIlluminatable;
if (target != null)
if (SimulationManager.GetEntityById(TargetId) is ILaserIlluminatable target)
{
double distanceToTarget = Vector3D.Distance(Position, target.Position);
if (distanceToTarget <= MaxIlluminationRange)
{
target.Illuminate();
Console.WriteLine($"激光目标指示器 {Id} 正在照射目标 {TargetId}");
// 发布LaserIlluminationEvent
PublishEvent(new LaserIlluminationEvent
{
TargetId = TargetId
});
}
else
{
target.StopIllumination();
StopIllumination();
Console.WriteLine($"激光目标指示器 {Id} 超出照射范围,停止照射目标 {TargetId}");
}
}
}
private void StopIllumination()
{
if (SimulationManager.GetEntityById(TargetId) is ILaserIlluminatable target)
{
target.StopIllumination();
Console.WriteLine($"激光目标指示器 {Id} 停止照射目标 {TargetId}");
PublishIlluminationStopEvent();
}
}
private void OnLaserJamming(LaserJammingEvent evt)
{
if (evt.TargetId == TargetId)
{
if (SimulationManager.GetEntityById(TargetId) is Tank target)
{
double distanceToTarget = Vector3D.Distance(Position, target.Position);
// 调整干扰效果计算方法
double jammingEffectiveness = 20 * Math.Log10(evt.JammingPower) - 20 * Math.Log10(distanceToTarget) - 20 * Math.Log10(4 * Math.PI);
Console.WriteLine($"激光目标指示器 {Id} 收到干扰事件,干扰功率: {evt.JammingPower:F2}, 距离: {distanceToTarget:F2}, 干扰效果: {jammingEffectiveness:F2} dB, 阈值: {JammingThreshold:F2} dB");
if (jammingEffectiveness > JammingThreshold)
{
if (!IsJammed)
{
Console.WriteLine($"激光目标指示器 {Id} 被干扰,停止工作");
IsJammed = true;
DeactivateLaser();
}
}
else
{
if (IsJammed)
{
Console.WriteLine($"激光目标指示器 {Id} 干扰解除,恢复工作");
IsJammed = false;
ActivateLaser();
}
}
}
}
}
public void ActivateLaser()
{
IsActive = true;
IsJammed = false;
Console.WriteLine($"激光目标指示器 {Id} 已激活");
IlluminateTarget(); // 立即开始照射目标
}
public void DeactivateLaser()
{
if (IsActive)
{
IsActive = false;
StopIllumination();
Console.WriteLine($"激光目标指示器 {Id} 已停用");
}
}
private void PublishIlluminationStopEvent()
{
PublishEvent(new LaserIlluminationStopEvent
{
TargetId = TargetId
});
}
public override string GetStatus()
{
return $"激光目标指示器 {Id}:\n" +
$" 位置: {Position}\n" +
$" 目标: {TargetId}\n" +
$" 激活状态: {(IsActive ? "" : "")}";
$" 激活状态: {(IsActive ? "" : "")}\n" +
$" 干扰状态: {(IsJammed ? "" : "")}\n" +
$" 最大照射范围: {MaxIlluminationRange}";
}
}
}

74
Models/LaserJammer.cs Normal file
View File

@ -0,0 +1,74 @@
using System;
using ActiveProtect.SimulationEnvironment;
namespace ActiveProtect.Models
{
public class LaserJammer
{
private readonly Tank tank;
public bool IsJamming { get; private set; }
public double JammingPower { get; private set; }
private double jammingCooldown = 0;
private const double MaxJammingCooldown = 5.0;
private const double MaxJammingPower = 10000.0; // 降低最大干扰功率
private const double InitialJammingPower = 4000.0; // 设置初始干扰功率
private const double PowerIncreaseRate = 2000.0; // 每秒增加的功率
public LaserJammer(Tank tank)
{
this.tank = tank;
IsJamming = false;
JammingPower = 0;
tank.SimulationManager.SubscribeToEvent<LaserIlluminationStopEvent>(OnLaserIlluminationStop);
}
public void Update(double deltaTime)
{
if (IsJamming)
{
// 逐渐增加干扰功率
JammingPower = Math.Min(JammingPower + PowerIncreaseRate * deltaTime, MaxJammingPower);
jammingCooldown += deltaTime;
if (jammingCooldown >= MaxJammingCooldown)
{
StopJamming();
}
Console.WriteLine($"坦克 {tank.Id} 的激光干扰器正在工作,当前功率: {JammingPower:F2}");
}
else if (tank.LaserWarner.IsAlarming)
{
StartJamming();
}
}
private void StartJamming()
{
IsJamming = true;
JammingPower = InitialJammingPower; // 从初始功率开始
jammingCooldown = 0;
Console.WriteLine($"坦克 {tank.Id} 的激光干扰器开始工作,初始功率: {JammingPower:F2}");
}
private void StopJamming()
{
if (IsJamming)
{
IsJamming = false;
JammingPower = 0;
jammingCooldown = 0;
Console.WriteLine($"坦克 {tank.Id} 的激光干扰器停止工作");
}
}
private void OnLaserIlluminationStop(LaserIlluminationStopEvent evt)
{
if (evt.TargetId == tank.Id)
{
Console.WriteLine($"坦克 {tank.Id} 接收到激光照射停止事件,停止干扰");
StopJamming();
}
}
}
}

View File

@ -1,15 +1,13 @@
using ActiveProtect.SimulationEnvironment;
using System;
namespace ActiveProtect.Models
{
public class LaserSemiActiveGuidedMissile : Missile
{
// 添加新的属性
public bool IsLaserDetected { get; private set; } = false;
private const double LaserLockDistance = 1000; // 1公里单位
// 激光半主动制导导弹的特殊属性
public bool IsLaserLocked { get; private set; } = false;
private const double LaserLockDistance = 1000; // 1公里单位
public LaserSemiActiveGuidedMissile(
string id,
@ -23,18 +21,20 @@ namespace ActiveProtect.Models
public override void Update(double deltaTime)
{
base.Update(deltaTime);
// 更新激光检测和锁定逻辑
UpdateLaserDetection();
if (IsLaserDetected)
{
UpdateLaserLock();
IsGuidanceLost = false;
}
else
{
LoseGuidance();
}
}
private void UpdateLaserDetection()
{
// 检查是否有激光照射目标
var target = SimulationManager.GetEntityById(TargetId) as ILaserIlluminatable;
if (target != null)
{
@ -48,13 +48,10 @@ namespace ActiveProtect.Models
private void UpdateLaserLock()
{
// 如果检测到激光,则锁定目标
IsLaserLocked = IsLaserDetected;
if (IsLaserLocked)
{
// 根据激光照射的光斑进行导引
// 这里可以添加更精确的导引逻辑
AdjustTrajectoryBasedOnLaserGuidance();
}
}
@ -62,14 +59,25 @@ namespace ActiveProtect.Models
private void AdjustTrajectoryBasedOnLaserGuidance()
{
// 实现基于激光导引的轨迹调整
// 这里可以添加更复杂的导引算法
// 这里可以添加更精确的导引逻辑
}
protected override void LoseGuidance()
{
if (!IsLaserDetected)
{
base.LoseGuidance();
IsLaserLocked = false;
Console.WriteLine($"激光半主动制导导弹 {Id} 失去激光引导");
}
}
public override string GetStatus()
{
return base.GetStatus().Replace("导弹", "激光半主动制导导弹") +
$"\n 激光检测: {(IsLaserDetected ? "" : "")}" +
$"\n 激光锁定: {(IsLaserLocked ? "" : "")}";
string baseStatus = base.GetStatus().Replace("导弹", "激光半主动制导导弹");
string additionalStatus = $"\n 激光检测: {(IsLaserDetected ? "" : "")}" +
$"\n 激光锁定: {(IsLaserLocked ? "" : "")}";
return baseStatus + additionalStatus;
}
}
}

69
Models/LaserWarner.cs Normal file
View File

@ -0,0 +1,69 @@
using ActiveProtect.SimulationEnvironment;
using System;
namespace ActiveProtect.Models
{
public class LaserWarner
{
private readonly Tank tank;
public bool IsAlarming { get; private set; }
private double alarmDuration = 5.0; // 警报持续5秒
private double alarmTimer = 0;
public LaserWarner(Tank tank)
{
this.tank = tank;
IsAlarming = false;
tank.SimulationManager.SubscribeToEvent<LaserIlluminationEvent>(OnLaserIllumination);
tank.SimulationManager.SubscribeToEvent<LaserIlluminationStopEvent>(OnLaserIlluminationStop);
}
public void Update(double deltaTime)
{
if (IsAlarming)
{
alarmTimer += deltaTime;
if (alarmTimer >= alarmDuration)
{
StopAlarm();
}
}
}
private void OnLaserIllumination(LaserIlluminationEvent evt)
{
if (evt.TargetId == tank.Id)
{
TriggerAlarm();
}
}
private void OnLaserIlluminationStop(LaserIlluminationStopEvent evt)
{
if (evt.TargetId == tank.Id)
{
StopAlarm();
}
}
public void TriggerAlarm()
{
if (!IsAlarming)
{
IsAlarming = true;
alarmTimer = 0;
Console.WriteLine($"坦克 {tank.Id} 的激光告警器发出警报!");
}
}
public void StopAlarm()
{
if (IsAlarming)
{
IsAlarming = false;
alarmTimer = 0;
Console.WriteLine($"坦克 {tank.Id} 的激光告警器停止警报");
}
}
}
}

View File

@ -26,41 +26,7 @@ namespace ActiveProtect.Models
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; }
@ -87,6 +53,10 @@ namespace ActiveProtect.Models
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)
{
@ -119,6 +89,10 @@ namespace ActiveProtect.Models
Console.WriteLine($"导弹 {Id} 的初始阶: {CurrentStage}");
LastTargetPosition = Position; // 初始化 LastTargetPosition
// 订阅相关事件
simulationManager.SubscribeToEvent<LaserIlluminationEvent>(OnLaserIllumination);
simulationManager.SubscribeToEvent<LaserIlluminationStopEvent>(OnLaserIlluminationStop);
}
public override void Update(double deltaTime)
@ -152,7 +126,7 @@ namespace ActiveProtect.Models
FlightTime += deltaTime;
FlightDistance += Speed * deltaTime;
UpdateDistanceToTarget(Vector3D.Distance(Position, SimulationManager.GetElementPosition(TargetId)));
UpdateDistanceToTarget(Vector3D.Distance(Position, SimulationManager.GetEntityById(TargetId).Position));
// 首先检查是否命中目标
if (CheckHit())
@ -170,6 +144,22 @@ namespace ActiveProtect.Models
// 更新飞行阶段
UpdateFlightStage();
if (IsGuidanceLost)
{
HandleLostGuidance(deltaTime);
}
else
{
// 重置失去引导的时间
LostGuidanceTime = 0;
}
// 发布事件示例
if (CurrentStage == FlightStage.Launch)
{
PublishEvent(new MissileFireEvent { TargetId = TargetId });
}
}
private bool CheckHit()
@ -192,7 +182,7 @@ namespace ActiveProtect.Models
private (Vector3D, Vector3D) CalculateDerivatives(Vector3D position, Vector3D velocity, double deltaTime)
{
Vector3D targetPosition = SimulationManager.GetElementPosition(TargetId);
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()
@ -266,6 +256,7 @@ namespace ActiveProtect.Models
public void Explode()
{
IsActive = false;
SimulationManager.HandleTargetHit(TargetId, Id);
Console.WriteLine($"导弹 {Id} 在 {Position} 爆炸,命中目标!");
}
@ -273,8 +264,9 @@ namespace ActiveProtect.Models
{
IsActive = false;
string reason = FlightTime >= MaxFlightTime ? "超出最大飞行时间" :
FlightDistance >= MaxFlightDistance ? "超出最大飞行距<E8A18C><E8B79D><EFBFBD>" :
Position.Y <= 0 ? "高度小于等于0" : "未知原因";
FlightDistance >= MaxFlightDistance ? "超出最大飞行距" :
Position.Y <= 0 ? "高度小于等于0" :
IsGuidanceLost ? "失去引导" : "未知原因";
Console.WriteLine($"导弹 {Id} 自毁。原因: {reason}");
}
@ -288,7 +280,9 @@ namespace ActiveProtect.Models
$" 飞行时间: {FlightTime:F2}/{MaxFlightTime:F2}\n" +
$" 飞行距离: {FlightDistance:F2}/{MaxFlightDistance:F2}\n" +
$" 距离目标: {DistanceToTarget:F2}\n" +
$" 发动机工作时间: {EngineBurnTime:F2}/{MaxEngineBurnTime:F2}";
$" 发动机工作时间: {EngineBurnTime:F2}/{MaxEngineBurnTime:F2}\n" +
$" 失去引导: {(IsGuidanceLost ? "" : "")}\n" +
$" 失去引导时间: {LostGuidanceTime:F2}/{MaxLostGuidanceTime:F2}";
}
public void SetProportionalNavigationCoefficient(double newCoefficient)
@ -296,6 +290,53 @@ namespace ActiveProtect.Models
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;
}
}
}
}

View File

@ -1,39 +1,70 @@
using ActiveProtect.SimulationEnvironment;
using System;
namespace ActiveProtect.Models
{
public class Tank : SimulationElement, ILaserIlluminatable
{
public double Speed { get; set; } = 0;
public bool IsActive { get; private set; } = false;
public double MaxSpeed { get; private set; } = 0;
public double MaxArmor { get; private set; } = 0;
public double Armor { get; private set; } = 0;
public double CurrentArmor { get; private set; } = 0;
public bool IsActive { get; private set; } = true;
public double MaxSpeed { get; private set; }
public double MaxArmor { get; private set; }
public double CurrentArmor { get; private set; }
public bool IsIlluminated { get; private set; } = false;
public LaserWarner LaserWarner { get; private set; }
public LaserJammer LaserJammer { get; private set; }
public Tank(string id, TankConfig tankConfig, ISimulationManager simulationManager)
: base(id, tankConfig.InitialPosition, tankConfig.InitialOrientation, simulationManager)
{
Position = tankConfig.InitialPosition;
Orientation = tankConfig.InitialOrientation;
Speed = tankConfig.InitialSpeed;
IsActive = true;
MaxSpeed = tankConfig.MaxSpeed;
MaxArmor = tankConfig.MaxArmor;
Armor = tankConfig.MaxArmor;
CurrentArmor = tankConfig.MaxArmor;
IsIlluminated = false;
SimulationManager = simulationManager;
LaserWarner = new LaserWarner(this);
LaserJammer = new LaserJammer(this);
// 移除事件订阅因为现在由LaserWarner直接处理
}
public void TakeDamage(double damage)
public override void Update(double deltaTime)
{
CurrentArmor -= damage;
if (!IsActive) return;
UpdatePosition(deltaTime);
LaserWarner.Update(deltaTime);
LaserJammer.Update(deltaTime);
// 如果激光干扰器正在工作发布LaserJammingEvent
if (LaserJammer.IsJamming)
{
PublishEvent(new LaserJammingEvent
{
TargetId = Id,
JammingPower = LaserJammer.JammingPower
});
}
}
private void UpdatePosition(double deltaTime)
{
Vector3D direction = Orientation.ToVector();
Vector3D movement = direction * Speed * deltaTime;
Position += movement;
}
public void TakeDamage(double damage, bool isMissileDamage = false)
{
if (isMissileDamage)
{
damage = CurrentArmor * 0.5;
}
CurrentArmor = Math.Max(0, CurrentArmor - damage);
if (CurrentArmor <= 0)
{
CurrentArmor = 0;
IsActive = false;
PublishEvent(new EntityDestroyedEvent { DestroyedEntityId = Id });
}
}
@ -47,49 +78,18 @@ namespace ActiveProtect.Models
IsIlluminated = false;
}
public override void Update(double deltaTime)
{
// 移除对基类抽象方法的调用
// 实现坦克特定的更新逻辑
UpdatePosition(deltaTime);
UpdateArmor();
CheckIlluminationStatus();
}
private void UpdatePosition(double deltaTime)
{
// 根据速度更新坦克位置
Vector3D direction = Orientation.ToVector();
Vector3D movement = direction * Speed * deltaTime;
Position += movement;
}
private void UpdateArmor()
{
// 可能的装甲恢复逻辑
if (CurrentArmor < MaxArmor)
{
CurrentArmor = Math.Min(CurrentArmor + 10, MaxArmor);
}
}
private void CheckIlluminationStatus()
{
// 检查激光照射状态,可能会影响坦克的其他属性
if (IsIlluminated)
{
// 实现被激光照射时的效果
}
}
// 移除OnLaserIllumination和OnLaserIlluminationStop方法因为现在由LaserWarner直接处理
public override string GetStatus()
{
return base.GetStatus() +
$"\n 速度: {Speed}" +
$"\n 最大速度: {MaxSpeed}" +
$"\n 装甲: {CurrentArmor}/{MaxArmor}" +
$"\n 状态: {(IsActive ? "" : "")}" +
$"\n 激光照射: {(IsIlluminated ? "" : "")}";
return $"坦克 {Id}:\n" +
$" 位置: {Position}\n" +
$" 速度: {Speed:F2}/{MaxSpeed:F2}\n" +
$" 装甲: {CurrentArmor:F2}/{MaxArmor:F2}\n" +
$" 状态: {(IsActive ? "" : "")}\n" +
$" 激光照射: {(IsIlluminated ? "" : "")}\n" +
$" 激光报警: {(LaserWarner.IsAlarming ? "" : "")}\n" +
$" 激光干扰: {(LaserJammer.IsJamming ? $" (: {LaserJammer.JammingPower:F2})" : "")}";
}
}
}

View File

@ -37,7 +37,7 @@ namespace ActiveProtect
MaxEngineBurnTime = 5,
MaxAcceleration = 100,
ProportionalNavigationCoefficient = 3,
StageConfig = Missile.FlightStageConfig.StandardMissile,
StageConfig = FlightStageConfig.StandardMissile,
DistanceParams = new MissileDistanceParams(500, 100, 20),
Type = MissileType.StandardMissile
},
@ -54,7 +54,7 @@ namespace ActiveProtect
MaxEngineBurnTime = 5,
MaxAcceleration = 100,
ProportionalNavigationCoefficient = 3,
StageConfig = Missile.FlightStageConfig.LaserGuidedShell,
StageConfig = FlightStageConfig.LaserGuidedShell,
DistanceParams = new MissileDistanceParams(300, 100, 20),
Type = MissileType.InfraredCommandGuidance
},
@ -71,13 +71,13 @@ namespace ActiveProtect
MaxEngineBurnTime = 5,
MaxAcceleration = 100,
ProportionalNavigationCoefficient = 3,
StageConfig = Missile.FlightStageConfig.ShortRangeMissile,
StageConfig = FlightStageConfig.ShortRangeMissile,
DistanceParams = new MissileDistanceParams(400, 100, 20),
Type = MissileType.MillimeterWaveTerminalGuidance
},
// 新增激光半主动制导导弹配置
new() {
InitialPosition = new Vector3D(1500, 150, 100),
InitialPosition = new Vector3D(2000, 150, 100),
InitialOrientation = new Orientation(Math.PI, -0.12, 0),
InitialSpeed = 700,
MaxSpeed = 800,
@ -88,7 +88,7 @@ namespace ActiveProtect
MaxEngineBurnTime = 5,
MaxAcceleration = 100,
ProportionalNavigationCoefficient = 3,
StageConfig = Missile.FlightStageConfig.LaserSemiActiveGuidedMissile,
StageConfig = FlightStageConfig.LaserSemiActiveGuidedMissile,
DistanceParams = new MissileDistanceParams(500, 200, 20),
Type = MissileType.SemiActiveLaserGuidance
}
@ -97,8 +97,9 @@ namespace ActiveProtect
[
new LaserDesignatorConfig
{
InitialPosition = new Vector3D(500, 50, 100),
TargetId = "Tank_1"
InitialPosition = new Vector3D(500, 150, 100),
TargetId = "Tank_1",
MaxIlluminationRange = 1000
}
],
SimulationTimeStep = 0.05
@ -108,11 +109,14 @@ namespace ActiveProtect
var simulationManager = new SimulationManager(config);
// 运行仿真
while (!simulationManager.IsSimulationEnded)
int maxIterations = 1000; // 增加最大迭代次数
int iteration = 0;
while (!simulationManager.IsSimulationEnded && iteration < maxIterations)
{
simulationManager.Update();
simulationManager.PrintStatus();
Thread.Sleep(100); // 暂停100毫秒使输出更易读
iteration++;
}
Console.WriteLine("仿真结束");

View File

@ -1,12 +0,0 @@
using ActiveProtect.Models;
using ActiveProtect.SimulationEnvironment;
namespace ActiveProtect.SimulationEnvironment
{
public interface ISimulationManager
{
Vector3D GetElementPosition(string elementId);
SimulationElement GetEntityById(string id);
}
}

View File

@ -44,7 +44,7 @@ namespace ActiveProtect.SimulationEnvironment
public double MaxFlightDistance { get; set; }
public double MaxAcceleration { get; set; }
public double ProportionalNavigationCoefficient { get; set; }
public Missile.FlightStageConfig StageConfig { get; set; }
public FlightStageConfig StageConfig { get; set; }
public MissileDistanceParams DistanceParams { get; set; }
public double ThrustAcceleration { get; set; }
public double MaxEngineBurnTime { get; set; }
@ -60,7 +60,7 @@ namespace ActiveProtect.SimulationEnvironment
TargetIndex = 0; // 目标索引
MaxFlightTime = 0; // 最大飞行时间
MaxFlightDistance = 0; // 最大飞行距离
StageConfig = Missile.FlightStageConfig.StandardMissile; // 飞行阶段配置
StageConfig = FlightStageConfig.StandardMissile; // 飞行阶段配置
ThrustAcceleration = 0; // 推力加速度
MaxEngineBurnTime = 0; // 最大发动机燃烧时间
MaxAcceleration = 0; // 最大加速度
@ -74,11 +74,12 @@ namespace ActiveProtect.SimulationEnvironment
{
public Vector3D InitialPosition { get; set; }
public string TargetId { get; set; }
public double MaxIlluminationRange { get; set; }
public LaserDesignatorConfig()
{
InitialPosition = new Vector3D(0, 0, 0);
TargetId = "";
MaxIlluminationRange = 1000;
}
}
@ -88,4 +89,40 @@ namespace ActiveProtect.SimulationEnvironment
public double AttackDistance { get; set; } = attackDistance;
public double ExplosionDistance { get; set; } = explosionDistance;
}
/// <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);
}
}

View File

@ -15,5 +15,12 @@ namespace ActiveProtect.SimulationEnvironment
{
return $"{GetType().Name} {Id} at {Position}, Orientation: {Orientation}";
}
protected void PublishEvent(SimulationEvent evt)
{
evt.SenderId = Id;
evt.Timestamp = SimulationManager.CurrentTime;
SimulationManager.PublishEvent(evt);
}
}
}

View File

@ -0,0 +1,34 @@
namespace ActiveProtect.SimulationEnvironment
{
public class SimulationEvent
{
public string? SenderId { get; set; }
public double Timestamp { get; set; }
}
public class MissileFireEvent : SimulationEvent
{
public string? TargetId { get; set; }
}
public class LaserIlluminationEvent : SimulationEvent
{
public string? TargetId { get; set; }
}
public class LaserJammingEvent : SimulationEvent
{
public string? TargetId { get; set; }
public double JammingPower { get; set; }
}
public class EntityDestroyedEvent : SimulationEvent
{
public string? DestroyedEntityId { get; set; }
}
public class LaserIlluminationStopEvent : SimulationEvent
{
public string? TargetId { get; set; }
}
}

View File

@ -5,12 +5,25 @@ using ActiveProtect.Models;
namespace ActiveProtect.SimulationEnvironment
{
public interface ISimulationManager
{
double CurrentTime { get; }
SimulationElement GetEntityById(string id);
void HandleTargetHit(string targetId, string missileId);
void PublishEvent(SimulationEvent evt);
void SubscribeToEvent<T>(Action<T> handler) where T : SimulationEvent;
void UnsubscribeFromEvent<T>(Action<T> handler) where T : SimulationEvent;
}
public class SimulationManager : ISimulationManager
{
public List<SimulationElement> Elements { get; private set; }
public double CurrentTime { get; private set; }
public bool IsSimulationEnded { get; private set; }
private readonly SimulationConfig config;
private Dictionary<Type, List<Delegate>> eventHandlers = new Dictionary<Type, List<Delegate>>();
public SimulationManager(SimulationConfig config)
{
@ -54,7 +67,40 @@ namespace ActiveProtect.SimulationEnvironment
for (int i = 0; i < config.LaserDesignatorConfigs.Count; i++)
{
var laserDesignatorConfig = config.LaserDesignatorConfigs[i];
Elements.Add(new LaserDesignator($"LD_{i + 1}", laserDesignatorConfig, this));
var laserDesignator = new LaserDesignator($"LD_{i + 1}", laserDesignatorConfig, this);
Elements.Add(laserDesignator);
laserDesignator.ActivateLaser(); // 激活激光目标指示器
}
}
public void PublishEvent(SimulationEvent evt)
{
var eventType = evt.GetType();
if (eventHandlers.TryGetValue(eventType, out var handlers))
{
foreach (var handler in handlers)
{
handler.DynamicInvoke(evt);
}
}
}
public void SubscribeToEvent<T>(Action<T> handler) where T : SimulationEvent
{
var eventType = typeof(T);
if (!eventHandlers.ContainsKey(eventType))
{
eventHandlers[eventType] = new List<Delegate>();
}
eventHandlers[eventType].Add(handler);
}
public void UnsubscribeFromEvent<T>(Action<T> handler) where T : SimulationEvent
{
var eventType = typeof(T);
if (eventHandlers.ContainsKey(eventType))
{
eventHandlers[eventType].Remove(handler);
}
}
@ -97,19 +143,44 @@ namespace ActiveProtect.SimulationEnvironment
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");
}
public SimulationElement GetEntityById(string id)
{
return Elements.FirstOrDefault(e => e.Id == id) ?? throw new InvalidOperationException($"Entity with id {id} not found");
}
public void HandleTargetHit(string targetId, string missileId)
{
if (GetEntityById(targetId) is Tank tank && GetEntityById(missileId) is Missile missile)
{
// 计算导弹造成的伤害
double damage = CalculateMissileDamage(missile);
// 对坦克造成伤害
tank.TakeDamage(damage, true);
// 移除已爆炸的导弹
RemoveEntity(missileId);
// 记录击中事件
LogHitEvent(targetId, missileId, damage);
}
}
private void RemoveEntity(string missileId)
{
Elements.Remove(GetEntityById(missileId));
}
private double CalculateMissileDamage(Missile missile)
{
// 这里可以根据导弹类型、速度等因素计算伤害
// 现在我们简单地返回一个固定值
return 100;
}
private void LogHitEvent(string targetId, string missileId, double damage)
{
Console.WriteLine($"目标 {targetId} 被导弹 {missileId} 击中,造成 {damage} 点伤害");
}
}
}