protected override Vector2 CalculateForce() { if (_menace == null || (Vehicle.Position - _menace.Position).sqrMagnitude > _sqrSafetyDistance) { return(Vector2.zero); } // offset from this to menace, that distance, unit vector toward menace var position = Vehicle.PredictFutureDesiredPosition(_predictionTime); var offset = _menace.Position - position; var distance = offset.magnitude; var roughTime = distance / _menace.Speed; var predictionTime = ((roughTime > _predictionTime) ? _predictionTime : roughTime); var target = _menace.PredictFuturePosition(predictionTime); // This was the totality of SteerToFlee var desiredVelocity = position - target; return(desiredVelocity - Vehicle.DesiredVelocity); }
protected override Vector2 CalculateForce() { if (_quarry == null) { enabled = false; return(Vector2.zero); } var force = Vector2.zero; var offset = _quarry.Position - Vehicle.Position; var distance = offset.magnitude; var radius = Vehicle.Radius + _quarry.Radius + _acceptableDistance; if (!(distance > radius)) { return(force); } var unitOffset = offset / distance; // how parallel are the paths of "this" and the quarry // (1 means parallel, 0 is pependicular, -1 is anti-parallel) var parallelness = Vector2.Dot(Vehicle.Forward, _quarry.Forward); // how "forward" is the direction to the quarry // (1 means dead ahead, 0 is directly to the side, -1 is straight back) var forwardness = Vector2.Dot(Vehicle.Forward, unitOffset); var directTravelTime = distance / Vehicle.Speed; // While we could parametrize this value, if we care about forward/backwards // these values are appropriate enough. var f = OpenSteerUtility.IntervalComparison(forwardness, -0.707f, 0.707f); var p = OpenSteerUtility.IntervalComparison(parallelness, -0.707f, 0.707f); float timeFactor = 0; // to be filled in below // Break the pursuit into nine cases, the cross product of the // quarry being [ahead, aside, or behind] us and heading // [parallel, perpendicular, or anti-parallel] to us. switch (f) { case +1: switch (p) { case +1: // ahead, parallel timeFactor = 4; break; case 0: // ahead, perpendicular timeFactor = 1.8f; break; case -1: // ahead, anti-parallel timeFactor = 0.85f; break; } break; case 0: switch (p) { case +1: // aside, parallel timeFactor = 1; break; case 0: // aside, perpendicular timeFactor = 0.8f; break; case -1: // aside, anti-parallel timeFactor = 4; break; } break; case -1: switch (p) { case +1: // behind, parallel timeFactor = 0.5f; break; case 0: // behind, perpendicular timeFactor = 2; break; case -1: // behind, anti-parallel timeFactor = 2; break; } break; } // estimated time until intercept of quarry var et = directTravelTime * timeFactor; var etl = (et > _maxPredictionTime) ? _maxPredictionTime : et; // estimated position of quarry at intercept var target = _quarry.PredictFuturePosition(etl); force = Vehicle.GetSeekVector(target, _slowDownOnApproach); #if ANNOTATE_PURSUIT Debug.DrawRay(Vehicle.Position, force, Color.blue); Debug.DrawLine(Quarry.Position, target, Color.cyan); Debug.DrawRay(target, Vector2.up * 4, Color.cyan); #endif return(force); }