< Summary

Class:Agent
Assembly:bamlab.micromissiles
File(s):/github/workspace/Assets/Scripts/Agents/Agent.cs
Covered lines:159
Uncovered lines:97
Coverable lines:256
Total lines:460
Line coverage:62.1% (159 of 256)
Covered branches:0
Total branches:0
Covered methods:27
Total methods:45
Method coverage:60% (27 of 45)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
Agent()0%110100%
SetFlightPhase(...)0%440100%
GetFlightPhase()0%110100%
IsInitialized()0%2100%
IsTerminated()0%110100%
SetAgentConfig(...)0%110100%
SetStaticConfig(...)0%330100%
IsAssignable()0%2100%
AssignTarget(...)0%2100%
GetAssignedTarget()0%2100%
HasAssignedTarget()0%110100%
GetTargetModel()0%2100%
UnassignTarget()0%6200%
AddInterceptor(...)0%2100%
RemoveInterceptor(...)0%2100%
TerminateAgent()0%12300%
HandleInterceptHit(...)0%20400%
HandleInterceptMiss()0%20400%
HandleTargetIntercepted()0%6200%
HandleThreatHit()0%12300%
HandleHitGround()0%42600%
SetInitialVelocity(...)0%110100%
GetPosition()0%110100%
SetPosition(...)0%110100%
GetSpeed()0%110100%
GetVelocity()0%110100%
SetVelocity(...)0%110100%
GetAcceleration()0%2100%
SetAcceleration(...)0%2100%
GetRelativeTransformation(...)0%2100%
GetRelativeTransformationToWaypoint(...)0%110100%
GetRelativePositionTransformation(...)0%2.032081.25%
GetRelativeVelocityTransformation(...)0%5.225079.31%
GetRelativeAccelerationTransformation(...)0%2100%
GetDynamicPressure()0%110100%
Awake()0%110100%
Start()0%110100%
FixedUpdate()0%16.3515081.82%
AlignWithVelocity()0%220100%
CalculateAcceleration(...)0%110100%
CalculateMaxForwardAcceleration()0%330100%
CalculateMaxNormalAcceleration()0%550100%
CalculateDrag()0%770100%
CalculateLiftInducedDrag(...)0%330100%

File(s)

/github/workspace/Assets/Scripts/Agents/Agent.cs

