/// <summary>
 /// Constructs a new GetNextCommandSet command
 /// </summary>
 /// <param name="reference">the object to be handed to the AIManager</param>
 /// <param name="lastDistance">The last distance from the enemy to the player</param>
 public GetNextCommandSet(Enemy reference, int lastDistance)
 {
     this.reference = reference;
     this.lastDistance = lastDistance;
     Initialize();
 }
Ejemplo n.º 2
0
 /// <summary>
 /// Checks if a wall is between the enemy and the current player
 /// </summary>
 /// <param name="enemy">the enemy to check against</param>
 /// <returns>Whether or not the enemy can see the player</returns>
 private bool WallInWay(Enemy enemy)
 {
     //For each wall on the same floor as the enemy...
     foreach (var wall in level.walls.Where(x => x.location.Z == playerLoc.Z))
     {
         //If a collision is possible (ie the enemy and the player are not both on one side of the wall)...
         if ((enemy.center.X > wall.rectangle.Right && playerLoc.X > wall.rectangle.Right) ||
             (enemy.center.X < wall.rectangle.Left && playerLoc.X < wall.rectangle.Left) ||
             (enemy.center.Y > wall.rectangle.Top && playerLoc.Y > wall.rectangle.Top) ||
             (enemy.center.Y < wall.rectangle.Bottom && playerLoc.Y < wall.rectangle.Bottom))
         {
             //Create a vector between the player and the enemy
             Vector2 v = new Vector2(playerLoc.X - enemy.center.X, playerLoc.Y - enemy.center.Y);
             //Create vectors representing each of the wall's rectangle's sides
             Vector2[] wallVecs = new Vector2[4];
             wallVecs[0] = new Vector2(wall.rectangle.Left, wall.rectangle.Bottom - wall.rectangle.Top);
             wallVecs[1] = new Vector2(wall.rectangle.Right, wall.rectangle.Bottom - wall.rectangle.Top);
             wallVecs[2] = new Vector2(wall.rectangle.Right - wall.rectangle.Left, wall.rectangle.Top);
             wallVecs[3] = new Vector2(wall.rectangle.Right - wall.rectangle.Left, wall.rectangle.Bottom);
             bool checker = false;
             //For each wall side, if the sight line does not intersect the wall, return false.
             foreach (var wallVec in wallVecs)
             {
                 if (wallVec.X / v.X == wallVec.Y / v.Y)
                 {
                     checker = true;
                     break;
                 }
             }
             if (!checker)
                 continue;
         }
         return true;
     }
     return false;
 }
 public WaitForNextCommand(Enemy reference)
 {
     this.reference = reference;
 }
