CounterDroneBackend/src/CounterDrone.Core/Simulation/PlatformEntity.cs
tian c8e066be64 仿真实体 +ModelId:DroneSpec/FireUnitSpec/SensorSpec → EntitySnapshot
- DroneSpec/FireUnitSpec/SensorSpec 加 ModelId (FK→ModelInfo)
- DroneEntity/PlatformEntity/DetectionEntity 内部带 ModelId
- DetectionSource +ModelId
- EntitySnapshot +ModelId,每帧推送给 Unity
- CollectSnapshots 传播所有实体 ModelId
2026-06-19 09:59:55 +08:00

141 lines
5.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
/// <summary>空基平台精确投放时刻(计算值)</summary>
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; }
/// <summary>Ready 包含:冷却就绪 + 有弹药 + 非飞行中</summary>
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;
}
/// <summary>下令空基平台飞往投放点</summary>
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;
}
/// <summary>地基:直接发射;空基:投弹后冷却</summary>
public void Release()
{
MunitionCount--;
CooldownRemaining = Cooldown;
State = PlatformState.Idle;
}
/// <summary>空基平台到达投放点后可投弹</summary>
public bool CanRelease => State == PlatformState.ReadyToRelease && CooldownRemaining <= 0 && MunitionCount > 0;
/// <summary>当前速度矢量(空基平台:飞行方向 × 巡航速度;地基:零矢量)</summary>
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);
}
}
}
}