< Summary

Class:MissileMovement
Assembly:bamlab.micromissiles
File(s):/github/workspace/Assets/Scripts/Movements/MissileMovement.cs
Covered lines:58
Uncovered lines:14
Coverable lines:72
Total lines:139
Line coverage:80.5% (58 of 72)
Covered branches:0
Total branches:0
Covered methods:9
Total methods:11
Method coverage:81.8% (9 of 11)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
MissileMovement(...)0%110100%
Act(...)0%1915073.91%
ActReady(...)0%110100%
ActBoost(...)0%550100%
ActMidCourse(...)0%110100%
ActTerminal(...)0%2100%
ActBallistic(...)0%2100%
AvoidGround(...)0%3.183072.73%
CalculateNetAccelerationInput(...)0%110100%

File(s)

/github/workspace/Assets/Scripts/Movements/MissileMovement.cs

#LineLine coverage
 1using UnityEngine;
 2
 3// Missile movement.
 4//
 5// A missile is defined by having multiple phases during its flight: ready phases (before it is
 6// launched), boost phases (when its burner is on), midcourse phases (after the burner has completed
 7// burning), and terminal phases (when the agent is homing in on the target).
 8//
 9// We define three additional states for our simulator: initialized state (when the missile has been
 10// created), ballistic state (when the missile is subject to only drag and gravity), and terminated
 11// state (when the missile has finished its flight).
 12//
 13// The missile is responsible for determining when it enters the boost phase.
 14public class MissileMovement : AerialMovement {
 15  // Flight phase of the agent.
 16  private Simulation.FlightPhase _flightPhase;
 17
 18  // Boost time in seconds relative to the agent's creation time.
 19  private float _boostTime;
 20
 21  public Simulation.FlightPhase FlightPhase {
 15322    get { return _flightPhase; }
 2523    set {
 2524      _flightPhase = value;
 2825      if (FlightPhase == Simulation.FlightPhase.Boost) {
 326        _boostTime = Agent.ElapsedTime;
 327      }
 2528    }
 29  }
 30
 2431  public MissileMovement(IAgent agent) : base(agent) {
 1232    FlightPhase = Simulation.FlightPhase.Initialized;
 1233  }
 34
 35  // Determine the agent's actual acceleration input given its intended acceleration input by
 36  // applying physics and other constraints.
 1237  public override Vector3 Act(in Vector3 accelerationInput) {
 38    // Step through the flight phases.
 1239    if (FlightPhase == Simulation.FlightPhase.Boost &&
 140        Agent.ElapsedTime > _boostTime + (Agent.StaticConfig?.BoostConfig?.BoostTime ?? 0)) {
 141      FlightPhase = Simulation.FlightPhase.Midcourse;
 142    }
 43
 44    // Act according to the flight phase.
 1245    switch (FlightPhase) {
 146      case Simulation.FlightPhase.Initialized: {
 47        // In the initialized phase, the agent is not subject to any acceleration.
 148        return Vector3.zero;
 49      }
 350      case Simulation.FlightPhase.Ready: {
 351        return ActReady(accelerationInput);
 52      }
 253      case Simulation.FlightPhase.Boost: {
 254        return ActBoost(accelerationInput);
 55      }
 556      case Simulation.FlightPhase.Midcourse: {
 557        return ActMidCourse(accelerationInput);
 58      }
 059      case Simulation.FlightPhase.Terminal: {
 060        return ActTerminal(accelerationInput);
 61      }
 062      case Simulation.FlightPhase.Ballistic: {
 063        return ActBallistic(accelerationInput);
 64      }
 165      case Simulation.FlightPhase.Terminated: {
 66        // In the terminated phase, the agent is not subject to any acceleration.
 167        return Vector3.zero;
 68      }
 069      default: {
 070        return Vector3.zero;
 71      }
 72    }
 1273  }
 74
 75  // In the ready phase, the agent is subject to drag and gravity but has not boosted yet.
 376  private Vector3 ActReady(in Vector3 accelerationInput) {
 377    Vector3 limitedAccelerationInput = LimitAccelerationInput(accelerationInput);
 378    return CalculateNetAccelerationInput(limitedAccelerationInput);
 379  }
 80
 81  // In the boost phase, the boost acceleration is added to the control acceleration input.
 282  private Vector3 ActBoost(in Vector3 accelerationInput) {
 283    Vector3 accelerationInputWithGroundAvoidance = AvoidGround(accelerationInput);
 284    Vector3 limitedAccelerationInput = LimitAccelerationInput(accelerationInputWithGroundAvoidance);
 85
 86    // Determine the boost acceleration.
 287    float boostAcceleration =
 88        (Agent.StaticConfig?.BoostConfig?.BoostAcceleration ?? 0) * Constants.kGravity;
 289    Vector3 totalAccelerationInput = boostAcceleration * Agent.Forward + limitedAccelerationInput;
 290    return CalculateNetAccelerationInput(totalAccelerationInput);
 291  }
 92
 93  // In the midcourse phase, the agent accelerates according to the control acceleration input but
 94  // is subject to drag and gravity.
 595  private Vector3 ActMidCourse(in Vector3 accelerationInput) {
 596    Vector3 accelerationInputWithGroundAvoidance = AvoidGround(accelerationInput);
 597    Vector3 limitedAccelerationInput = LimitAccelerationInput(accelerationInputWithGroundAvoidance);
 598    return CalculateNetAccelerationInput(limitedAccelerationInput);
 599  }
 100
 101  // In the terminal phase, the agent is homing in on the target and is still subject to drag and
 102  // gravity.
 0103  private Vector3 ActTerminal(in Vector3 accelerationInput) {
 104    // Currently, the agent acts the same in the terminal phase as in the midcourse phase.
 0105    return ActMidCourse(accelerationInput);
 0106  }
 107
 108  // In the ballistic phase, the agent is subject to only drag and gravity.
 0109  private Vector3 ActBallistic(in Vector3 accelerationInput) {
 0110    return ActMidCourse(accelerationInput: Vector3.zero);
 0111  }
 112
 113  // Adjust the acceleration input to avoid the ground.
 7114  private Vector3 AvoidGround(in Vector3 accelerationInput) {
 115    const float groundProximityThresholdFactor = 5f;
 116
 7117    Vector3 agentPosition = Agent.Position;
 7118    Vector3 agentVelocity = Agent.Velocity;
 7119    float altitude = agentPosition.y;
 7120    float groundProximityThreshold =
 121        Mathf.Abs(agentVelocity.y) * groundProximityThresholdFactor +
 122        0.5f * Constants.kGravity * groundProximityThresholdFactor * groundProximityThresholdFactor;
 7123    if (agentVelocity.y < 0 && altitude < groundProximityThreshold) {
 124      // Add some upward acceleration to avoid the ground.
 0125      float blendFactor = 1 - (altitude / groundProximityThreshold);
 0126      return accelerationInput + blendFactor * Agent.MaxNormalAcceleration() * Agent.Up;
 127    }
 7128    return accelerationInput;
 7129  }
 130
 131  // Calculate the acceleration input with drag and gravity.
 10132  private Vector3 CalculateNetAccelerationInput(in Vector3 accelerationInput) {
 10133    Vector3 gravity = Physics.gravity;
 10134    float airDrag = CalculateDrag();
 10135    float liftInducedDrag = CalculateLiftInducedDrag(accelerationInput + gravity);
 10136    float dragAcceleration = -(airDrag + liftInducedDrag);
 10137    return accelerationInput + gravity + dragAcceleration * Agent.Forward;
 10138  }
 139}