private bool SearchForPath(cAI ai, Node currentNode) { //Gets list of passable neighbours and then sorts them by the estimated distance traveled if taking this node on the path (F) and sets current node to closed currentNode.State = NodeState.Closed; List <Node> passableNeighbours = GetPassableNeighbours(ai, currentNode); passableNeighbours.Sort((node1, node2) => node1.F.CompareTo(node2.F)); //Recursively searches through each neighbour until the shortest path is found if a valid path is available foreach (Node passableNeighbour in passableNeighbours) { if (passableNeighbour.Location == ai.TargetNodeLocation) { return(true); } else { if (SearchForPath(ai, passableNeighbour)) { return(true); } } } return(false); }
private void SetNextNode(cAI ai) { //Updates current node location then finds next node in the path and sets it as the next node ai.CurrentNodeLocation = ai.NextNodeLocation; //Ensures path has at least more than one value in it or finds another target and path if (ai.Path.Count() > 1) { ai.NextNode = ai.Path[ai.PathNodesTraversed]; ai.NextNodeLocation = map[(int)ai.Path[ai.PathNodesTraversed].X, (int)ai.Path[ai.PathNodesTraversed].Y].Location; ai.NextSet = true; } else { SetTargetNode(ai); SetRandomPath(ai); } }
private List <Node> GetPassableNeighbours(cAI ai, Node currentNode) { List <Node> passableNeighbours = new List <Node>(); //Gets all neighbouring nodes of current node List <Node> neighbours = GetNeighbours(ai, currentNode); //Gets all walkable nodes in the neighbouring nodes that are more efficient nodes to use in the path than the currently chosen node foreach (Node neighbour in neighbours) { //Ignores closed nodes if (neighbour.State == NodeState.Closed) { continue; } //Ignores unpassable nodes if (!neighbour.Passable) { continue; } //If node has already been tested, tests to see if traversing the neighbouring node will be more efficient from this node than its parents node, then adds it to passable neighbours if it is if (neighbour.State == NodeState.Open) { float gDistance = new Vector3(neighbour.Location - neighbour.ParentNode.Location).Length; float tempGDistance = currentNode.G + gDistance; if (tempGDistance < neighbour.G) { neighbour.ParentNode = currentNode; passableNeighbours.Add(neighbour); } } //If node is currently untested, adds it to the passable neighbours list and sets it to Open State else { neighbour.ParentNode = currentNode; neighbour.State = NodeState.Open; passableNeighbours.Add(neighbour); } } return(passableNeighbours); }
private void SetRandomPath(cAI ai) { Node currentNode = map[(int)ai.CurrentNode.X, (int)ai.CurrentNode.Y]; ai.Path.Clear(); //Calculates total direct distance between nodes and target node for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { if (!(i == ai.CurrentNode.X && j == ai.CurrentNode.Y)) { map[i, j].H = new Vector3(map[i, j].Location - ai.TargetNodeLocation).Length; } map[i, j].ParentNode = null; map[i, j].State = NodeState.Untested; } } //Returns true if a valid path to the target node can be found bool pathFound = SearchForPath(ai, currentNode); //If path is found, back tracks through the nodes in the path using the parent nodes to retrieve the complete path and then stores in a list from starting node to target node if (pathFound) { Node node = map[(int)ai.TargetNode.X, (int)ai.TargetNode.Y]; while (node.ParentNode != null) { ai.Path.Add(new Vector2(node.mapX, node.mapY)); node = node.ParentNode; } ai.Path.Reverse(); ai.PathSet = true; } //Prints out path in console for debugging purposes foreach (Vector2 node in ai.Path) { //Console.WriteLine(node.X + ", " + node.Y); } }
private void SetTargetNode(cAI ai) { bool targetSet = false; int randomX = 0; int randomY = 0; //Randomly chooses a target node that is passable on the map grid while (!targetSet) { randomX = rnd.Next(1, rows); randomY = rnd.Next(1, columns); //Ensures that the chosen target node is passable, then sets new target node if (map[randomX, randomY].Passable == true) { ai.TargetNode = new Vector2(randomX, randomY); ai.TargetNodeLocation = map[randomX, randomY].Location; targetSet = true; ai.TargetSet = true; ai.PathNodesTraversed = 0; } } }
private List <Node> GetNeighbours(cAI ai, Node currentNode) { List <Node> neighbours = new List <Node>(); //Gets neighbour above current node if (currentNode.Directions.Contains(NodeDirection.Up)) { neighbours.Add(map[(int)currentNode.mapX, (int)currentNode.mapY + 1]); } //Gets neighbour below current node if (currentNode.Directions.Contains(NodeDirection.Down)) { neighbours.Add(map[(int)currentNode.mapX, (int)currentNode.mapY - 1]); } //Gets neighbour right of current node if (currentNode.Directions.Contains(NodeDirection.Right)) { neighbours.Add(map[(int)currentNode.mapX + 1, (int)currentNode.mapY]); } //Gets neighbour left of current node if (currentNode.Directions.Contains(NodeDirection.Left)) { neighbours.Add(map[(int)currentNode.mapX - 1, (int)currentNode.mapY]); } //Diagonal movement //Top Right //neighbours.Add(map[(int)currentNode.mapX + 1, (int)currentNode.mapY + 1]); //Bottom Right //neighbours.Add(map[(int)currentNode.mapX + 1, (int)currentNode.mapY - 1]); //Top Left //neighbours.Add(map[(int)currentNode.mapX - 1, (int)currentNode.mapY + 1]); //Bottom Left //neighbours.Add(map[(int)currentNode.mapX - 1, (int)currentNode.mapY - 1]); return(neighbours); }
public void OnAction() { foreach (oEntity entity in entityList) { //Retrieves list of components from current entity List <IComponent> components = entity.Components; //Retrieves transform component from current entity IComponent transformComponent = components.Find(delegate(IComponent component) { return(component.ComponentMask == ComponentMasks.COMPONENT_TRANSFORM); }); //Sets transform if not already set if (((cTransform)transformComponent).SetTransform == false) { UpdateTransform((cTransform)transformComponent); ((cTransform)transformComponent).SetTransform = true; } //Retrieves speed component from current entity IComponent speedComponent = components.Find(delegate(IComponent component) { return(component.ComponentMask == ComponentMasks.COMPONENT_SPEED); }); //Retrieves AI component from current entity IComponent aiComponent = components.Find(delegate(IComponent component) { return(component.ComponentMask == ComponentMasks.COMPONENT_AI); }); #region AI movement //Checks if the entity has an AI component, then applies movement based on AI path if (aiComponent != null && ((cAI)aiComponent).DestinationReached != true) { cAI ai = ((cAI)aiComponent); float velocity = ((cSpeed)speedComponent).Speed; cTransform transform = ((cTransform)transformComponent); Vector3 direction; float angle; //Finds the direction towards the target node direction = new Vector3(ai.NextNodeLocation - transform.Translation).Normalized(); //Finds the angle between the target direction and the agent forward vector angle = (float)(Math.Atan2(direction.X, direction.Z) - Math.Atan2(transform.Right.X, transform.Right.Z)); //if the angle is over 180 in either direction then invert it to be a smaller angle in the opposite direction if (angle > Math.PI) { angle -= (float)(2 * Math.PI); } if (angle < -Math.PI) { angle += (float)(2 * Math.PI); } //Rotates the agent towards the target location if not facing it transform.Rotation += new Vector3(0, angle, 0); //Moves agent towards target location transform.Translation += transform.Right * velocity * sceneManager.dt; //Checks if entity is moving left if (direction.X < -0.3f) { //Checks if entity has reached the next node then sets current node to the next node causing the AI system to update to a new next node if ((transform.Translation.X) < (ai.NextNodeLocation.X + 0.1f)) { ai.CurrentNode = ai.NextNode; } } //Checks if entity is moving down else if (direction.Z < -0.3f) { //Checks if entity has reached the next node then sets current node to the next node causing the AI system to update to a new next node if ((transform.Translation.Z) < (ai.NextNodeLocation.Z + 0.1f)) { ai.CurrentNode = ai.NextNode; } } else { //Checks if entity has reached the next node then sets current node to the next node causing the AI system to update to a new next node if ((int)(transform.Translation.X + 0.1f) == ai.NextNodeLocation.X && (int)(transform.Translation.Z + 0.1f) == ai.NextNodeLocation.Z) { ai.CurrentNode = ai.NextNode; } } } #endregion //Updates transform of entity every frame UpdateTransform((cTransform)transformComponent); } }