| | | 1 | | using UnityEngine; |
| | | 2 | | |
| | | 3 | | // Speed escape detector. |
| | | 4 | | // |
| | | 5 | | // The speed escape detector checks whether the agent has a speed greater than the threat's when it |
| | | 6 | | // has navigated to the threat's current position. |
| | | 7 | | public class SpeedEscapeDetector : EscapeDetectorBase { |
| | | 8 | | // Minimum fractional speed to prevent division by zero. |
| | | 9 | | private const float _minFractionalSpeed = 1e-6f; |
| | | 10 | | |
| | 0 | 11 | | public SpeedEscapeDetector(IAgent agent) : base(agent) {} |
| | | 12 | | |
| | 0 | 13 | | public override bool IsEscaping(IHierarchical target) { |
| | 0 | 14 | | if (target == null) { |
| | 0 | 15 | | return false; |
| | | 16 | | } |
| | | 17 | | |
| | 0 | 18 | | float predictedAgentSpeed = CalculatePredictedAgentSpeed(target.Position); |
| | 0 | 19 | | return predictedAgentSpeed <= target.Speed; |
| | 0 | 20 | | } |
| | | 21 | | |
| | | 22 | | // Calculate the predicted agent speed when it has reached the target's current position. |
| | 0 | 23 | | private float CalculatePredictedAgentSpeed(in Vector3 targetPosition) { |
| | | 24 | | // The speed decays exponentially with the traveled distance and with the bearing change. |
| | 0 | 25 | | float distanceTimeConstant = 2 * (Agent.StaticConfig.BodyConfig?.Mass ?? 0) / |
| | | 26 | | (Constants.CalculateAirDensityAtAltitude(Agent.Position.y) * |
| | | 27 | | (Agent.StaticConfig.LiftDragConfig?.DragCoefficient ?? 0) * |
| | | 28 | | (Agent.StaticConfig.BodyConfig?.CrossSectionalArea ?? 0)); |
| | 0 | 29 | | float angleTimeConstant = Agent.StaticConfig.LiftDragConfig?.LiftDragRatio ?? 1; |
| | | 30 | | // During the turn, the minimum radius dictates the minimum distance needed to make the turn. |
| | 0 | 31 | | float minTurningRadius = Agent.Velocity.sqrMagnitude / Agent.MaxNormalAcceleration(); |
| | | 32 | | |
| | 0 | 33 | | Vector3 directionToTarget = targetPosition - Agent.Position; |
| | 0 | 34 | | float distanceToTarget = directionToTarget.magnitude; |
| | 0 | 35 | | float angleToTarget = Vector3.Angle(Agent.Velocity, directionToTarget) * Mathf.Deg2Rad; |
| | | 36 | | // The fractional speed is the product of the fractional speed after traveling the distance and |
| | | 37 | | // of the fractional speed after turning. |
| | 0 | 38 | | float fractionalSpeed = |
| | | 39 | | Mathf.Exp(-((distanceToTarget + angleToTarget * minTurningRadius) / distanceTimeConstant + |
| | | 40 | | angleToTarget / angleTimeConstant)); |
| | | 41 | | // Prevent division by zero. |
| | 0 | 42 | | fractionalSpeed = Mathf.Max(fractionalSpeed, _minFractionalSpeed); |
| | 0 | 43 | | return fractionalSpeed * Agent.Speed; |
| | 0 | 44 | | } |
| | | 45 | | } |