示例#1
0
        /// <summary>
        /// Checks if a particular dodge is valid
        /// </summary>
        private bool isDodgeValid(DynamicObject callingAI,float dodgeAngle,int dodgeAngleMultiplierYaw,int dodgeAngleMultiplierPitch,PathInformation pathInfo, StaticObject closestObstruction,float dodgeDistance, ref Vector3 dodgeWp)
        {
            bool bFlag = false;
            //Define a conal area around the current path to choose another path from
            Quaternion qRot = Quaternion.CreateFromYawPitchRoll(dodgeAngle * dodgeAngleMultiplierYaw, dodgeAngle * dodgeAngleMultiplierPitch, 0);
            Vector3 choiceVector = Vector3.Normalize(
                Vector3.Transform(pathInfo.currentWaypoint.Position - callingAI.Position,
                    Matrix.CreateFromQuaternion(qRot)));
            dodgeWp = callingAI.Position + choiceVector * dodgeDistance;
            if ((dodgeWp - closestObstruction.Position).Length() > dodgeDistance)
            {
                foreach (GridObjectInterface o in spatialGrid.checkNeighbouringBlocks(dodgeWp))
                {
                    if (o != callingAI)
                    {

                        if (o is StaticObject)
                        {
                            if ((o.Position - dodgeWp).Length() > (o.getBoundingSphere().Radius + callingAI.getBoundingSphere().Radius * (DODGE_DISTANCE_MULTIPLIER)))
                                bFlag = true;
                        }
                        if (o is DynamicObject)
                        {
                            if (isObjectRegistered(o as DynamicObject))
                            {
                                Node otherObjectsWaypoint = objectPaths[o as DynamicObject].currentWaypoint;
                                if (otherObjectsWaypoint != null)
                                {
                                    if ((otherObjectsWaypoint.Position - dodgeWp).Length() < (o.getBoundingSphere().Radius + callingAI.getBoundingSphere().Radius * (DODGE_DISTANCE_MULTIPLIER)))
                                        bFlag = false;
                                }
                            }
                        }
                        if (!spatialGrid.isInGrid(new Node(dodgeWp,-1)))
                            bFlag = false;
                    }
                }
            }
            return bFlag;
        }
示例#2
0
 /// <summary>
 /// Checks if there are any obstructions in close proximity which must be dodged
 /// </summary>
 /// <param name="AIObject">ai object to check around</param>
 /// <returns>list of possible obstructions</returns>
 private List<StaticObject> obstructionsInCloseProximity(DynamicObject AIObject)
 {
     List<StaticObject> results = new List<StaticObject>();
     foreach (GridObjectInterface obj in this.spatialGrid.checkNeighbouringBlocks(AIObject))
     {
         if (obj is StaticObject && !(obj is Bullet || obj is Missile))
         {
             float radiusToCheck = (obj.getBoundingSphere().Radius + AIObject.getBoundingSphere().Radius) * DODGE_DISTANCE_MULTIPLIER;
             if ((AIObject.Position - obj.Position).Length() <= radiusToCheck)
             {
                     results.Add(obj as StaticObject);
             }
         }
     }
     return results;
 }
示例#3
0
        /// <summary>
        /// Method to test if a collision will occur on the current route of the calling ai (and which collision will occur first). If such
        /// a possible collision is detected the callingAI will attempt to dodge the object.
        /// </summary>
        /// <param name="callingAI">AI that the test is performed for.</param>
        /// <param name="obstructionsList">A list of obstructions as returned by PathIntersectTest</param>
        private void avoidCollisions(DynamicObject callingAI, List<StaticObject> obstructionsList)
        {
            //find the closest obstruction and dodge it:
            if (obstructionsList.Count == 0) return;

            PathInformation pathInfo = objectPaths[callingAI];
            StaticObject closestObstruction = obstructionsList.First();
            float closestObstructionDistance = (closestObstruction.Position - callingAI.Position).Length();

            for (int i = 1; i < obstructionsList.Count; ++i)
            {
                StaticObject obstruction = obstructionsList.ElementAt(i);
                float distanceToObstruction = (obstruction.Position - callingAI.Position).Length();
                if (distanceToObstruction < closestObstructionDistance)
                {
                    closestObstruction = obstruction;
                    closestObstructionDistance = distanceToObstruction;
                }
            }
            if (closestObstruction is DynamicObject)
                if (isObjectRegistered(closestObstruction as DynamicObject))
                    if (objectPaths[closestObstruction as DynamicObject].currentWaypoint != null)
                        if (objectPaths[closestObstruction as DynamicObject].currentWaypoint.connectedEdges.Count == 0 || closestObstruction is playerObject)
                            return; // that object is dodging already don't make it stop
            //Make the obstruction yield for the next few steps:
            if (closestObstruction is DynamicObject)
                if (!movementYieldList.Keys.Contains(closestObstruction as DynamicObject))
                    movementYieldList.Add(closestObstruction as DynamicObject, YIELD_TICKS);

            //Now dodge it:
            dodgeObject(callingAI, closestObstruction);
        }
示例#4
0
        /// <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;
        }
