< Summary

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

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
MissileMovement(...)0%2100%
Act(...)0%2401500%
ActReady(...)0%2100%
ActBoost(...)0%30500%
ActMidCourse(...)0%2100%
ActTerminal(...)0%2100%
ActBallistic(...)0%2100%
AvoidGround(...)0%12300%
CalculateNetAccelerationInput(...)0%2100%

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 {
 022    get { return _flightPhase; }
 023    set {
 024      _flightPhase = value;
 025      if (FlightPhase == Simulation.FlightPhase.Boost) {
 026        _boostTime = Agent.ElapsedTime;
 027      }
 028    }
 29  }
 30
 031  public MissileMovement(IAgent agent) : base(agent) {
 032    FlightPhase = Simulation.FlightPhase.Initialized;
 033  }
 34
 35  // Determine the agent's actual acceleration input given its intended acceleration input by
 36  // applying physics and other constraints.
 037  public override Vector3 Act(in Vector3 accelerationInput) {
 38    // Step through the flight phases.
 039    if (FlightPhase == Simulation.FlightPhase.Boost &&
 040        Agent.ElapsedTime > _boostTime + (Agent.StaticConfig?.BoostConfig?.BoostTime ?? 0)) {
 041      FlightPhase = Simulation.FlightPhase.Midcourse;
 042    }
 43
 44    // Act according to the flight phase.
 045    switch (FlightPhase) {
 046      case Simulation.FlightPhase.Initialized: {
 47        // In the initialized phase, the agent is not subject to any acceleration.
 048        return Vector3.zero;
 49      }
 050      case Simulation.FlightPhase.Ready: {
 051        return ActReady(accelerationInput);
 52      }
 053      case Simulation.FlightPhase.Boost: {
 054        return ActBoost(accelerationInput);
 55      }
 056      case Simulation.FlightPhase.Midcourse: {
 057        return ActMidCourse(accelerationInput);
 58      }
 059      case Simulation.FlightPhase.Terminal: {
 060        return ActTerminal(accelerationInput);
 61      }
 062      case Simulation.FlightPhase.Ballistic: {
 063        return ActBallistic(accelerationInput);
 64      }
 065      case Simulation.FlightPhase.Terminated: {
 66        // In the terminated phase, the agent is not subject to any acceleration.
 067        return Vector3.zero;
 68      }
 069      default: {
 070        return Vector3.zero;
 71      }
 72    }
 073  }
 74
 75  // In the ready phase, the agent is subject to drag and gravity but has not boosted yet.
 076  private Vector3 ActReady(in Vector3 accelerationInput) {
 077    Vector3 limitedAccelerationInput = LimitAccelerationInput(accelerationInput);
 078    return CalculateNetAccelerationInput(limitedAccelerationInput);
 079  }
 80
 81  // In the boost phase, the boost acceleration is added to the control acceleration input.
 082  private Vector3 ActBoost(in Vector3 accelerationInput) {
 083    Vector3 accelerationInputWithGroundAvoidance = AvoidGround(accelerationInput);
 084    Vector3 limitedAccelerationInput = LimitAccelerationInput(accelerationInputWithGroundAvoidance);
 85
 86    // Determine the boost acceleration.
 087    float boostAcceleration =
 88        (Agent.StaticConfig?.BoostConfig?.BoostAcceleration ?? 0) * Constants.kGravity;
 089    Vector3 totalAccelerationInput = boostAcceleration * Agent.Forward + limitedAccelerationInput;
 090    return CalculateNetAccelerationInput(totalAccelerationInput);
 091  }
 92
 93  // In the midcourse phase, the agent accelerates according to the control acceleration input but
 94  // is subject to drag and gravity.
 095  private Vector3 ActMidCourse(in Vector3 accelerationInput) {
 096    Vector3 accelerationInputWithGroundAvoidance = AvoidGround(accelerationInput);
 097    Vector3 limitedAccelerationInput = LimitAccelerationInput(accelerationInputWithGroundAvoidance);
 098    return CalculateNetAccelerationInput(limitedAccelerationInput);
 099  }
 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.
 0114  private Vector3 AvoidGround(in Vector3 accelerationInput) {
 115    const float groundProximityThresholdFactor = 5f;
 116
 0117    Vector3 agentPosition = Agent.Position;
 0118    Vector3 agentVelocity = Agent.Velocity;
 0119    float altitude = agentPosition.y;
 0120    float groundProximityThreshold =
 121        Mathf.Abs(agentVelocity.y) * groundProximityThresholdFactor +
 122        0.5f * Constants.kGravity * groundProximityThresholdFactor * groundProximityThresholdFactor;
 0123    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    }
 0128    return accelerationInput;
 0129  }
 130
 131  // Calculate the acceleration input with drag and gravity.
 0132  private Vector3 CalculateNetAccelerationInput(in Vector3 accelerationInput) {
 0133    Vector3 gravity = Physics.gravity;
 0134    float airDrag = CalculateDrag();
 0135    float liftInducedDrag = CalculateLiftInducedDrag(accelerationInput + gravity);
 0136    float dragAcceleration = -(airDrag + liftInducedDrag);
 0137    return accelerationInput + gravity + dragAcceleration * Agent.Forward;
 0138  }
 139}