| | 1 | | using System.Collections; |
| | 2 | | using System.Collections.Generic; |
| | 3 | | using UnityEngine; |
| | 4 | |
|
| | 5 | | public class FixedWingThreat : Threat { |
| | 6 | | [SerializeField] |
| 9 | 7 | | private float _navigationGain = 50f; |
| | 8 | |
|
| | 9 | | private Vector3 _accelerationInput; |
| 9 | 10 | | private double _elapsedTime = 0; |
| | 11 | | private Rigidbody _rigidbody; |
| | 12 | |
|
| | 13 | | // Start is called before the first frame update |
| 8 | 14 | | protected override void Start() { |
| 8 | 15 | | base.Start(); |
| 8 | 16 | | _rigidbody = GetComponent<Rigidbody>(); |
| 8 | 17 | | } |
| | 18 | |
|
| | 19 | | // Update is called once per frame |
| 0 | 20 | | protected override void FixedUpdate() { |
| 0 | 21 | | base.FixedUpdate(); |
| 0 | 22 | | } |
| | 23 | |
|
| 0 | 24 | | protected override void UpdateReady(double deltaTime) {} |
| | 25 | |
|
| 0 | 26 | | protected override void UpdateBoost(double deltaTime) {} |
| | 27 | |
|
| 0 | 28 | | protected override void UpdateMidCourse(double deltaTime) { |
| 0 | 29 | | _elapsedTime += deltaTime; |
| 0 | 30 | | Vector3 accelerationInput = Vector3.zero; |
| | 31 | |
|
| 0 | 32 | | if (ShouldEvade()) { |
| 0 | 33 | | accelerationInput = EvadeInterceptor(GetClosestInterceptor()); |
| 0 | 34 | | } else if (HasAssignedTarget()) { |
| | 35 | | // Update waypoint and power setting |
| 0 | 36 | | UpdateWaypointAndPower(); |
| | 37 | |
|
| 0 | 38 | | float sensorUpdatePeriod = 1f / dynamicAgentConfig.dynamic_config.sensor_config.frequency; |
| 0 | 39 | | if (_elapsedTime >= sensorUpdatePeriod) { |
| | 40 | | // TODO: Implement guidance filter to estimate state from sensor output |
| | 41 | | // For now, we'll use the threat's actual state |
| 0 | 42 | | _elapsedTime = 0; |
| 0 | 43 | | } |
| | 44 | |
|
| | 45 | | // Calculate the normal acceleration input using PN |
| 0 | 46 | | Vector3 normalAcceleration = CalculateAccelerationInput(); |
| | 47 | |
|
| | 48 | | // Adjust the speed based on power setting |
| 0 | 49 | | Vector3 forwardAcceleration = CalculateForwardAcceleration(); |
| | 50 | |
|
| | 51 | | // Combine the accelerations |
| 0 | 52 | | accelerationInput = normalAcceleration + forwardAcceleration; |
| 0 | 53 | | } |
| | 54 | |
|
| | 55 | | // Calculate and set the total acceleration |
| 0 | 56 | | Vector3 acceleration = CalculateAcceleration(accelerationInput); |
| 0 | 57 | | _rigidbody.AddForce(acceleration, ForceMode.Acceleration); |
| 0 | 58 | | } |
| | 59 | |
|
| 0 | 60 | | private void UpdateWaypointAndPower() { |
| | 61 | | // Get the next waypoint and power setting from the attack behavior |
| | 62 | | // TODO: Implement support for SENSORS to update the track on the target position |
| 0 | 63 | | (_currentWaypoint, _currentPowerSetting) = |
| | 64 | | _attackBehavior.GetNextWaypoint(transform.position, _target.transform.position); |
| 0 | 65 | | } |
| | 66 | |
|
| 2 | 67 | | private Vector3 CalculateAccelerationInput() { |
| | 68 | | // Cache the transform and velocity. |
| 2 | 69 | | Transform threatTransform = transform; |
| 2 | 70 | | Vector3 right = threatTransform.right; |
| 2 | 71 | | Vector3 forward = threatTransform.forward; |
| 2 | 72 | | Vector3 position = threatTransform.position; |
| 2 | 73 | | Vector3 velocity = GetVelocity(); |
| 2 | 74 | | float speed = velocity.magnitude; |
| | 75 | |
|
| 2 | 76 | | IController controller = new PnController(this, _navigationGain); |
| 2 | 77 | | Vector3 accelerationInput = controller.PlanToWaypoint(_currentWaypoint); |
| | 78 | |
|
| | 79 | | // Clamp the normal acceleration input to the maximum normal acceleration. |
| 2 | 80 | | float maxNormalAcceleration = CalculateMaxNormalAcceleration(); |
| 2 | 81 | | accelerationInput = Vector3.ClampMagnitude(accelerationInput, maxNormalAcceleration); |
| | 82 | |
|
| | 83 | | // Avoid the ground when close to the surface and too low on the glideslope. |
| 2 | 84 | | float altitude = position.y; |
| | 85 | | // Sink rate is opposite to climb rate. |
| 2 | 86 | | float sinkRate = -velocity.y; |
| 2 | 87 | | float distanceToTarget = (_currentWaypoint - position).magnitude; |
| 2 | 88 | | float groundProximityThreshold = Mathf.Abs(sinkRate) * 5f; // Adjust threshold as necessary |
| 2 | 89 | | if (sinkRate > 0 && altitude / sinkRate < distanceToTarget / speed) { |
| | 90 | | // Evade upward normal to the velocity. |
| 0 | 91 | | Vector3 upwardsDirection = Vector3.Cross(forward, right); |
| | 92 | |
|
| | 93 | | // Blend between the calculated acceleration input and the upward acceleration. |
| 0 | 94 | | float blendFactor = 1 - (altitude / groundProximityThreshold); |
| 0 | 95 | | accelerationInput.y = |
| | 96 | | Vector3 |
| | 97 | | .Lerp(accelerationInput, upwardsDirection * CalculateMaxNormalAcceleration(), |
| | 98 | | blendFactor) |
| | 99 | | .y; |
| 0 | 100 | | } |
| | 101 | |
|
| 2 | 102 | | accelerationInput = Vector3.ClampMagnitude(accelerationInput, maxNormalAcceleration); |
| 2 | 103 | | _accelerationInput = accelerationInput; |
| 2 | 104 | | return accelerationInput; |
| 2 | 105 | | } |
| | 106 | |
|
| | 107 | | // Optional: Add this method to visualize debug information |
| 0 | 108 | | protected virtual void OnDrawGizmos() { |
| 0 | 109 | | if (Application.isPlaying) { |
| 0 | 110 | | Gizmos.color = Color.yellow; |
| 0 | 111 | | Gizmos.DrawLine(transform.position, _currentWaypoint); |
| | 112 | |
|
| 0 | 113 | | Gizmos.color = Color.green; |
| 0 | 114 | | Gizmos.DrawRay(transform.position, _accelerationInput); |
| 0 | 115 | | } |
| 0 | 116 | | } |
| | 117 | | } |