/// <summary> /// Method to set the path of an ai unit in order to dodge an object /// </summary> /// <param name="callingAI">ai to perform dodge</param> /// <param name="closestObstruction">closest obstruction</param> private void dodgeObject(DynamicObject callingAI, StaticObject closestObstruction) { if (!this.isObjectRegistered(callingAI)) return; PathInformation pathInfo = objectPaths[callingAI]; if (pathInfo.currentWaypoint == null) return; if (!dodgeInactiveCountDown.Keys.Contains(callingAI)) dodgeInactiveCountDown.Add(callingAI, RETAIN_DODGE_PATH_TICKS); else return; Vector3 dodgeWp = new Vector3(); bool bFlag = false; // Set the new path: float dodgeDistance = (callingAI.getBoundingSphere().Radius + closestObstruction.getBoundingSphere().Radius) * DODGE_DISTANCE_MULTIPLIER; float distanceToObject = (callingAI.Position - closestObstruction.Position).Length(); float distanceToCurrentWp = (callingAI.Position - pathInfo.currentWaypoint.Position).Length(); float dodgeAngle = (float)Math.Abs(Math.Atan2(distanceToObject, dodgeDistance)); for (int i = (int)Math.Ceiling(dodgeAngle); i * dodgeAngle < Math.PI; ++i) { for (int j = (int)Math.Ceiling(dodgeAngle); j * dodgeAngle < Math.PI; ++j) { if (isDodgeValid(callingAI, dodgeAngle, i, j, pathInfo, closestObstruction, dodgeDistance, ref dodgeWp)) { bFlag = true; break; } if (isDodgeValid(callingAI, -dodgeAngle, i, j, pathInfo, closestObstruction, dodgeDistance, ref dodgeWp)) { bFlag = true; break; } } if (bFlag) break; } List<Node> path = pathInfo.remainingPath; if (path.Count > 0) path.Remove(path.Last()); path.Add(new Node(dodgeWp, -1)); pathInfo.remainingPath = path; }
/// <summary> /// Performs a dogfight move against the opponent /// </summary> /// <param name="ti">Team on which the ai is registered</param> /// <param name="ai">Character to perform move</param> /// <param name="target">Opponent of the ai</param> public void doDogfightMove(TeamInformation ti, DynamicObject ai, StaticObject target) { if (!this.isObjectRegistered(ai)) return; float radiusToGoBehindTarget = (target.getBoundingSphere().Radius + ai.getBoundingSphere().Radius) * RADIUS_MULTIPLIER_TO_GO_BEHIND_TARGET; Vector3 wpPosition = target.Position + Vector3.Normalize(Matrix.CreateFromQuaternion(target.rotation).Forward) * radiusToGoBehindTarget; Vector3 wpDPosition = target.Position + Vector3.Normalize(Matrix.CreateFromQuaternion(target.rotation).Up) * radiusToGoBehindTarget / RADIUS_FACTOR_TO_GO_ABOVE_TARGET; if (Vector3.Dot(Vector3.Normalize(wpPosition - target.Position), Vector3.Normalize(ai.Position - target.Position)) < DOT_ANGLE_TO_STOP_DOGFIGHT_MOVE || (ai.Position - target.Position).Length() > CHASE_WHEN_FURTHER) { PathInformation fighterPath = objectPaths[ai]; List<Node> waypointList = fighterPath.remainingPath; //we clear the waypoint list and add new waypoints: if (waypointList.Count > 0) { bool shouldAddTopWaypt = (Vector3.Dot(Vector3.Normalize(Matrix.CreateFromQuaternion(target.rotation).Forward), Vector3.Normalize(target.Position - ai.Position)) > 0); if ((wpPosition - waypointList.ElementAt(0).Position).Length() > TARGET_WP_BUFFER || shouldAddTopWaypt) { waypointList.Clear(); if (shouldAddTopWaypt) waypointList.Insert(0, new Node(wpDPosition, -1)); waypointList.Insert(0, new Node(wpPosition, -1)); } } else { if (Vector3.Dot(Vector3.Normalize(Matrix.CreateFromQuaternion(target.rotation).Forward), Vector3.Normalize(target.Position - ai.Position)) > 0) waypointList.Insert(0, new Node(wpDPosition, -1)); waypointList.Insert(0, new Node(wpPosition, -1)); } fighterPath.remainingPath = waypointList; } else //stop navigation (we are behind the target so we can start shooting it) getPath(ai).Clear(); }