#LineLine coverage
 1using System.Collections;
 2using System.Collections.Generic;
 3using UnityEngine;
 4
 5public abstract class Agent : MonoBehaviour {
 6  // In the initialized phase, the agent is subject to no forces.
 7  // In the ready phase, the agent is subject to gravity and drag with zero input acceleration.
 8  // TODO(titan): Replace this enumeration with the Protobuf enumeration.
 9  public enum FlightPhase { INITIALIZED, READY, BOOST, MIDCOURSE, TERMINAL, TERMINATED }
 10
 11  [SerializeField]
 94412  private FlightPhase _flightPhase = FlightPhase.INITIALIZED;
 13
 14  [SerializeField]
 15  protected Vector3 _velocity;
 16
 17  [SerializeField]
 18  protected Vector3 _acceleration;
 19
 20  [SerializeField]
 21  protected Vector3 _dragAcceleration;
 22
 23  [SerializeField]
 24  protected float _speed;
 25
 26  [SerializeField]
 94427  protected List<Agent> _interceptors = new List<Agent>();
 28  [SerializeField]
 29  protected Agent _target;
 30  [SerializeField]
 31  protected Agent _targetModel;
 32
 33  [SerializeField]
 94434  protected double _timeSinceBoost = 0;
 35  [SerializeField]
 94436  protected double _timeInPhase = 0;
 37
 38  public Configs.StaticConfig staticConfig;
 39  public Configs.AgentConfig agentConfig;
 40
 41  // Define delegates.
 42  public delegate void TerminatedEventHandler(Agent agent);
 43  public event TerminatedEventHandler OnTerminated;
 44
 45  public delegate void InterceptHitEventHandler(Interceptor interceptor, Threat target);
 46  public delegate void InterceptMissEventHandler(Interceptor interceptor, Threat target);
 47  public delegate void ThreatHitEventHandler(Threat threat);
 48  public delegate void ThreatMissEventHandler(Threat threat);
 49
 50  // Define events.
 51  public event InterceptHitEventHandler OnInterceptHit;
 52  public event InterceptMissEventHandler OnInterceptMiss;
 53  public event ThreatHitEventHandler OnThreatHit;
 54  public event ThreatMissEventHandler OnThreatMiss;
 55
 56  private Vector3 _initialVelocity;
 57
 226558  public void SetFlightPhase(FlightPhase flightPhase) {
 226559    _timeInPhase = 0;
 226560    _flightPhase = flightPhase;
 302061    if (flightPhase == FlightPhase.INITIALIZED || flightPhase == FlightPhase.TERMINATED) {
 75562      GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezeAll;
 226563    } else {
 151064      GetComponent<Rigidbody>().constraints = RigidbodyConstraints.None;
 151065    }
 302066    if (flightPhase == FlightPhase.BOOST) {
 75567      SetVelocity(GetVelocity() + _initialVelocity);
 75568    }
 226569  }
 70
 56471  public FlightPhase GetFlightPhase() {
 56472    return _flightPhase;
 56473  }
 74
 075  public bool IsInitialized() {
 076    return _flightPhase != FlightPhase.INITIALIZED;
 077  }
 78
 1151679  public bool IsTerminated() {
 1151680    return _flightPhase == FlightPhase.TERMINATED;
 1151681  }
 82
 75583  public virtual void SetAgentConfig(Configs.AgentConfig config) {
 75584    agentConfig = config;
 75585  }
 86
 75587  public virtual void SetStaticConfig(Configs.StaticConfig config) {
 75588    staticConfig = config;
 75589    GetComponent<Rigidbody>().mass = staticConfig.BodyConfig?.Mass ?? 1;
 75590  }
 91
 092  public virtual bool IsAssignable() {
 093    return true;
 094  }
 95
 096  public virtual void AssignTarget(Agent target) {
 097    _target = target;
 098    _target.AddInterceptor(this);
 099    _targetModel = SimManager.Instance.CreateDummyAgent(target.GetPosition(), target.GetVelocity());
 0100  }
 101
 0102  public Agent GetAssignedTarget() {
 0103    return _target;
 0104  }
 105
 5219106  public bool HasAssignedTarget() {
 5219107    return _target != null;
 5219108  }
 109
 0110  public Agent GetTargetModel() {
 0111    return _targetModel;
 0112  }
 113
 0114  public virtual void UnassignTarget() {
 0115    if (HasAssignedTarget()) {
 0116      _target.RemoveInterceptor(this);
 0117    }
 0118    _target = null;
 0119    _targetModel = null;
 0120  }
 121
 0122  public void AddInterceptor(Agent interceptor) {
 0123    _interceptors.Add(interceptor);
 0124  }
 125
 0126  public void RemoveInterceptor(Agent interceptor) {
 0127    _interceptors.Remove(interceptor);
 0128  }
 129
 130  public IReadOnlyList<Agent> AssignedInterceptors {
 2265131    get { return _interceptors; }
 132  }
 133
 0134  public virtual void TerminateAgent() {
 0135    UnassignTarget();
 0136    if (_flightPhase != FlightPhase.TERMINATED) {
 0137      OnTerminated?.Invoke(this);
 0138    }
 0139    _flightPhase = FlightPhase.TERMINATED;
 0140    SetPosition(Vector3.zero);
 0141    gameObject.SetActive(false);
 0142  }
 143
 0144  public void HandleInterceptHit(Agent agent) {
 0145    if (this is Interceptor interceptor && agent is Threat threat) {
 0146      OnInterceptHit?.Invoke(interceptor, threat);
 0147      TerminateAgent();
 0148    }
 0149  }
 150
 0151  public void HandleInterceptMiss() {
 0152    if (this is Interceptor interceptor && _target is Threat threat) {
 0153      OnInterceptMiss?.Invoke(interceptor, threat);
 0154    }
 0155  }
 156
 0157  public void HandleTargetIntercepted() {
 0158    if (this is Threat threat) {
 0159      TerminateAgent();
 0160    }
 0161  }
 162
 0163  public void HandleThreatHit() {
 0164    if (this is Threat threat) {
 0165      OnThreatHit?.Invoke(threat);
 0166      TerminateAgent();
 0167    }
 0168  }
 169
 0170  public void HandleHitGround() {
 0171    if (this is Interceptor interceptor && _target is Threat target) {
 0172      OnInterceptMiss?.Invoke(interceptor, target);
 0173    }
 0174    if (this is Threat threat) {
 0175      OnThreatMiss?.Invoke(threat);
 0176    }
 0177    TerminateAgent();
 0178  }
 179
 755180  public void SetInitialVelocity(Vector3 velocity) {
 755181    _initialVelocity = velocity;
 755182  }
 183
 17315184  public Vector3 GetPosition() {
 17315185    return transform.position;
 17315186  }
 187
 470188  public void SetPosition(Vector3 position) {
 470189    transform.position = position;
 470190  }
 191
 16041192  public double GetSpeed() {
 16041193    return GetComponent<Rigidbody>().linearVelocity.magnitude;
 16041194  }
 195
 35687196  public Vector3 GetVelocity() {
 35687197    return GetComponent<Rigidbody>().linearVelocity;
 35687198  }
 199
 1225200  public void SetVelocity(Vector3 velocity) {
 1225201    GetComponent<Rigidbody>().linearVelocity = velocity;
 1225202  }
 203
 0204  public Vector3 GetAcceleration() {
 0205    return _acceleration;
 0206  }
 207
 0208  public void SetAcceleration(Vector3 acceleration) {
 0209    _acceleration = acceleration;
 0210  }
 211
 0212  public Transformation GetRelativeTransformation(Agent target) {
 0213    Transformation transformation = new Transformation();
 214
 215    // Get the relative position transformation.
 0216    transformation.position =
 217        GetRelativePositionTransformation(target.GetPosition() - GetPosition());
 218
 219    // Get the relative velocity transformation.
 0220    transformation.velocity = GetRelativeVelocityTransformation(
 221        target.GetPosition() - GetPosition(), target.GetVelocity() - GetVelocity());
 222
 223    // Get the relative acceleration transformation.
 0224    transformation.acceleration = GetRelativeAccelerationTransformation(target);
 0225    return transformation;
 0226  }
 227
 5219228  public Transformation GetRelativeTransformationToWaypoint(Vector3 waypoint) {
 5219229    Transformation transformation = new Transformation();
 230
 231    // Get the relative position transformation.
 5219232    transformation.position = GetRelativePositionTransformation(waypoint - GetPosition());
 233
 234    // Get the relative velocity transformation.
 5219235    transformation.velocity =
 236        GetRelativeVelocityTransformation(waypoint - GetPosition(), -GetVelocity());
 237
 5219238    return transformation;
 5219239  }
 240
 5219241  private PositionTransformation GetRelativePositionTransformation(Vector3 relativePosition) {
 5219242    PositionTransformation positionTransformation = new PositionTransformation();
 243
 244    // Set the relative position in Cartesian coordinates.
 5219245    positionTransformation.cartesian = relativePosition;
 246
 247    // Calculate the distance (range) to the target.
 5219248    positionTransformation.range = relativePosition.magnitude;
 249
 5219250    Vector3 flatRelativePosition = Vector3.ProjectOnPlane(relativePosition, transform.up);
 5219251    Vector3 verticalRelativePosition = relativePosition - flatRelativePosition;
 252
 253    // Calculate the elevation (vertical angle relative to forward).
 5219254    positionTransformation.elevation =
 255        Mathf.Atan(verticalRelativePosition.magnitude / flatRelativePosition.magnitude);
 256
 257    // Calculate the azimuth (horizontal angle relative to forward).
 5219258    if (flatRelativePosition.magnitude == 0) {
 0259      positionTransformation.azimuth = 0;
 5219260    } else {
 5219261      positionTransformation.azimuth =
 262          Vector3.SignedAngle(transform.forward, flatRelativePosition, transform.up) * Mathf.PI /
 263          180;
 5219264    }
 265
 5219266    return positionTransformation;
 5219267  }
 268
 269  private VelocityTransformation GetRelativeVelocityTransformation(Vector3 relativePosition,
 5219270                                                                   Vector3 relativeVelocity) {
 5219271    VelocityTransformation velocityTransformation = new VelocityTransformation();
 272
 273    // Set the relative velocity in Cartesian coordinates.
 5219274    velocityTransformation.cartesian = relativeVelocity;
 275
 276    // Calculate range rate (radial velocity).
 5219277    velocityTransformation.range = Vector3.Dot(relativeVelocity, relativePosition.normalized);
 278
 279    // Project relative velocity onto the sphere passing through the target.
 5219280    Vector3 tangentialVelocity = Vector3.ProjectOnPlane(relativeVelocity, relativePosition);
 281
 282    // The target azimuth vector is orthogonal to the relative position vector and
 283    // points to the starboard of the target along the azimuth-elevation sphere.
 5219284    Vector3 targetAzimuth = Vector3.Cross(transform.up, relativePosition);
 285    // The target elevation vector is orthogonal to the relative position vector
 286    // and points upwards from the target along the azimuth-elevation sphere.
 5219287    Vector3 targetElevation = Vector3.Cross(relativePosition, transform.right);
 288    // If the relative position vector is parallel to the yaw or pitch axis, the
 289    // target azimuth vector or the target elevation vector will be undefined.
 5219290    if (targetAzimuth.magnitude == 0) {
 0291      targetAzimuth = Vector3.Cross(targetElevation, relativePosition);
 5219292    } else if (targetElevation.magnitude == 0) {
 0293      targetElevation = Vector3.Cross(relativePosition, targetAzimuth);
 0294    }
 295
 296    // Project the relative velocity vector on the azimuth-elevation sphere onto
 297    // the target azimuth vector.
 5219298    Vector3 tangentialVelocityOnAzimuth = Vector3.Project(tangentialVelocity, targetAzimuth);
 299
 300    // Calculate the time derivative of the azimuth to the target.
 5219301    velocityTransformation.azimuth =
 302        tangentialVelocityOnAzimuth.magnitude / relativePosition.magnitude;
 7777303    if (Vector3.Dot(tangentialVelocityOnAzimuth, targetAzimuth) < 0) {
 2558304      velocityTransformation.azimuth *= -1;
 2558305    }
 306
 307    // Project the velocity vector on the azimuth-elevation sphere onto the target
 308    // elevation vector.
 5219309    Vector3 tangentialVelocityOnElevation = Vector3.Project(tangentialVelocity, targetElevation);
 310
 311    // Calculate the time derivative of the elevation to the target.
 5219312    velocityTransformation.elevation =
 313        tangentialVelocityOnElevation.magnitude / relativePosition.magnitude;
 10333314    if (Vector3.Dot(tangentialVelocityOnElevation, targetElevation) < 0) {
 5114315      velocityTransformation.elevation *= -1;
 5114316    }
 317
 5219318    return velocityTransformation;
 5219319  }
 320
 0321  private AccelerationTransformation GetRelativeAccelerationTransformation(Agent agent) {
 322    // Since the agent's acceleration is an input, the relative acceleration is just the agent's
 323    // acceleration.
 0324    AccelerationTransformation accelerationTransformation = new AccelerationTransformation();
 0325    accelerationTransformation.cartesian = agent.GetAcceleration();
 0326    return accelerationTransformation;
 0327  }
 328
 4848329  public double GetDynamicPressure() {
 4848330    var airDensity = Constants.CalculateAirDensityAtAltitude(transform.position.y);
 4848331    var flowSpeed = GetSpeed();
 4848332    return 0.5 * airDensity * (flowSpeed * flowSpeed);
 4848333  }
 334
 335  protected abstract void UpdateReady(double deltaTime);
 336  protected abstract void UpdateBoost(double deltaTime);
 337  protected abstract void UpdateMidCourse(double deltaTime);
 338
 1884339  protected virtual void Awake() {}
 340
 1884341  protected virtual void Start() {}
 342
 5974343  protected virtual void FixedUpdate() {
 5974344    _speed = (float)GetSpeed();
 11193345    if (_flightPhase != FlightPhase.INITIALIZED && _flightPhase != FlightPhase.READY) {
 5219346      _timeSinceBoost += Time.fixedDeltaTime;
 5219347    }
 5974348    _timeInPhase += Time.fixedDeltaTime;
 349
 5974350    var boostTime = staticConfig.BoostConfig?.BoostTime ?? 0;
 5974351    double elapsedSimulationTime = SimManager.Instance.GetElapsedSimulationTime();
 352
 5974353    if (_flightPhase == FlightPhase.TERMINATED) {
 0354      return;
 355    }
 6729356    if (_flightPhase == FlightPhase.INITIALIZED || _flightPhase == FlightPhase.READY) {
 755357      SetFlightPhase(FlightPhase.BOOST);
 755358    }
 6729359    if (_timeSinceBoost > boostTime && _flightPhase == FlightPhase.BOOST) {
 755360      SetFlightPhase(FlightPhase.MIDCOURSE);
 755361    }
 5974362    AlignWithVelocity();
 5974363    switch (_flightPhase) {
 364      case FlightPhase.INITIALIZED:
 0365        break;
 366      case FlightPhase.READY:
 0367        UpdateReady(Time.fixedDeltaTime);
 0368        break;
 369      case FlightPhase.BOOST:
 755370        UpdateBoost(Time.fixedDeltaTime);
 755371        break;
 372      case FlightPhase.MIDCOURSE:
 373      case FlightPhase.TERMINAL:
 5219374        UpdateMidCourse(Time.fixedDeltaTime);
 5219375        break;
 376      case FlightPhase.TERMINATED:
 0377        break;
 378    }
 379
 5974380    _velocity = GetVelocity();
 381    // Store the acceleration because it is set to zero after each simulation step
 5974382    _acceleration =
 383        GetComponent<Rigidbody>().GetAccumulatedForce() / GetComponent<Rigidbody>().mass;
 5974384  }
 385
 5974386  protected virtual void AlignWithVelocity() {
 5974387    Vector3 velocity = GetVelocity();
 388    // Only align if we have significant velocity.
 11948389    if (velocity.magnitude > 0.1f) {
 390      // Create a rotation with forward along velocity and up along world up.
 5974391      Quaternion targetRotation = Quaternion.LookRotation(velocity, Vector3.up);
 392
 393      // Smoothly rotate towards the target rotation.
 5974394      transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation,
 395                                                    10000f * Time.fixedDeltaTime);
 5974396    }
 5974397  }
 398
 4848399  protected Vector3 CalculateAcceleration(Vector3 accelerationInput) {
 4848400    Vector3 gravity = Physics.gravity;
 4848401    float airDrag = CalculateDrag();
 4848402    float liftInducedDrag = CalculateLiftInducedDrag(accelerationInput + gravity);
 4848403    float dragAcceleration = -(airDrag + liftInducedDrag);
 404
 405    // Project the drag acceleration onto the forward direction.
 4848406    Vector3 dragAccelerationAlongRoll = dragAcceleration * transform.forward;
 4848407    _dragAcceleration = dragAccelerationAlongRoll;
 408
 4848409    return accelerationInput + gravity + dragAccelerationAlongRoll;
 4848410  }
 411
 5219412  public float CalculateMaxForwardAcceleration() {
 5219413    return staticConfig.AccelerationConfig?.MaxForwardAcceleration ?? 0;
 5219414  }
 415
 5219416  public float CalculateMaxNormalAcceleration() {
 5219417    float maxReferenceNormalAcceleration =
 418        (float)((staticConfig.AccelerationConfig?.MaxReferenceNormalAcceleration ?? 0) *
 419                Constants.kGravity);
 5219420    float referenceSpeed = staticConfig.AccelerationConfig?.ReferenceSpeed ?? 1;
 5219421    return Mathf.Pow((float)GetSpeed() / referenceSpeed, 2) * maxReferenceNormalAcceleration;
 5219422  }
 423
 4848424  private float CalculateDrag() {
 4848425    float dragCoefficient = staticConfig.LiftDragConfig?.DragCoefficient ?? 0;
 4848426    float crossSectionalArea = staticConfig.BodyConfig?.CrossSectionalArea ?? 0;
 4848427    float mass = staticConfig.BodyConfig?.Mass ?? 1;
 4848428    float dynamicPressure = (float)GetDynamicPressure();
 4848429    float dragForce = dragCoefficient * dynamicPressure * crossSectionalArea;
 4848430    return dragForce / mass;
 4848431  }
 432
 4848433  private float CalculateLiftInducedDrag(Vector3 accelerationInput) {
 4848434    float liftAcceleration = Vector3.ProjectOnPlane(accelerationInput, transform.forward).magnitude;
 4848435    float liftDragRatio = staticConfig.LiftDragConfig?.LiftDragRatio ?? 1;
 4848436    return Mathf.Abs(liftAcceleration / liftDragRatio);
 4848437  }
 438}
 439
 440public class DummyAgent : Agent {
 441  protected override void Start() {
 442    base.Start();
 443  }
 444
 445  protected override void FixedUpdate() {
 446    GetComponent<Rigidbody>().AddForce(_acceleration, ForceMode.Acceleration);
 447  }
 448
 449  protected override void UpdateReady(double deltaTime) {
 450    // Do nothing.
 451  }
 452
 453  protected override void UpdateBoost(double deltaTime) {
 454    // Do nothing.
 455  }
 456
 457  protected override void UpdateMidCourse(double deltaTime) {
 458    // Do nothing.
 459  }
 460}