public GoldMine(Game game, Node node, Graph graph, AIAgent agent) :base (game, node, graph, agent, Color.White) { spriteName = "goldMine"; this.node = node; this.node.IsBlocked = true; this.Position = node.Position * Game1.graphSize; this.Position = new Vector2(Position.X + 16, Position.Y + 16); resourceRemaining = maxResource; goldText = new TextRepresentation(game, Position); game.Components.Add(goldText); }
public Building(Game game, Node node, Graph graph, AIAgent agent, Color renderColor) : base(game) { this.graph = graph; this.renderColor = renderColor; this.game = game; Position = node.Position * Game1.graphSize; Position = new Vector2(Position.X + 16, Position.Y + 16); healthText = new TextRepresentation(game, new Vector2(Position.X, Position.Y - 8)); game.Components.Add(healthText); LoadContent(); }
public Base(Game1 game, Node node, Graph graph, AIAgent agent) :base(game, node, graph, agent, agent.RenderColor) { buildingType = BuildingType.Base; spriteName = "base"; this.agent = agent; this.node = node; isOperational = true; this.node.IsBlocked = true; this.Position = node.Position * Game1.graphSize; this.Position = new Vector2(Position.X + 16, Position.Y + 16); health = 1000; maxHealth = 1000; }
public Barracks(Game game, Node node, Graph graph, AIAgent agent) :base (game, node, graph, agent, agent.RenderColor) { buildingType = BuildingType.Barracks; spriteName = "barracks"; this.agent = agent; this.node = node; isOperational = false; this.node.IsBlocked = true; timeToCreate = 60000; //60 seconds maxHealth = 1500; health = 1; agent.GoldCount -= 500; agent.buildings.UnfinishedBuildings.Add(this); }
/// <summary> /// Compares the two nodes and sends back the nodes neighbor. /// </summary> /// <param name="node">the node we want to fight the neighbor of</param> /// <returns>the neighbor</returns> public Node GetNeighbor(Node node) { if (node == first) { return second; } else if (node == second) { return first; } else { return null; } }
public GoldRefinery(Game game, Node node, Graph graph, AIAgent agent) : base(game, node, graph, agent, agent.RenderColor) { buildingType = BuildingType.GoldRefinery; spriteName = "goldRefinery"; this.agent = agent; this.node = node; this.node.IsBlocked = true; this.Position = node.Position * Game1.graphSize; this.Position = new Vector2(Position.X + 16, Position.Y + 16); agent.buildings.UnfinishedBuildings.Add(this); timeToCreate = 45000; //45 seconds maxHealth = 1000; health = 1; agent.GoldCount -= 400; }
public AIAgent(Game game, Node location, Graph graph, List<GoldMine> goldMines, Color renderColor) : base(game) { this.renderColor = renderColor; Base myBase = new Base((Game1)game, location, graph, this); game.Components.Add(myBase); units = new Units(); buildings = new Buildings(); buildings.GetBase = myBase; buildings.GetGoldMines = goldMines; goldText = new TextRepresentation(game, new Vector2(buildings.GetBase.Position.X, buildings.GetBase.Position.Y + 8)); Game.Components.Add(goldText); this.goldMines = goldMines; foreach (GoldMine mine in goldMines) { if (Vector2.Distance(mine.Position, buildings.GetBase.Position) < distanceToNearestGoldMine) { distanceToNearestGoldMine = Vector2.Distance(mine.Position, buildings.GetBase.Position); buildings.NearestGoldMine = mine; } } }
public override void Update(GameTime gameTime) { base.Update(gameTime); if (!isActive) { goldText.Text = ""; return; } goldText.Position = new Vector2(position.X - 8, position.Y - 8); goldText.Text = goldCount.ToString(); if (peonState == PeonState.Moving) { if (Vector2.Distance(position, curTarget) < slowRadius + 5 && targetPath.Count > 2) { if (!graph.IsNodeBlocked(targetPath.Peek())) { curTarget = targetPath.Pop(); if (!graph.IsNodeBlocked(targetPath.Peek())) { curTarget = (curTarget + targetPath.Pop()) / 2; } else { peonState = PeonState.Idle; return; } } else { peonState = PeonState.Idle; return; } curTarget = new Vector2(curTarget.X + sprite.Width / 2, curTarget.Y + sprite.Height / 2); } else if (Vector2.Distance(position, curTarget) < slowRadius + 5 && targetPath.Count > 0) { if (!graph.IsNodeBlocked(targetPath.Peek())) { curTarget = targetPath.Pop(); } else { peonState = PeonState.Idle; } curTarget = new Vector2(curTarget.X + sprite.Width / 2, curTarget.Y + sprite.Height / 2); } else if (targetPath.Count == 0 && Vector2.Distance(position, curTarget) < stopRadius) { if (graph.IsNodeBlocked(position)) { MoveToLocation(targetLocation); return; } graph.SetNodeBlocked(position); peonState = PeonState.Idle; } //rotate based on orientation base.rotation = (float)Math.Atan2(orientation.X, -orientation.Y); acceleration = curTarget - this.Position; distance = Math.Abs(acceleration.Length()); if (distance < stopRadius) { speed = 0; } else if (distance < slowRadius) { speed = maxSpeed * distance / slowRadius; } else { speed = maxSpeed; } oldVelocity = velocity; acceleration = Vector2.Normalize(curTarget - this.Position) * maxAccel; velocity += velocity * gameTime.ElapsedGameTime.Milliseconds + .5f * acceleration * gameTime.ElapsedGameTime.Milliseconds * gameTime.ElapsedGameTime.Milliseconds; velocity = Vector2.Normalize(velocity) * speed; position += velocity; if (velocity != Vector2.Zero) { orientation = velocity; } } else if (peonState == PeonState.Idle) { if (peonObjective == PeonObjective.GoToBuild) { curNode = graph.GetNode(position); foreach (Edge edge in curNode.Neighbors) { tempNode = edge.GetNeighbor(curNode); //searches through the neighbor nodes to make sure it isnt on the wall or next to something else. if (!tempNode.IsBlocked) { canBuild = true; foreach (Edge innerEdge in tempNode.Neighbors) { if (innerEdge.GetNeighbor(tempNode).IsBlocked && innerEdge.GetNeighbor(tempNode) != curNode) { canBuild = false; } } if (canBuild) { agent.IsAgentGoingToBuildSomething = false; if (buildingType == Building.BuildingType.GoldRefinery) { GoldRefinery newRefinery = new GoldRefinery(game, tempNode, graph, agent); Game.Components.Add(newRefinery); peonObjective = PeonObjective.Build; return; } else if (buildingType == Building.BuildingType.Barracks) { Barracks newBarracks = new Barracks(game, tempNode, graph, agent); Game.Components.Add(newBarracks); peonObjective = PeonObjective.Build; return; } } } } } graph.SetNodeBlocked(position); } else if (peonState == PeonState.Mining) { graph.SetNodeBlocked(position); if (goldMine.GoldRemaining == 0) { peonState = PeonState.Idle; } else if (goldCount != goldCountMax) { timer += gameTime.ElapsedGameTime.Milliseconds; if (timer >= timeToGetGold) { timer = 0; if (goldToGetPerTime > goldMine.GoldRemaining) { goldCount += goldMine.TakeResource(goldMine.GoldRemaining); peonState = PeonState.Idle; } if (goldCount + goldToGetPerTime > goldCountMax) { goldCount += goldMine.TakeResource(goldCountMax - goldCount); } else { goldCount += goldMine.TakeResource(goldToGetPerTime); } } } else { peonState = PeonState.Idle; } } }
/// <summary> /// Replaces the priorty of a node if a shorter path is found /// </summary> /// <param name="value">Node to replace the priority of</param> /// <param name="priority">New priority to set to the node</param> public void ReplacePriority(Node value, float priority) { int index = 0; for (int i = 0; i < values.Count; i++) { if (values[i] == value) { index = i; } } values.RemoveAt(index); priorities.RemoveAt(index); values.Add(value); priorities.Add(priority); }
public Graph(int width, int height) { this.width = width; this.height = height; //Initializes the node array nodeGrid = new Node[width, height]; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { nodeGrid[x, y] = new Node(new Vector2(x, y)); } } //Sets the neighbors of each node for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { //if node has 8 neighbors if (x != 0 && x != width - 1 && y != 0 && y != height - 1) { nodeGrid[x, y].Neighbors = new List<Edge> { new Edge(nodeGrid[x, y], nodeGrid[x, y + 1], 1), new Edge(nodeGrid[x, y], nodeGrid[x + 1, y], 1), new Edge(nodeGrid[x, y], nodeGrid[x, y - 1], 1), new Edge(nodeGrid[x, y], nodeGrid[x - 1, y], 1), new Edge(nodeGrid[x, y], nodeGrid[x - 1, y - 1], (float)Math.Sqrt(2)), new Edge(nodeGrid[x, y], nodeGrid[x + 1, y - 1], (float)Math.Sqrt(2)), new Edge(nodeGrid[x, y], nodeGrid[x - 1, y + 1], (float)Math.Sqrt(2)), new Edge(nodeGrid[x, y], nodeGrid[x + 1, y + 1], (float)Math.Sqrt(2)),}; } //if node has 3 neighbors else if ((x == 0 || x == width - 1) && (y == 0 || y == height - 1)) { if (x == 0 && y == 0) { nodeGrid[x, y].Neighbors = new List<Edge> { new Edge(nodeGrid[x, y], nodeGrid[x, y + 1], 1), new Edge(nodeGrid[x, y], nodeGrid[x + 1, y], 1), new Edge(nodeGrid[x, y], nodeGrid[x + 1, y + 1], (float)Math.Sqrt(2)) }; } else if (x == 0 && y == height - 1) { nodeGrid[x, y].Neighbors = new List<Edge> { new Edge(nodeGrid[x, y], nodeGrid[x + 1, y], 1), new Edge(nodeGrid[x, y], nodeGrid[x, y - 1], 1), new Edge(nodeGrid[x, y], nodeGrid[x + 1, y - 1], (float)Math.Sqrt(2)) }; } else if (x == width - 1 && y == 0) { nodeGrid[x, y].Neighbors = new List<Edge> { new Edge(nodeGrid[x, y], nodeGrid[x, y + 1], 1), new Edge(nodeGrid[x, y], nodeGrid[x - 1, y], 1), new Edge(nodeGrid[x, y], nodeGrid[x - 1, y + 1], (float)Math.Sqrt(2)) }; } else if (x == width - 1 && y == height - 1) { nodeGrid[x, y].Neighbors = new List<Edge> { new Edge(nodeGrid[x, y], nodeGrid[x, y - 1], 1), new Edge(nodeGrid[x, y], nodeGrid[x - 1, y], 1), new Edge(nodeGrid[x, y], nodeGrid[x - 1, y - 1], (float)Math.Sqrt(2)) }; } } //if node has 5 neighbors else { if (x == 0) { nodeGrid[x, y].Neighbors = new List<Edge> { new Edge(nodeGrid[x, y], nodeGrid[x, y + 1], 1), new Edge(nodeGrid[x, y], nodeGrid[x + 1, y], 1), new Edge(nodeGrid[x, y], nodeGrid[x, y - 1], 1), new Edge(nodeGrid[x, y], nodeGrid[x + 1, y + 1], (float)Math.Sqrt(2)), new Edge(nodeGrid[x, y], nodeGrid[x + 1, y - 1], (float)Math.Sqrt(2))}; } else if (x == width - 1) { nodeGrid[x, y].Neighbors = new List<Edge> { new Edge(nodeGrid[x, y], nodeGrid[x, y + 1], 1), new Edge(nodeGrid[x, y], nodeGrid[x, y - 1], 1), new Edge(nodeGrid[x, y], nodeGrid[x - 1, y], 1), new Edge(nodeGrid[x, y], nodeGrid[x - 1, y - 1], (float)Math.Sqrt(2)), new Edge(nodeGrid[x, y], nodeGrid[x - 1, y + 1], (float)Math.Sqrt(2))}; } else if (y == 0) { nodeGrid[x, y].Neighbors = new List<Edge> { new Edge(nodeGrid[x, y], nodeGrid[x, y + 1], 1), new Edge(nodeGrid[x, y], nodeGrid[x + 1, y], 1), new Edge(nodeGrid[x, y], nodeGrid[x - 1, y], 1), new Edge(nodeGrid[x, y], nodeGrid[x - 1, y + 1], (float)Math.Sqrt(2)), new Edge(nodeGrid[x, y], nodeGrid[x + 1, y + 1], (float)Math.Sqrt(2))}; } else if (y == height - 1) { nodeGrid[x, y].Neighbors = new List<Edge> { new Edge(nodeGrid[x, y], nodeGrid[x + 1, y], 1), new Edge(nodeGrid[x, y], nodeGrid[x, y - 1], 1), new Edge(nodeGrid[x, y], nodeGrid[x - 1, y], 1), new Edge(nodeGrid[x, y], nodeGrid[x - 1, y - 1], (float)Math.Sqrt(2)), new Edge(nodeGrid[x, y], nodeGrid[x + 1, y - 1], (float)Math.Sqrt(2))}; } } } } }
/// <summary> /// Returns the priorty of a node /// </summary> /// <param name="node">Node to get the priority of</param> /// <returns>Priorty of the node</returns> public float GetPriority(Node node) { for (int i = 0; i < values.Count; i++) { if (values[i] == node) { return priorities[i]; } } return 0; }
/// <summary> /// Searches through the list to find the node with the highest priority and returns it/ /// </summary> /// <param name="topValue">Node with highest priority</param> /// <param name="topPriority">Priority value of that node</param> public void Dequeue(out Node topValue, out float topPriority) { int bestIndex = 0; float bestPriority = priorities[0]; for (int i = 1; i < priorities.Count; i++) { if (bestPriority > priorities[i]) { bestPriority = priorities[i]; bestIndex = i; } } topValue = values[bestIndex]; topPriority = bestPriority; values.RemoveAt(bestIndex); priorities.RemoveAt(bestIndex); }
public void Enqueue(Node value, float priority) { values.Add(value); priorities.Add(priority); }
/// <summary> /// Uses A* to find the fastest path to the goal /// </summary> /// <param name="start">Start location of path</param> /// <param name="finish">Finish location of path</param> /// <returns>Queue of locations which is the path</returns> public Stack<Vector2> ComputePath(Vector2 start, Vector2 finish) { //Initialize our variables start = new Vector2(start.X / (Game1.WINDOW_WIDTH / width), start.Y / (Game1.WINDOW_HEIGHT / height)); finish = new Vector2(finish.X / (Game1.WINDOW_WIDTH / width), finish.Y / (Game1.WINDOW_HEIGHT / height)); nodeQueue = new PriorityQueue(); targetPath = new Stack<Vector2>(); nodeQueue.Enqueue(nodeGrid[(int)start.X, (int)start.Y], 0); nodeGrid[(int)start.X, (int)start.Y].IsVisited = true; while (nodeQueue.Count > 0) { nodeQueue.Dequeue(out curNode, out topPriority); //If we have found the target node if (curNode == nodeGrid[(int)finish.X, (int)finish.Y]) { targetPath.Push(new Vector2(curNode.Position.X * (Game1.WINDOW_WIDTH / width), curNode.Position.Y * (Game1.WINDOW_HEIGHT / height))); //Loop back through the backnodes to find the fastest path and add them to the targetPath variable while (curNode.BackNode != null) { curNode = curNode.BackNode.GetNeighbor(curNode); targetPath.Push(new Vector2(curNode.Position.X * (Game1.WINDOW_WIDTH / width), curNode.Position.Y * (Game1.WINDOW_HEIGHT / height))); } ResetGraph(); return targetPath; } //Look through each neighbor to find who we have not checked yet foreach (Edge edge in curNode.Neighbors) { float priority = curNode.Length + edge.Length + Vector2.Distance(edge.GetNeighbor(curNode).Position, nodeGrid[(int)finish.X, (int)finish.Y].Position); if (!edge.GetNeighbor(curNode).IsVisited && !edge.GetNeighbor(curNode).IsBlocked) { edge.GetNeighbor(curNode).IsVisited = true; edge.GetNeighbor(curNode).BackNode = edge; nodeQueue.Enqueue(edge.GetNeighbor(curNode), priority); edge.GetNeighbor(curNode).Length = curNode.Length + edge.Length; } else if (edge.GetNeighbor(curNode).IsVisited && !edge.GetNeighbor(curNode).IsBlocked) { if (edge.GetNeighbor(curNode).Length > curNode.Length + edge.Length) { nodeQueue.ReplacePriority(edge.GetNeighbor(curNode), priority); edge.GetNeighbor(curNode).Length = curNode.Length + edge.Length; edge.GetNeighbor(curNode).BackNode = edge; } } } } //if unit cannot find path, dont move him targetPath.Clear(); ResetGraph(); return targetPath; }
/// <summary> /// Constructor for the Edge. /// </summary> /// <param name="first">The first end of the edge.</param> /// <param name="second">The second end of the edge.</param> /// <param name="length">The distance between the edges.</param> public Edge(Node first, Node second, float length) { this.first = first; this.second = second; this.length = length; }