refactor: code cleanup - warnings, dead code, naming
Warnings (9 to 0): events declared nullable, _cache nullable, IDamageModel param nullable. Dead code removed: DefaultFormations class + FormationTemplate; AlgorithmTypes legacy types (ThreatProfile/DefenseRecommendation/DefenseSolution/MultiGroupRecommendation/RecommendedPlatform/RecommendedDetection); DroneEntity CurrentWaypointIndex/FormationOffsetX/Y/ApplyFormationOffset/wind params; Vector3 operators+Length+DistanceTo; CloudExpansionModel Phase2Duration/TimeToDensity; Kinematics EstimatedShellTime/GaussianConcentration; InterceptCandidate write-only fields (CoverageDuration/FlightTime/ShellFlightTime); ParticleParams EmitRate/ColorHex. Naming: DefaultDefensePlanner -> DefensePlanner (only impl of IDefensePlanner); inCloudTime -> inCloudDistance (returns meters not seconds); DamageAssessment class summary fixed; wind comments clarified (drone wind removed vs cloud wind active). Tests: 191 pass, 0 warnings.
This commit is contained in:
parent
8515f7821a
commit
3b8fb4ee86
@ -3,53 +3,6 @@ using CounterDrone.Core.Models;
|
||||
|
||||
namespace CounterDrone.Core.Algorithms
|
||||
{
|
||||
/// <summary>威胁画像</summary>
|
||||
public class ThreatProfile
|
||||
{
|
||||
public CombatScene Environment { get; set; } = new();
|
||||
public List<TargetConfig> Targets { get; set; } = new();
|
||||
public RoutePlan Route { get; set; } = new();
|
||||
public List<Waypoint> Waypoints { get; set; } = new();
|
||||
public List<ControlZone> ControlZones { get; set; } = new();
|
||||
/// <summary>偏好平台类型(null = 算法自行决定,当前默认地基)</summary>
|
||||
public PlatformType? PreferredPlatformType { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>防御推荐方案</summary>
|
||||
public class DefenseRecommendation
|
||||
{
|
||||
public DefenseSolution Best { get; set; } = new();
|
||||
public DefenseSolution Critical { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>单套防御方案</summary>
|
||||
public class DefenseSolution
|
||||
{
|
||||
public AerosolType RecommendedAerosolType { get; set; }
|
||||
public string AerosolRationale { get; set; } = string.Empty;
|
||||
public CloudDispersal RecommendedCloud { get; set; } = new();
|
||||
|
||||
public List<RecommendedPlatform> Platforms { get; set; } = new();
|
||||
public List<RecommendedDetection> Detections { get; set; } = new();
|
||||
|
||||
public float InterceptProbability { get; set; }
|
||||
public string SummaryRationale { get; set; } = string.Empty;
|
||||
|
||||
public List<FireEvent> FireSchedule { get; set; } = new();
|
||||
|
||||
/// <summary>此方案占用的平台起始索引(多编队合并用)</summary>
|
||||
public int PlatformOffset { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>多编队推荐结果</summary>
|
||||
public class MultiGroupRecommendation
|
||||
{
|
||||
/// <summary>每组的独立方案</summary>
|
||||
public List<DefenseSolution> GroupSolutions { get; set; } = new();
|
||||
/// <summary>合并后的总发射计划</summary>
|
||||
public List<FireEvent> MergedFireSchedule { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>火力单元(完整的武器系统)</summary>
|
||||
public class FireUnit
|
||||
{
|
||||
@ -121,47 +74,17 @@ namespace CounterDrone.Core.Algorithms
|
||||
}
|
||||
}
|
||||
|
||||
public class RecommendedPlatform
|
||||
{
|
||||
public PlatformType Type { get; set; }
|
||||
public Vector3 Position { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
public int MunitionCount { get; set; }
|
||||
public float CoverageVolume { get; set; }
|
||||
public float Cooldown { get; set; } = 5f;
|
||||
public float MuzzleVelocity { get; set; } = 800f;
|
||||
/// <summary>空基平台巡航速度 m/s</summary>
|
||||
public float CruiseSpeed { get; set; } = 55f;
|
||||
/// <summary>空基平台投放高度 m</summary>
|
||||
public float ReleaseAltitude { get; set; }
|
||||
}
|
||||
|
||||
public class RecommendedDetection
|
||||
{
|
||||
public Vector3 Position { get; set; }
|
||||
public float DetectionRadius { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>三维向量(纯 C#,不依赖 UnityEngine)</summary>
|
||||
public struct Vector3
|
||||
{
|
||||
public float X, Y, Z;
|
||||
public Vector3(float x, float y, float z) { X = x; Y = y; Z = z; }
|
||||
|
||||
public static Vector3 operator +(Vector3 a, Vector3 b) => new(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
|
||||
public static Vector3 operator -(Vector3 a, Vector3 b) => new(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
|
||||
public static Vector3 operator *(Vector3 a, float s) => new(a.X * s, a.Y * s, a.Z * s);
|
||||
public float Length => (float)System.Math.Sqrt(X * X + Y * Y + Z * Z);
|
||||
public float DistanceTo(Vector3 other) => (this - other).Length;
|
||||
}
|
||||
|
||||
/// <summary>粒子渲染参数</summary>
|
||||
public class ParticleParams
|
||||
{
|
||||
public float EmitRate { get; set; } = 100;
|
||||
public float Opacity { get; set; } = 1.0f;
|
||||
public string ColorHex { get; set; } = "#FFFFFF";
|
||||
public float SizeMultiplier { get; set; } = 1.0f;
|
||||
}
|
||||
|
||||
@ -184,10 +107,7 @@ namespace CounterDrone.Core.Algorithms
|
||||
public FireUnit Unit { get; set; } = null!;
|
||||
public AerosolType AmmoType { get; set; }
|
||||
public float EarliestInterceptTime { get; set; }
|
||||
public float CoverageDuration { get; set; }
|
||||
public float KillProbability { get; set; }
|
||||
public float FlightTime { get; set; } // 弹药/平台飞行时间
|
||||
public float ShellFlightTime { get; set; } // 仅地基用
|
||||
}
|
||||
|
||||
/// <summary>单元分配:一个火力单元被分配给一个威胁的配置</summary>
|
||||
|
||||
@ -20,8 +20,6 @@ namespace CounterDrone.Core.Algorithms
|
||||
/// <summary>Phase 2 结束时的有效半径(30s 湍流膨胀)</summary>
|
||||
public float TurbulentRadius => RadiusAt(30f);
|
||||
|
||||
/// <summary>Phase 2 边界时间</summary>
|
||||
public float Phase2Duration => 30f;
|
||||
/// <summary>湍流膨胀系数 k</summary>
|
||||
public float TurbulentExpansionK => (float)_ammo.TurbulentExpansionK;
|
||||
|
||||
@ -55,17 +53,6 @@ namespace CounterDrone.Core.Algorithms
|
||||
return volume > 0.001f ? (float)_ammo.SourceStrength / volume : (float)_ammo.CoreDensity;
|
||||
}
|
||||
|
||||
/// <summary>达到指定浓度所需时间(密度随膨胀下降,较晚时间密度更低)</summary>
|
||||
/// <returns>浓度首次低于threshold的时间(s),如果不会低于则返回MaxDuration</returns>
|
||||
public float TimeToDensity(float threshold)
|
||||
{
|
||||
// 密度 ≈ SourceStrength / (4/3 π R³),随R增大而下降
|
||||
// 求R使得密度=threshold: R³ = SourceStrength / (threshold * 4π/3)
|
||||
float src = (float)_ammo.SourceStrength;
|
||||
float volume = src / Math.Max(threshold, 0.000001f);
|
||||
float r = (float)Math.Pow(volume * 3f / (4f * (float)Math.PI), 1f / 3f);
|
||||
return TimeToReach(r);
|
||||
}
|
||||
|
||||
/// <summary>覆盖指定距离需要的云团数量</summary>
|
||||
/// <param name="requiredCoverage">需要覆盖的距离 (m)</param>
|
||||
|
||||
@ -3,7 +3,7 @@ using CounterDrone.Core.Models;
|
||||
|
||||
namespace CounterDrone.Core.Algorithms
|
||||
{
|
||||
/// <summary>毁伤评估——路径积分计算无人机穿过云团的暴露时间</summary>
|
||||
/// <summary>毁伤评估——路径积分计算无人机穿过云团的路径长度(米),用于换算暴露时间</summary>
|
||||
public static class DamageAssessment
|
||||
{
|
||||
/// <summary>线段 (p1→p2) 在球体内的长度,换算为路径长度 (m)</summary>
|
||||
|
||||
@ -5,15 +5,15 @@ using CounterDrone.Core.Models;
|
||||
|
||||
namespace CounterDrone.Core.Algorithms
|
||||
{
|
||||
/// <summary>默认防御规划器 — 五步流水线,全部调用与引擎共享的物理工具类</summary>
|
||||
public class DefaultDefensePlanner : IDefensePlanner
|
||||
/// <summary>防御规划器 — 五步流水线,全部调用与引擎共享的物理工具类</summary>
|
||||
public class DefensePlanner : IDefensePlanner
|
||||
{
|
||||
private readonly List<AmmunitionSpec> _ammoCatalog;
|
||||
private readonly IDamageModel _damageModel;
|
||||
private readonly PlannerConfig _config;
|
||||
|
||||
public DefaultDefensePlanner(List<AmmunitionSpec> ammoCatalog, PlannerConfig config,
|
||||
IDamageModel damageModel = null)
|
||||
public DefensePlanner(List<AmmunitionSpec> ammoCatalog, PlannerConfig config,
|
||||
IDamageModel? damageModel = null)
|
||||
{
|
||||
_ammoCatalog = ammoCatalog ?? throw new ArgumentNullException(nameof(ammoCatalog));
|
||||
_config = config ?? throw new ArgumentNullException(nameof(config));
|
||||
@ -290,10 +290,7 @@ namespace CounterDrone.Core.Algorithms
|
||||
Unit = unit,
|
||||
AmmoType = ammoType,
|
||||
EarliestInterceptTime = interceptTime,
|
||||
CoverageDuration = effectiveR * 2f,
|
||||
KillProbability = prob,
|
||||
FlightTime = shellTime,
|
||||
ShellFlightTime = shellTime,
|
||||
};
|
||||
}
|
||||
|
||||
@ -324,10 +321,7 @@ namespace CounterDrone.Core.Algorithms
|
||||
Unit = unit,
|
||||
AmmoType = ammoType,
|
||||
EarliestInterceptTime = interceptTime,
|
||||
CoverageDuration = effectiveR * 2f,
|
||||
KillProbability = prob,
|
||||
FlightTime = totalTime,
|
||||
ShellFlightTime = fallTime,
|
||||
};
|
||||
}
|
||||
|
||||
@ -55,12 +55,6 @@ namespace CounterDrone.Core.Algorithms
|
||||
return range / (muzzleVelocity * cosAngle);
|
||||
}
|
||||
|
||||
/// <summary>炮弹飞行时间:抛物线轨迹到目标点的时间(自动求解发射角,下行段命中)</summary>
|
||||
public static float EstimatedShellTime(float horizontalDist, float muzzleVelocity)
|
||||
{
|
||||
return ParabolicShellTime(horizontalDist, 0f, muzzleVelocity);
|
||||
}
|
||||
|
||||
/// <summary>抛物线飞行时间:解 tan(θ) 二次方程求到达 (horizontalDist, heightDiff) 的时间</summary>
|
||||
public static float ParabolicShellTime(float horizontalDist, float heightDiff, float muzzleVelocity)
|
||||
{
|
||||
@ -232,16 +226,6 @@ namespace CounterDrone.Core.Algorithms
|
||||
var denom = (float)Math.Pow(2f * (float)Math.PI, 1.5f) * sigmaY * sigmaY * sigmaZ;
|
||||
return denom > 0.001f ? sourceStrength / denom : 0f;
|
||||
}
|
||||
|
||||
/// <summary>高斯烟团某点浓度 C(x,y,z) — 简化:相对中心的偏移</summary>
|
||||
public static float GaussianConcentration(float q, float sx, float sy, float sz, float offsetY, float offsetZ)
|
||||
{
|
||||
var norm = q / ((float)Math.Pow(2f * (float)Math.PI, 1.5f) * sx * sy * sz);
|
||||
var ey = (float)Math.Exp(-0.5f * offsetY * offsetY / (sy * sy));
|
||||
var ez = (float)Math.Exp(-0.5f * offsetZ * offsetZ / (sz * sz));
|
||||
var ezr = (float)Math.Exp(-0.5f * offsetZ * offsetZ / (sz * sz));
|
||||
return norm * ey * (ez + ezr);
|
||||
}
|
||||
public static bool PointInPolygon(float px, float pz, ReadOnlySpan<(float X, float Z)> vertices)
|
||||
{
|
||||
if (vertices.Length < 3) return false;
|
||||
|
||||
@ -4,7 +4,7 @@ namespace CounterDrone.Core
|
||||
{
|
||||
public static class DefaultFireUnits
|
||||
{
|
||||
private static List<FireUnitTemplate> _cache;
|
||||
private static List<FireUnitTemplate>? _cache;
|
||||
|
||||
public static List<FireUnitTemplate> GetAll()
|
||||
{
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CounterDrone.Core
|
||||
{
|
||||
public static class DefaultFormations
|
||||
{
|
||||
private static List<FormationTemplate> _cache;
|
||||
|
||||
public static List<FormationTemplate> GetAll()
|
||||
{
|
||||
if (_cache != null) return _cache;
|
||||
_cache = new List<FormationTemplate>
|
||||
{
|
||||
new() { Id = "single", Name = "单机", FormationMode = 0, LateralCount = 1, LongitudinalCount = 1 },
|
||||
new() { Id = "line-abreast-3", Name = "3机横队", FormationMode = 1, LateralCount = 3, LongitudinalCount = 1,
|
||||
LateralSpacing = 50 },
|
||||
new() { Id = "line-abreast-5", Name = "5机横队", FormationMode = 1, LateralCount = 5, LongitudinalCount = 1,
|
||||
LateralSpacing = 50 },
|
||||
new() { Id = "column-3", Name = "3机纵队", FormationMode = 1, LateralCount = 1, LongitudinalCount = 3,
|
||||
LongitudinalSpacing = 100 },
|
||||
new() { Id = "box-2x2", Name = "2×2方队", FormationMode = 1, LateralCount = 2, LongitudinalCount = 2,
|
||||
LateralSpacing = 50, LongitudinalSpacing = 100 },
|
||||
new() { Id = "swarm-10", Name = "蜂群(10架)", FormationMode = 2, LateralCount = 10, LongitudinalCount = 1,
|
||||
LateralSpacing = 30 },
|
||||
};
|
||||
return _cache;
|
||||
}
|
||||
|
||||
public static FormationTemplate GetById(string id) => GetAll().Find(t => t.Id == id);
|
||||
}
|
||||
|
||||
public class FormationTemplate
|
||||
{
|
||||
public string Id { get; set; } = "";
|
||||
public string Name { get; set; } = "";
|
||||
public int FormationMode { get; set; }
|
||||
public int LateralCount { get; set; } = 1;
|
||||
public int LongitudinalCount { get; set; } = 1;
|
||||
public double LateralSpacing { get; set; }
|
||||
public double LongitudinalSpacing { get; set; }
|
||||
}
|
||||
}
|
||||
@ -14,7 +14,6 @@ namespace CounterDrone.Core.Simulation
|
||||
public float Wingspan { get; }
|
||||
public float TypicalSpeed { get; }
|
||||
public List<Waypoint> Route { get; }
|
||||
public int CurrentWaypointIndex { get; private set; }
|
||||
public float PosX { get; private set; }
|
||||
public float PosY { get; private set; }
|
||||
public float PosZ { get; private set; }
|
||||
@ -25,8 +24,6 @@ namespace CounterDrone.Core.Simulation
|
||||
public float PrevX { get; private set; }
|
||||
public float PrevY { get; private set; }
|
||||
public float PrevZ { get; private set; }
|
||||
public float FormationOffsetX { get; set; }
|
||||
public float FormationOffsetY { get; set; }
|
||||
/// <summary>沿航路已飞行弧长(米),由 RouteGeometry 驱动</summary>
|
||||
private float _traveledArc;
|
||||
|
||||
@ -79,36 +76,19 @@ namespace CounterDrone.Core.Simulation
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyFormationOffset(int latIdx, float latSpacing, int longIdx, float longSpacing, FormationMode mode)
|
||||
{
|
||||
if (latIdx == 0 && longIdx == 0) return;
|
||||
switch (mode)
|
||||
{
|
||||
case FormationMode.Formation:
|
||||
FormationOffsetY = latIdx * latSpacing;
|
||||
FormationOffsetX = -longIdx * longSpacing;
|
||||
break;
|
||||
case FormationMode.Swarm:
|
||||
var rng = new Random((latIdx + longIdx * 100) * 137);
|
||||
FormationOffsetX = (float)(rng.NextDouble() - 0.5) * latSpacing * 3;
|
||||
FormationOffsetY = (float)(rng.NextDouble() - 0.5) * latSpacing * 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void SavePreviousPosition()
|
||||
{
|
||||
PrevX = PosX; PrevY = PosY; PrevZ = PosZ;
|
||||
}
|
||||
|
||||
public void Update(float deltaTime, float windSpeed, WindDirection windDir)
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (Status != DroneStatus.Flying) return;
|
||||
if (Route.Count == 0) return;
|
||||
|
||||
// 运动模型统一在 RouteGeometry:弧长推进 + 位置查询。
|
||||
// 无人机严格沿航路匀速飞行,不受风偏影响(风偏已移除,见风偏补偿说明)。
|
||||
// windSpeed/windDir 保留签名供未来飞控模型使用,当前不参与运动。
|
||||
// 无人机严格按航路匀速飞行。无人机不受风偏影响(真实无人机有飞控修正航向),
|
||||
// 但云团受风偏影响(见 SimulationEngine 毁伤判定的云团参考系修正)。
|
||||
float totalLen = RouteGeometry.TotalLength(Route);
|
||||
if (totalLen <= 0f)
|
||||
{
|
||||
|
||||
@ -28,12 +28,12 @@ namespace CounterDrone.Core.Simulation
|
||||
public IReadOnlyList<MunitionEntity> Munitions => _munitions;
|
||||
public IReadOnlyList<SimEvent> Events => _allEvents;
|
||||
|
||||
public event Action<MunitionEntity> OnMunitionLaunched;
|
||||
public event Action<CloudEntity> OnCloudGenerated;
|
||||
public event Action<DroneEntity> OnDroneDestroyed;
|
||||
public event Action<DroneEntity> OnDroneReachedTarget;
|
||||
public event Action<DroneEntity, ControlZoneEntity> OnZoneIntruded;
|
||||
public event Action OnSimulationEnded;
|
||||
public event Action<MunitionEntity>? OnMunitionLaunched;
|
||||
public event Action<CloudEntity>? OnCloudGenerated;
|
||||
public event Action<DroneEntity>? OnDroneDestroyed;
|
||||
public event Action<DroneEntity>? OnDroneReachedTarget;
|
||||
public event Action<DroneEntity, ControlZoneEntity>? OnZoneIntruded;
|
||||
public event Action? OnSimulationEnded;
|
||||
|
||||
private List<DroneEntity> _drones = new();
|
||||
private List<PlatformEntity> _platforms = new();
|
||||
@ -237,7 +237,7 @@ namespace CounterDrone.Core.Simulation
|
||||
// 5. 无人机移动
|
||||
foreach (var drone in _drones.Where(d => d.Status == DroneStatus.Flying))
|
||||
{
|
||||
drone.Update(scaledDt, (float)_scene.WindSpeed, (WindDirection)_scene.WindDirection);
|
||||
drone.Update(scaledDt);
|
||||
if (drone.Status == DroneStatus.ReachedTarget)
|
||||
{
|
||||
OnDroneReachedTarget?.Invoke(drone);
|
||||
@ -257,14 +257,14 @@ namespace CounterDrone.Core.Simulation
|
||||
{
|
||||
float ccx = cloud.Dispersion.Center.X, ccy = cloud.Dispersion.Center.Y, ccz = cloud.Dispersion.Center.Z;
|
||||
// 无人机线段换算到云团参考系:相对位置 = drone - cloud
|
||||
float inCloudTime = DamageAssessment.PathInSphere(
|
||||
float inCloudDistance = DamageAssessment.PathInSphere(
|
||||
drone.PrevX - (ccx - cloudDx), drone.PrevY - (ccy - cloudDy), drone.PrevZ - (ccz - cloudDz),
|
||||
drone.PosX - ccx, drone.PosY - ccy, drone.PosZ - ccz,
|
||||
0f, 0f, 0f,
|
||||
cloud.Dispersion.EffectiveRadius);
|
||||
if (inCloudTime > 0 && cloud.Dispersion.CoreDensity >= (float)_ammoSpec.EffectiveConcentration)
|
||||
if (inCloudDistance > 0 && cloud.Dispersion.CoreDensity >= (float)_ammoSpec.EffectiveConcentration)
|
||||
{
|
||||
float exposureIncrement = inCloudTime / (drone.TypicalSpeed / 3.6f);
|
||||
float exposureIncrement = inCloudDistance / (drone.TypicalSpeed / 3.6f);
|
||||
drone.ExposureTime += exposureIncrement;
|
||||
var dmg = _damageModel.CalculateDamage(drone.TargetType, drone.PowerType, cloud.AerosolType, cloud.Dispersion.CoreDensity, drone.ExposureTime, exposureIncrement);
|
||||
drone.ApplyDamage(dmg);
|
||||
|
||||
Binary file not shown.
@ -72,7 +72,7 @@ namespace CounterDrone.Unity
|
||||
TotalMunitions = 3,
|
||||
AmmoTypes = new() { AerosolType.InertGas, AerosolType.ActiveMaterial, AerosolType.ActiveFuel },
|
||||
});
|
||||
var result = new DefaultDefensePlanner(ammoCatalog, PlannerConfig.Load(paths)).Plan(fireUnits, new List<DroneGroup> { droneGroup }, detail.Scene);
|
||||
var result = new DefensePlanner(ammoCatalog, PlannerConfig.Load(paths)).Plan(fireUnits, new List<DroneGroup> { droneGroup }, detail.Scene);
|
||||
scenarioMgr.SaveCloud(taskId, new CloudDispersal
|
||||
{
|
||||
PositionX = (droneGroup.Waypoints[0].PosX + droneGroup.Waypoints[^1].PosX) / 2,
|
||||
|
||||
@ -67,7 +67,7 @@ namespace CounterDrone.Unity
|
||||
// 推荐方案
|
||||
var detail = scenario.GetTaskDetail(taskId);
|
||||
var ammoCatalog = db.Table<AmmunitionSpec>().ToList();
|
||||
var planner = new DefaultDefensePlanner(ammoCatalog, PlannerConfig.Load(paths));
|
||||
var planner = new DefensePlanner(ammoCatalog, PlannerConfig.Load(paths));
|
||||
var droneGroup = new DroneGroup
|
||||
{
|
||||
GroupId = "default",
|
||||
|
||||
@ -48,7 +48,7 @@ namespace CounterDrone.Unity
|
||||
new RoutePlanRepository(_db), new WaypointRepository(_db));
|
||||
|
||||
_frameStore = new FrameDataStore(_paths);
|
||||
_engine = new SimulationEngine(_scenario, _frameStore, new DamageModelRouter(), _paths, new DefaultDefensePlanner(DefaultAmmunition.GetAll(), PlannerConfig.Load(_paths)));
|
||||
_engine = new SimulationEngine(_scenario, _frameStore, new DamageModelRouter(), _paths, new DefensePlanner(DefaultAmmunition.GetAll(), PlannerConfig.Load(_paths)));
|
||||
}
|
||||
|
||||
public void LoadAndStart(string taskId)
|
||||
|
||||
@ -59,7 +59,7 @@ namespace CounterDrone.Core.Tests
|
||||
|
||||
private PlannerResult Plan(List<FireUnit> units, DroneGroup threat,
|
||||
CombatScene? env = null)
|
||||
=> new DefaultDefensePlanner(TestAmmo, TestPlannerConfig.Instance).Plan(units, new() { threat }, env ?? new CombatScene());
|
||||
=> new DefensePlanner(TestAmmo, TestPlannerConfig.Instance).Plan(units, new() { threat }, env ?? new CombatScene());
|
||||
|
||||
// ═══════════════════════════════════════
|
||||
// 威胁排序
|
||||
@ -233,7 +233,7 @@ namespace CounterDrone.Core.Tests
|
||||
[Fact]
|
||||
public void Allocation_MultiUnit_PoolsChannels()
|
||||
{
|
||||
var result = new DefaultDefensePlanner(TestAmmo, TestPlannerConfig.Instance).Plan(
|
||||
var result = new DefensePlanner(TestAmmo, TestPlannerConfig.Instance).Plan(
|
||||
new() { MakeGroundUnit("u0", 5000), MakeGroundUnit("u1", 5100) },
|
||||
new() { MakeThreat(speed: 200) }, new CombatScene());
|
||||
Assert.True(result.Best.ThreatsEngaged == 1);
|
||||
@ -259,8 +259,8 @@ namespace CounterDrone.Core.Tests
|
||||
// 边界
|
||||
// ═══════════════════════════════════════
|
||||
|
||||
[Fact] public void Edge_NoUnits_Unengaged() => Assert.Equal(1, new DefaultDefensePlanner(TestAmmo, TestPlannerConfig.Instance).Plan(new(), new() { MakeThreat() }, new CombatScene()).Best.ThreatsUnengaged);
|
||||
[Fact] public void Edge_NoThreats_Empty() => Assert.Equal(0, new DefaultDefensePlanner(TestAmmo, TestPlannerConfig.Instance).Plan(new() { MakeGroundUnit("u0", 5000) }, new(), new CombatScene()).Best.ThreatsEngaged);
|
||||
[Fact] public void Edge_NoUnits_Unengaged() => Assert.Equal(1, new DefensePlanner(TestAmmo, TestPlannerConfig.Instance).Plan(new(), new() { MakeThreat() }, new CombatScene()).Best.ThreatsUnengaged);
|
||||
[Fact] public void Edge_NoThreats_Empty() => Assert.Equal(0, new DefensePlanner(TestAmmo, TestPlannerConfig.Instance).Plan(new() { MakeGroundUnit("u0", 5000) }, new(), new CombatScene()).Best.ThreatsEngaged);
|
||||
|
||||
[Fact]
|
||||
public void Edge_OutOfRange_Ground()
|
||||
@ -293,7 +293,7 @@ namespace CounterDrone.Core.Tests
|
||||
{
|
||||
var a = MakeThreat(PowerType.Piston, 120); a.GroupId = "g0";
|
||||
var b = MakeThreat(PowerType.Jet, 300); b.GroupId = "g1";
|
||||
var result = new DefaultDefensePlanner(TestAmmo, TestPlannerConfig.Instance).Plan(
|
||||
var result = new DefensePlanner(TestAmmo, TestPlannerConfig.Instance).Plan(
|
||||
new() { MakeGroundUnit("u0", 5000), MakeGroundUnit("u1", 5100) },
|
||||
new() { a, b }, new CombatScene());
|
||||
Assert.Equal(2, result.Best.ThreatsEngaged);
|
||||
|
||||
@ -44,7 +44,7 @@ namespace CounterDrone.Core.Tests
|
||||
var drone = new DroneEntity("d1", "g1", CreateConfig(),
|
||||
CreateRoute(0, 1000, 300, 120), 0, 50, 0, 0, FormationMode.Single);
|
||||
float prevX = drone.PosX;
|
||||
drone.Update(1f, 0, WindDirection.N);
|
||||
drone.Update(1f);
|
||||
Assert.True(drone.PosX > prevX);
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ namespace CounterDrone.Core.Tests
|
||||
{
|
||||
var drone = new DroneEntity("d1", "g1", CreateConfig(360),
|
||||
CreateRoute(0, 100, 300, 360), 0, 50, 0, 0, FormationMode.Single);
|
||||
drone.Update(2f, 0, WindDirection.N);
|
||||
drone.Update(2f);
|
||||
Assert.Equal(DroneStatus.ReachedTarget, drone.Status);
|
||||
}
|
||||
|
||||
@ -140,25 +140,25 @@ namespace CounterDrone.Core.Tests
|
||||
0, 0, 0, 0, FormationMode.Single);
|
||||
|
||||
// 推进到第一段中点(弧长 50):应在 X=50, Z=0
|
||||
drone.Update(50f / (60f / 3.6f), 0, WindDirection.N);
|
||||
drone.Update(50f / (60f / 3.6f));
|
||||
Assert.Equal(50f, drone.PosX, 1);
|
||||
Assert.Equal(0f, drone.PosZ, 1);
|
||||
Assert.Equal(DroneStatus.Flying, drone.Status);
|
||||
|
||||
// 推进到拐点(弧长 100):应在 X=100, Z=0
|
||||
drone.Update(50f / (60f / 3.6f), 0, WindDirection.N);
|
||||
drone.Update(50f / (60f / 3.6f));
|
||||
Assert.Equal(100f, drone.PosX, 1);
|
||||
Assert.Equal(0f, drone.PosZ, 1);
|
||||
Assert.Equal(DroneStatus.Flying, drone.Status);
|
||||
|
||||
// 推进到第二段中点(弧长 150):应在 X=100, Z=50
|
||||
drone.Update(50f / (60f / 3.6f), 0, WindDirection.N);
|
||||
drone.Update(50f / (60f / 3.6f));
|
||||
Assert.Equal(100f, drone.PosX, 1);
|
||||
Assert.Equal(50f, drone.PosZ, 1);
|
||||
Assert.Equal(DroneStatus.Flying, drone.Status);
|
||||
|
||||
// 推进到终点(弧长 200):应在 X=100, Z=100,状态 ReachedTarget
|
||||
drone.Update(50f / (60f / 3.6f), 0, WindDirection.N);
|
||||
drone.Update(50f / (60f / 3.6f));
|
||||
Assert.Equal(100f, drone.PosX, 1);
|
||||
Assert.Equal(100f, drone.PosZ, 1);
|
||||
Assert.Equal(DroneStatus.ReachedTarget, drone.Status);
|
||||
|
||||
@ -65,7 +65,7 @@ namespace CounterDrone.Core.Tests
|
||||
});
|
||||
|
||||
var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)),
|
||||
new DamageModelRouter(), new TestPathProvider(_testDir), new DefaultDefensePlanner(DefaultAmmunition.GetAll(), TestPlannerConfig.Instance));
|
||||
new DamageModelRouter(), new TestPathProvider(_testDir), new DefensePlanner(DefaultAmmunition.GetAll(), TestPlannerConfig.Instance));
|
||||
engine.Initialize(_taskId);
|
||||
engine.TimeScale = 4f;
|
||||
|
||||
@ -107,7 +107,7 @@ namespace CounterDrone.Core.Tests
|
||||
});
|
||||
|
||||
var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)),
|
||||
new DamageModelRouter(), new TestPathProvider(_testDir), new DefaultDefensePlanner(DefaultAmmunition.GetAll(), TestPlannerConfig.Instance));
|
||||
new DamageModelRouter(), new TestPathProvider(_testDir), new DefensePlanner(DefaultAmmunition.GetAll(), TestPlannerConfig.Instance));
|
||||
engine.Initialize(_taskId);
|
||||
engine.TimeScale = 4f;
|
||||
|
||||
@ -148,7 +148,7 @@ namespace CounterDrone.Core.Tests
|
||||
});
|
||||
|
||||
var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)),
|
||||
new DamageModelRouter(), new TestPathProvider(_testDir), new DefaultDefensePlanner(DefaultAmmunition.GetAll(), TestPlannerConfig.Instance));
|
||||
new DamageModelRouter(), new TestPathProvider(_testDir), new DefensePlanner(DefaultAmmunition.GetAll(), TestPlannerConfig.Instance));
|
||||
engine.Initialize(_taskId);
|
||||
engine.TimeScale = 4f;
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ namespace CounterDrone.Core.Tests
|
||||
|
||||
private SimulationEngine RunSimulation(int maxTicks, float tickDt = 1f / 20f, float timeScale = 8f)
|
||||
{
|
||||
var engine = new SimulationEngine(_scenario, _frameStore, new DamageModelRouter(), _paths, new DefaultDefensePlanner(_ammoCatalog, TestPlannerConfig.Instance));
|
||||
var engine = new SimulationEngine(_scenario, _frameStore, new DamageModelRouter(), _paths, new DefensePlanner(_ammoCatalog, TestPlannerConfig.Instance));
|
||||
|
||||
engine.Initialize(_taskId);
|
||||
engine.TimeScale = timeScale; // 8倍速加速
|
||||
|
||||
@ -36,7 +36,7 @@ namespace CounterDrone.Core.Tests
|
||||
new RoutePlanRepository(_mainDb), new WaypointRepository(_mainDb));
|
||||
|
||||
_engine = new SimulationEngine(_scenarioService, new FrameDataStore(paths),
|
||||
new DamageModelRouter(), paths, new DefaultDefensePlanner(DefaultAmmunition.GetAll(), TestPlannerConfig.Instance));
|
||||
new DamageModelRouter(), paths, new DefensePlanner(DefaultAmmunition.GetAll(), TestPlannerConfig.Instance));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user