using System;
using CounterDrone.Core;
using CounterDrone.Core.Algorithms;
using CounterDrone.Core.Models;
namespace CounterDrone.Core.Simulation
{
public enum PlatformState { Idle, FlyingToTarget, ReadyToRelease }
public class PlatformEntity
{
public string Id { get; }
public EquipmentRole Role { get; }
public PlatformType? PlatformType { get; }
public float PosX { get; private set; }
public float PosY { get; private set; }
public float PosZ { get; private set; }
public AerosolType? AerosolType { get; }
public int MunitionCount { get; private set; }
public float Cooldown { get; }
public float CooldownRemaining { get; private set; }
public PlatformState State { get; private set; } = PlatformState.Idle;
// 空基平台
public float CruiseSpeed { get; }
public float PatrolX { get; }
public float PatrolY { get; }
public float PatrolZ { get; }
public float ReleaseAltitude { get; }
private float _targetX, _targetY, _targetZ;
private float _flightDistance;
private float _flownDistance;
private float _driftDistance;
/// 空基平台精确投放时刻(计算值)
public float ExactReleaseTime => _exactReleaseTime;
private float _exactReleaseTime;
public float TargetX => _targetX;
public float TargetY => _targetY;
public float TargetZ => _targetZ;
public float FlightDistance => _flightDistance;
public float FlownDistance => _flownDistance;
// 地基平台
public float MuzzleVelocity { get; }
public string? ModelId { get; }
/// Ready 包含:冷却就绪 + 有弹药 + 非飞行中
public bool Ready => CooldownRemaining <= 0 && MunitionCount > 0 && State != PlatformState.FlyingToTarget;
public PlatformEntity(string id, FireUnitSpec spec, ScenarioUnit deployment)
{
Id = id;
Role = (EquipmentRole)deployment.EquipmentRole;
PlatformType = (PlatformType?)spec.PlatformType;
PosX = (float)deployment.PositionX;
PosY = (float)deployment.PositionY;
PosZ = (float)deployment.PositionZ;
AerosolType = deployment.AerosolType.HasValue ? (AerosolType?)deployment.AerosolType.Value : null;
MunitionCount = deployment.MunitionCount ?? 1;
Cooldown = (float)spec.Cooldown;
MuzzleVelocity = (float)spec.MuzzleVelocity;
CruiseSpeed = (float)spec.CruiseSpeed;
ReleaseAltitude = (float)spec.ReleaseAltitude;
ModelId = string.IsNullOrEmpty(spec.ModelId) ? null : spec.ModelId;
PatrolX = PosX;
PatrolY = PosY;
PatrolZ = PosZ;
}
public void Update(float deltaTime)
{
if (CooldownRemaining > 0)
CooldownRemaining -= deltaTime;
if (State != PlatformState.FlyingToTarget) return;
float step = CruiseSpeed * deltaTime;
_flownDistance += step;
if (_flownDistance >= _flightDistance - _driftDistance - 0.01f || _flightDistance < 0.01f)
{
// 在投放点(非终点),保留插值位置
float rt = _flightDistance > 0.01f ? Math.Min(1f, _flownDistance / _flightDistance) : 1f;
PosX = PatrolX + (_targetX - PatrolX) * rt;
PosY = PatrolY + (_targetY - PatrolY) * rt;
PosZ = PatrolZ + (_targetZ - PatrolZ) * rt;
State = PlatformState.ReadyToRelease;
return;
}
float t = _flownDistance / _flightDistance;
PosX = PatrolX + (_targetX - PatrolX) * t;
PosY = PatrolY + (_targetY - PatrolY) * t;
PosZ = PatrolZ + (_targetZ - PatrolZ) * t;
}
/// 下令空基平台飞往投放点
public void CommandFlyTo(float targetX, float releaseAlt, float targetZ, float fireTime, float disperseHeight)
{
if (PlatformType != Models.PlatformType.AirBased) return;
_targetX = targetX;
_targetY = releaseAlt;
_targetZ = targetZ;
float distToCloud = Kinematics.Distance3D(PosX, PosY, PosZ, targetX, releaseAlt, targetZ);
float fallTime = Kinematics.AirDropFallTime(releaseAlt, disperseHeight);
float driftDist = CruiseSpeed * fallTime;
_flightDistance = distToCloud;
_flownDistance = 0;
_driftDistance = driftDist;
float flightDist = Math.Max(0f, distToCloud - driftDist);
float flightTime = CruiseSpeed > 0 ? flightDist / CruiseSpeed : 0f;
_exactReleaseTime = fireTime + flightTime;
State = PlatformState.FlyingToTarget;
}
/// 地基:直接发射;空基:投弹后冷却
public void Release()
{
MunitionCount--;
CooldownRemaining = Cooldown;
State = PlatformState.Idle;
}
/// 空基平台到达投放点后可投弹
public bool CanRelease => State == PlatformState.ReadyToRelease && CooldownRemaining <= 0 && MunitionCount > 0;
/// 当前速度矢量(空基平台:飞行方向 × 巡航速度;地基:零矢量)
public (float Vx, float Vy, float Vz) CurrentVelocity
{
get
{
if (PlatformType != Models.PlatformType.AirBased) return (0, 0, 0);
return Kinematics.DirectionVelocity(PatrolX, PatrolY, PatrolZ, _targetX, _targetY, _targetZ, CruiseSpeed);
}
}
}
}