Ejemplo n.º 4
0
        /// <summary>
        /// Builds a path between two nodes, and converts it into a queue of movement commands
        /// </summary>
        /// <param name="start">The starting node</param>
        /// <param name="end">The ending node</param>
        /// <param name="reference">The enemy we are pathfinding for</param>
        /// <param name="commandsToCopy">The number of commands to copy to the queue before requesting new commands</param>
        /// <returns></returns>
        private Queue<ICommand> BuildPath(Vector3 start, Vector3 end, Enemy reference, int commandsToCopy)
        {
            //Build the path.
            List<IGraphNode> path = AStar.FindPath(map.Graph.GetNode((int)start.X, (int)start.Y, (int)start.Z), map.Graph.GetNode((int)end.X, (int)end.Y, (int)end.Z));
            //create a list of commands to translate between a list of nodes and a queue of commands
            List<ICommand> translationList = new List<ICommand>();
            //Populate the translation list with commands from the graph nodes.
            if (path == null)
            {
                return new Queue<ICommand>();
            }

            for (int i = 1; i < path.Count; i++)
            {
                var item = path[i];
                translationList.Add(new CommandMove(new Vector3(item.X * map.Graph.nodeWidth, item.Y * map.Graph.nodeHeight, item.Z), reference));
            }

            //if commandsToCopy is less than or equal to 0, then we don't want to add any extra commands in because it will be gotten elsewhere.
            if (commandsToCopy > -1)
            {
                //If the number of commands we are trying to input before requesting new commands is greater than the total number of commands, just stick it at the end of the list.
                if (commandsToCopy + 1 >= path.Count)
                    translationList.Insert(path.Count - 1, new GetNextCommandSet(reference, path[path.Count - 1].Cost));
                //Otherwise, place it after the number of commands it's trying to copy
                else
                    translationList.Insert(commandsToCopy + 1, new GetNextCommandSet(reference, path[commandsToCopy].Cost));

                //Copy a wait command to top off the list
                translationList.Add(new WaitForNextCommand(reference));
            }

            //Return a new queue of commands, gotten from the translation list
            return new Queue<ICommand>(translationList);
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Checks if a point lies within an enemy's vision cone
 /// </summary>
 /// <param name="enemy">enemy that needs to know if he can see</param>
 /// <param name="point">point that the enemy is trying to see</param>
 /// <returns>whether or not the point lies within the enemy</returns>
 private bool CanSee(Enemy enemy, Vector3 point)
 {
     //find the minimum angle in radians of the vision cone
     double minAngle = ((90 - (90 * enemy.direction)) - VISION_CONE_ANGLE_DEGREES) * DEG_TO_RAD;
     //find the maximum angle in radians of the vision cone
     double maxAngle = ((90 - (90 * enemy.direction)) + VISION_CONE_ANGLE_DEGREES) * DEG_TO_RAD;
     //find the angle between the enemy and the point
     double angle = -Math.Atan2((point.Y - enemy.center.Y), (point.X - enemy.center.X));
     //return if the angle is between the minimum angle and the maximum angle
     return angle < maxAngle && angle > minAngle;
 }
Ejemplo n.º 6
0
 /// <summary>
 /// Adds an enemy to the pursuit
 /// </summary>
 /// <param name="e">enemy to add to the pursuit</param>
 private void AddToPursuit(Enemy e)
 {
     //If a pursuit is not currently active, activate one
     if (!isPursuitActive)
     {
         currentPursuit = new HashSet<Enemy>();
         isPursuitActive = true;
     }
     //If the current enemy is already in the pursuit, don't add him in.
     if(!currentPursuit.Contains(e))
         currentPursuit.Add(e);
 }
Ejemplo n.º 7
0
        /// <summary>
        /// Runs the AI for the enemy passed in
        /// </summary>
        /// <param name="enemy">Enemy to run the AI on</param>
        public void RunAI(Enemy enemy)
        {
            //If our enemy state is unaware or aware but not actively pursuing, do this set of stuff.
            if (enemy.state < AI_STATE.HUNTING)
            {
                //If the enemy is on the same floor as the player, do stuff. Otherwise there's no way to see the player so don't bother
                if (enemy.center.Z == playerLoc.Z)
                {
                    //Find the distance between the player and the enemy
                    double dist = Vector3.DistanceSquared(enemy.location, playerLoc);
                    //If we are within vision radius, do stuff. Otherwise we can't see the player and the enemy goes on his merry way.
                    if (dist < MAX_VISION_RADIUS_SQUARED && CanSee(enemy, playerLoc) && !WallInWay(enemy))
                    {
                        //Update the player's last known location
                        lastKnownPlayerLoc = playerLoc;

                        //If the player is suspicious, rapidly increase his awareness based on the distance between him and us.
                        if (AIManager.SharedAIManager.PlayerIsSuspicious())
                        {
                            enemy.awareness += (MAX_VISION_RADIUS_SQUARED / dist) * .02;
                        }
                        //If the player isn't suspicious, slowly increase his awareness.
                        else
                        {
                            enemy.awareness += (MAX_VISION_RADIUS_SQUARED / dist) * .0009;
                        }
                        //If our enemy's awareness is greater than 1, begin pursuing the player.
                        if (enemy.awareness >= 1)
                        {
                            AddToPursuit(enemy);
                            SwitchPursuitState(AI_STATE.PURSUIT);
                        }
                    }
                }
            }
            //If our enemy state is currently pursuing the player
            if (enemy.state == AI_STATE.PURSUIT)
            {
                //Find the distance between the enemy in the player
                double dist = Vector3.DistanceSquared(enemy.location, playerLoc);
                //Find every enemy on the same floor as the player and within the current enemy's vision radius and add them to the current pursuit
                foreach (var other in level.basicEnemies.Where(x => x.location.Z == enemy.location.Z && Vector3.DistanceSquared(enemy.location, x.location) < MAX_VISION_RADIUS_SQUARED_PURSUIT))
                {
                    AddToPursuit(other);
                }
                //If the player is within the current vision radius and not behind any walls, update his current known location
                if (dist < MAX_VISION_RADIUS_SQUARED_PURSUIT)
                {
                    lastKnownPlayerLoc = playerLoc;
                }
                //If we can't see the player and are at the end of the path, switch the pursuit to hunting state because something went wrong.
                else if (map.Graph.GetNode((int)enemy.center.X, (int)enemy.center.Y, (int) enemy.center.Z) == map.Graph.GetNode((int)lastKnownPlayerLoc.X, (int)lastKnownPlayerLoc.Y, (int)lastKnownPlayerLoc.Z))
                {
                    SwitchPursuitState(AI_STATE.HUNTING);
                }
            }
            //If the enemy is currently hunting the player
            if (enemy.state == AI_STATE.HUNTING)
            {
                //slowly decrease the enemy's awareness
                enemy.awareness -= .0005;
                //If we are within vision radius, can see the player, and do not have a wall in the way...
                if (Vector3.DistanceSquared(enemy.location, playerLoc) < MAX_VISION_RADIUS_SQUARED_PURSUIT && CanSee(enemy, playerLoc) && !WallInWay(enemy))
                {
                    //give the player 1/6 of a second or less to get out of view range, and if he fails to do so re-enter pursuit mode.
                    enemy.awareness += .1;
                    if (enemy.awareness > 1)
                    {
                        lastKnownPlayerLoc = playerLoc;
                        SwitchPursuitState(AI_STATE.PURSUIT);
                    }
                }
                //If our awareness hits 0, exit hunting mode and resume normal pathfinding
                if (enemy.awareness <= 0)
                {
                    enemy.awareness = 0;
                    SwitchPursuitState(AI_STATE.AWARE);
                }
            }
        }
Ejemplo n.º 8
0
 /// <summary>
 /// Remove an enemy from the pursuit
 /// </summary>
 /// <param name="e">enemy to remove from the pursuit</param>
 public void RemoveFromPursuit(Enemy e)
 {
     //If the current pursuit doesn't have the enemy, don't bother removing it. Otherwise remove it.
     if(currentPursuit.Contains(e))
     {
         currentPursuit.Remove(e);
         //If the current pursuit is empty, end it.
         if (currentPursuit.Count == 0)
             isPursuitActive = false;
     }
 }
Ejemplo n.º 9
0
 /// <summary>
 /// Constructs a CommandMove object
 /// </summary>
 /// <param name="endPosition">The position we want to move to</param>
 /// <param name="reference">A reference to the enemy we are trying to move (we need access to it's Move method)</param>
 public CommandMove(Vector3 endPosition, Enemy reference)
 {
     this.reference = reference;
     this.endPosition = endPosition;
 }
        /// <summary>
        /// Makes an enemy object
        /// </summary>
        /// <param name="position">position to make the enemy at</param>
        /// <param name="commands">default commands</param>
        /// <returns>An enemy</returns>
        public static Enemy GenerateEnemy(Vector3 position, List<Tuple<string, string>> commands, int dir)
        {
            //Create a new enemy with the default starting variables and positions.
            Enemy temp = new Enemy(
                GameVariables.enemyMoveSpeed,
                GameVariables.enemyAnimations,
                GameVariables.enemyAnimationNames,
                position,
                new Rectangle((int)position.X, (int)position.Y,
                    GameVariables.tileWidth, GameVariables.tileHeight),
                    GameVariables.normalEnemyCash,
                    dir);

            //For each parseable command in the command list
            foreach (var parseable in commands)
            {
                //Add a new command based on the command's parameters
                switch (parseable.Item1.ToUpper().Trim('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'))
                {
                    case "MOVE":
                        //format is "X,Y,Z"
                        Vector3 moveTo = new Vector3();
                            string[] coords = parseable.Item2.Split(',');
                            float.TryParse(coords[0], out moveTo.X);
                            float.TryParse(coords[1], out moveTo.Y);
                            float.TryParse(coords[2], out moveTo.Z);
                            temp.defaultCommands.Enqueue(new CommandMove(moveTo, temp));
                        break;
                    case "WAIT":
                        int time = 0;
                        int.TryParse(parseable.Item2, out time);
                        temp.defaultCommands.Enqueue(new CommandWait(time));
                        break;
                    case "END ":
                        temp.defaultCommands.Enqueue(new GetNextCommandSet(temp, int.MaxValue));
                        temp.defaultCommands.Enqueue(new WaitForNextCommand(temp));
                        break;
                    default:
                        break;
                }
            }

            return temp;
        }