示例#5
0
 /// <summary>
 /// Sets a new path for an object if it is already registered
 /// </summary>
 /// <param name="AIObject">Any registered dynamic object</param>
 /// <param name="start">Start node (should be close to the object if possible)</param>
 /// <param name="end">End node</param>
 public void setNewPathForRegisteredObject(DynamicObject AIObject, Node start, Node end)
 {
     if (objectPaths.Keys.Contains(AIObject))
     {
         List<Node> path = AStar(start, end, AIObject is Destroyer);
         if (path != null)
             objectPaths[AIObject].remainingPath = path;
         else //we just go the the start node
         {
             path = new List<Node>();
             path.Add(start);
             objectPaths[AIObject].remainingPath = path;
         }
     }
 }
示例#6
0
        /// <summary>
        /// Turns the ai to face towards the a waypoint
        /// </summary>
        /// <param name="vWantDir"></param>
        /// <param name="vLookDir"></param>
        /// <param name="objectToTurn"></param>
        /// <param name="currentWaypoint"></param>
        /// <param name="gt"></param>
        internal void turnAI(ref Vector3 vWantDir, ref Vector3 vLookDir, DynamicObject objectToTurn, Vector3 currentWaypoint, GameTime gt)
        {
            //Calculate yaw and pitch for view direction and target direction
            vWantDir = Vector3.Normalize(currentWaypoint - objectToTurn.Position);
            vLookDir = Vector3.Normalize(-Matrix.CreateFromQuaternion(objectToTurn.rotation).Forward);
            float distance = (float)Math.Sqrt(vWantDir.Z * vWantDir.Z + vWantDir.X * vWantDir.X);
            float tpitch = distance == 0 ? (float)Math.Sign(-vWantDir.Y) * (float)Math.PI / 2 : -(float)Math.Atan2(vWantDir.Y, distance);
            float tyaw = (float)Math.Atan2(vWantDir.X, vWantDir.Z);
            distance = (float)Math.Sqrt(vLookDir.Z * vLookDir.Z + vLookDir.X * vLookDir.X);
            float cyaw = (float)Math.Atan2(vLookDir.X, vLookDir.Z);
            float cpitch = distance == 0 ? (float)Math.Sign(-vLookDir.Y) * (float)Math.PI / 2 : -(float)Math.Atan2(vLookDir.Y, distance);
            //now rotate towards the target yaw and pitch
            float diffy = tyaw - cyaw;
            float diffp = tpitch - cpitch;

            //get the direction we need to rotate in:
            if (Math.Abs(diffy) > Math.PI)
                if (tyaw > cyaw)
                    diffy = -(float)(Math.PI * 2 - Math.Abs(diffy));
                else
                    diffy = (float)(Math.PI * 2 - Math.Abs(diffy));

            if (Math.Abs(diffp) > Math.PI)
                if (tpitch > cpitch)
                    diffp = -(float)(Math.PI * 2 - Math.Abs(diffp));
                else
                    diffp = (float)(Math.PI * 2 - Math.Abs(diffp));

            if (Math.Abs(diffp) > Math.Abs(objectToTurn.getpitchSpeed) * (float)(gt.ElapsedGameTime.TotalSeconds))
                diffp = Math.Sign(diffp) * Math.Abs(objectToTurn.getpitchSpeed) * (float)(gt.ElapsedGameTime.TotalSeconds);
            if (Math.Abs(diffy) > Math.Abs(objectToTurn.getYawSpeed) * (float)(gt.ElapsedGameTime.TotalSeconds))
                diffy = Math.Sign(diffy) * Math.Abs(objectToTurn.getYawSpeed) * (float)(gt.ElapsedGameTime.TotalSeconds);

            //special case: deal with the pitch if its PI/2 or -PI/2, because if its slightly off it causes problems:
            if (Math.Abs(Math.Abs(tpitch) - Math.PI / 2) <= EPSILON_DISTANCE && !(Math.Abs(diffy) <= EPSILON_DISTANCE))
                objectToTurn.rotation = Quaternion.CreateFromYawPitchRoll(tyaw, tpitch, 0);
            else
                objectToTurn.rotation = Quaternion.CreateFromYawPitchRoll(cyaw + diffy, cpitch + diffp, 0);
        }
示例#7
0
 /// <summary>
 /// Method to register an object for computer-based navigation
 /// </summary>
 /// <param name="AIObject">Any dynamic object capable of moving</param>
 public void registerObject(DynamicObject AIObject)
 {
     if (!objectPaths.Keys.Contains(AIObject))
         objectPaths.Add(AIObject, new PathInformation());
 }
示例#8
0
 /// <summary>
 /// Checks if an object is registered in the navigation computer
 /// </summary>
 /// <param name="AIObject">Object to check</param>
 /// <returns>true iff object is registered</returns>
 public bool isObjectRegistered(DynamicObject AIObject)
 {
     return objectPaths.Keys.Contains(AIObject);
 }
示例#9
0
 /// <summary>
 /// Method to get the current Path of a registered object
 /// </summary>
 /// <param name="o">registered object</param>
 /// <returns>path if it exists. Either an empty list or Null otherwise</returns>
 public List<Node> getPath(DynamicObject o)
 {
     return objectPaths[o].remainingPath;
 }
示例#10
0
        /// <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();
        }
示例#11
0
 /// <summary>
 /// Method to deregister an object in order to stop computer-based navigation for that object
 /// </summary>
 /// <param name="AIObject">Currently registered dynamic object</param>
 public void deregisterObject(DynamicObject AIObject)
 {
     if (objectPaths.Keys.Contains(AIObject))
         objectPaths.Remove(AIObject);
 }