public Vector2 position; // Position of the current node #endregion Fields #region Constructors // Default Constructor public EnemyNutrientNode() { this.fEstimatedCost = 0.0f; this.fTotalCost = 1.0f; this.bAccessible = false; this.parent = null; }
public Vector2 position; // Position of the current node #endregion // Default Constructor public EnemyNutrientNode() { this.fEstimatedCost = 0.0f; this.fTotalCost = 1.0f; this.bAccessible = false; this.parent = null; }
// Constructor public EnemyNutrientNode(Vector2 pos) { this.fEstimatedCost = 0.0f; this.fTotalCost = 1.0f; this.bAccessible = true; this.parent = null; this.position = pos; }
// Get the obstacles in the scene public void GetObstacles() { // Initialise the nodes nodes = new EnemyNutrientNode[nNumOfRows, nNumOfColumns]; int index = 0; for (int i = 0; i < nNumOfRows; i++) { for (int j = 0; j < nNumOfColumns; j++) { Vector2 cellPos = GetNodeCenter(index); EnemyNutrientNode node = new EnemyNutrientNode(cellPos); nodes[i, j] = node; index++; } } // Set the position for each obstacle if (obstacleList != null && obstacleList.Count > 0) { foreach (GameObject obstacle in obstacleList) { if (obstacle != null) { if (IsInBounds(obstacle.transform.position)) { int indexCell = GetGridIndex(obstacle.transform.position); int column = GetColumn(indexCell); int row = GetRow(indexCell); int range = (int)(obstacle.GetComponent <CircleCollider2D> ().bounds.size.x / fUniversalnodeSize); // Assign unaccessible area nodes[row, column].MarkAsUnaccessible(); /* * for (int i = row - range; i < row + range; i++) * { * for (int j = column - range; j < column + range; j++) * { * if (i >= 0 && i < nNumOfRows && j >= 0 && j < nNumOfColumns) * { * if (nodes[i, j].bAccessible) * nodes[i, j].MarkAsUnaccessible(); * } * } * } */ } } } } }
// Check the neighbouring node. If it is accessible, add the neighbouring node to the neighbour list. void AssignNeighbour(int row, int column, ArrayList neighbors) { if (row >= 0 && column >= 0 && row < nNumOfRows && column < nNumOfColumns) { EnemyNutrientNode nodeToAdd = nodes[row, column]; if (nodeToAdd.bAccessible) { neighbors.Add(nodeToAdd); } } }
// Get the real path by reversing the path found private static ArrayList CalculatePath(EnemyNutrientNode node) { ArrayList list = new ArrayList(); while (node != null) { list.Add(node); node = node.parent; } list.Reverse(); return(list); }
void FindPath() { startPos = startObject.transform; endPos = goalObject.transform; // Initialize start and goal node startNode = new EnemyNutrientNode(MapManager.Instance.GetNodeCenter(MapManager.Instance.GetGridIndex((Vector2)startPos.position))); goalNode = new EnemyNutrientNode(MapManager.Instance.GetNodeCenter(MapManager.Instance.GetGridIndex((Vector2)endPos.position))); // Update the size and position of all obstacles in map MapManager.Instance.GetObstacles (); // Find a new path between the start and goal node pathArray = EnemyNutrientAStar.FindPath(startNode, goalNode); }
void FindPath() { startPos = startObject.transform; endPos = goalObject.transform; // Initialize start and goal node startNode = new EnemyNutrientNode(MapManager.Instance.GetNodeCenter(MapManager.Instance.GetGridIndex((Vector2)startPos.position))); goalNode = new EnemyNutrientNode(MapManager.Instance.GetNodeCenter(MapManager.Instance.GetGridIndex((Vector2)endPos.position))); // Update the size and position of all obstacles in map MapManager.Instance.GetObstacles(); // Find a new path between the start and goal node pathArray = EnemyNutrientAStar.FindPath(startNode, goalNode); }
// Get the neighouring nodes in 4 cardinal directions public void GetNeighbours(EnemyNutrientNode node, ArrayList neighbours) { Vector2 neighbourPos = node.position; int neighborIndex = GetGridIndex(neighbourPos); int row = GetRow(neighborIndex); int column = GetColumn(neighborIndex); // Top int leftNodeRow = row + 1; int leftNodeColumn = column; AssignNeighbour(leftNodeRow, leftNodeColumn, neighbours); // Bottom leftNodeRow = row - 1; leftNodeColumn = column; AssignNeighbour(leftNodeRow, leftNodeColumn, neighbours); // Left leftNodeRow = row; leftNodeColumn = column - 1; AssignNeighbour(leftNodeRow, leftNodeColumn, neighbours); // Right leftNodeRow = row; leftNodeColumn = column + 1; AssignNeighbour(leftNodeRow, leftNodeColumn, neighbours); // Top left leftNodeRow = row + 1; leftNodeColumn = column - 1; AssignNeighbour(leftNodeRow, leftNodeColumn, neighbours); // Top right leftNodeRow = row + 1; leftNodeColumn = column + 1; AssignNeighbour(leftNodeRow, leftNodeColumn, neighbours); // Bottom left leftNodeRow = row - 1; leftNodeColumn = column - 1; AssignNeighbour(leftNodeRow, leftNodeColumn, neighbours); // Bottom right leftNodeRow = row - 1; leftNodeColumn = column + 1; AssignNeighbour(leftNodeRow, leftNodeColumn, neighbours); }
// Override the class CompareTo function for sorting // Applied when calling Sort.Sort from ArrayList // Compare using the estimated total cost between two nodes public int CompareTo(object obj) { EnemyNutrientNode node = (EnemyNutrientNode)obj; if (this.fEstimatedCost < node.fEstimatedCost) { return(-1); } if (this.fEstimatedCost > node.fEstimatedCost) { return(1); } return(0); }
void Start() { // GetComponent on the gameObject thisRB = GetComponent <Rigidbody2D> (); pathfindingManager = GetComponent <EMNutrientPathfindingManager> (); // Initialization currentNode = null; nextNode = null; fSpeed = Random.Range(.4f, .8f); bIsAbsorbed = false; fAbsorbSpeed = Random.Range(1f, 2f); fAbsorbTime = 1f; // Not using A* by default bCanFindPath = false; // Call the PauseAStar function for initial movement StartCoroutine(PauseAStar()); }
// Draw the path found void OnDrawGizmos() { if (pathArray == null) { return; } if (pathArray.Count > 0) { int index = 1; foreach (EnemyNutrientNode node in pathArray) { if (index < pathArray.Count) { EnemyNutrientNode nextNode = (EnemyNutrientNode)pathArray[index]; Debug.DrawLine(node.position, nextNode.position, Color.green); index++; } } ; } }
void Update() { // Destroy the nutrient if enemy main cell is invisible if (!EMHelper.Instance().IsEnemyVisible) { Destroy(this.gameObject); } // Absorb behaviour if (bIsAbsorbed) { Absorb(); } else { // A* pathfinding if (bCanFindPath) { // Set the target to the next node if (pathfindingManager.pathArray != null) { if (pathfindingManager.pathArray.Count > 1) { nextNode = (EnemyNutrientNode)pathfindingManager.pathArray [1]; currentNode = nextNode; } } else { nextNode = null; } // Move to the target node if (currentNode != null) { thisRB.velocity = (currentNode.position - (Vector2)this.gameObject.transform.position) * fSpeed; } } } }
// Add the node to the frontier and sort all nodes based on the estimated total cost public void Push(EnemyNutrientNode node) { this.nodes.Add(node); this.nodes.Sort(); }
// Remove the node from the frontier and sort the rest based on the estimated total cost public void Remove(EnemyNutrientNode node) { this.nodes.Remove(node); this.nodes.Sort(); }
// Find the path between start node and goal node using AStar Algorithm public static ArrayList FindPath(EnemyNutrientNode start, EnemyNutrientNode goal) { // Start Finding the path frontier = new Frontier_ExploredSet (); // Initialize the frontier exploredSet = new Frontier_ExploredSet (); // Initialize the explored set frontier.Push(start); // Add the start node to the frontier start.fTotalCost = 0.0f; // Initialize the total cost for the start node start.fEstimatedCost = HeuristicEstimateCost(start, goal); // Calculate the heuristic EnemyNutrientNode node = null; // Initialize a node to use // While the frontier isnot empty while (frontier.Length != 0) { node = frontier.First(); // Take the first node in the frontier // If the node is the goal node, then the path is found // Instead of checking after adding the node to the explored set, we check it when it's first generated // The purpose is to save time from looking for a more optimal path if (node.position == goal.position) { return CalculatePath(node); } ArrayList neighbours = new ArrayList(); MapManager.Instance.GetNeighbours(node, neighbours); #region CheckNeighbours // Get the Neighbours for (int i = 0; i < neighbours.Count; i++) { // Cost between neighbour nodes EnemyNutrientNode neighbourNode = (EnemyNutrientNode)neighbours[i]; if (!exploredSet.Contains(neighbourNode)) { // Cost from current node to this neighbour node float cost = HeuristicEstimateCost(node, neighbourNode); // Total Cost So Far from start to this neighbour node float totalCost = node.fTotalCost + cost; // Estimated cost for neighbour node to the goal float neighbourNodeEstCost = HeuristicEstimateCost(neighbourNode, goal); // Assign neighbour node properties neighbourNode.fTotalCost = totalCost; neighbourNode.parent = node; neighbourNode.fEstimatedCost = totalCost + neighbourNodeEstCost; // Add the neighbour node to the frontier if not already existed in the frontier if (!frontier.Contains(neighbourNode)) { frontier.Push(neighbourNode); } } } #endregion exploredSet.Push(node); // Add the node to the explored set as it is expanded frontier.Remove(node); // Remove the node from the frontier } // If finished looping and cannot find the goal then return null if (node.position != goal.position) { //Debug.LogError("Goal Not Found"); //Debug.Log ("Last node position:" + node.position); //Debug.Log ("Goal node position:" + goal.position); return null; } // Calculate the path based on the final node return CalculatePath(node); }
void Update() { // Destroy the nutrient if enemy main cell is invisible if (!EMHelper.Instance().IsEnemyVisible) Destroy (this.gameObject); // Absorb behaviour if (bIsAbsorbed) Absorb (); else { // A* pathfinding if (bCanFindPath) { // Set the target to the next node if (pathfindingManager.pathArray != null) { if (pathfindingManager.pathArray.Count > 1) { nextNode = (EnemyNutrientNode)pathfindingManager.pathArray [1]; currentNode = nextNode; } } else nextNode = null; // Move to the target node if (currentNode != null) thisRB.velocity = (currentNode.position - (Vector2)this.gameObject.transform.position) * fSpeed; } } }
void Start() { // GetComponent on the gameObject thisRB = GetComponent<Rigidbody2D> (); pathfindingManager = GetComponent<EMNutrientPathfindingManager> (); // Initialization currentNode = null; nextNode = null; fSpeed = Random.Range (.4f, .8f); bIsAbsorbed = false; fAbsorbSpeed = Random.Range (1f, 2f); fAbsorbTime = 1f; // Not using A* by default bCanFindPath = false; // Call the PauseAStar function for initial movement StartCoroutine (PauseAStar ()); }
// Get the obstacles in the scene public void GetObstacles() { // Initialise the nodes nodes = new EnemyNutrientNode[nNumOfRows, nNumOfColumns]; int index = 0; for (int i = 0; i < nNumOfRows; i++) { for (int j = 0; j < nNumOfColumns; j++) { Vector2 cellPos = GetNodeCenter(index); EnemyNutrientNode node = new EnemyNutrientNode(cellPos); nodes[i, j] = node; index++; } } // Set the position for each obstacle if (obstacleList != null && obstacleList.Count > 0) { foreach (GameObject obstacle in obstacleList) { if (obstacle != null) { if (IsInBounds (obstacle.transform.position)) { int indexCell = GetGridIndex(obstacle.transform.position); int column = GetColumn(indexCell); int row = GetRow(indexCell); int range = (int)(obstacle.GetComponent<CircleCollider2D> ().bounds.size.x / fUniversalnodeSize); // Assign unaccessible area nodes[row, column].MarkAsUnaccessible(); /* for (int i = row - range; i < row + range; i++) { for (int j = column - range; j < column + range; j++) { if (i >= 0 && i < nNumOfRows && j >= 0 && j < nNumOfColumns) { if (nodes[i, j].bAccessible) nodes[i, j].MarkAsUnaccessible(); } } } */ } } } } }
// Get the real path by reversing the path found private static ArrayList CalculatePath(EnemyNutrientNode node) { ArrayList list = new ArrayList(); while (node != null) { list.Add(node); node = node.parent; } list.Reverse(); return list; }
// Calculate the estimated Heuristic cost to the goal node private static float HeuristicEstimateCost(EnemyNutrientNode currentNode, EnemyNutrientNode goalNode) { Vector2 vecCost = currentNode.position - goalNode.position; return(vecCost.magnitude); }
// Find the path between start node and goal node using AStar Algorithm public static ArrayList FindPath(EnemyNutrientNode start, EnemyNutrientNode goal) { // Start Finding the path frontier = new Frontier_ExploredSet(); // Initialize the frontier exploredSet = new Frontier_ExploredSet(); // Initialize the explored set frontier.Push(start); // Add the start node to the frontier start.fTotalCost = 0.0f; // Initialize the total cost for the start node start.fEstimatedCost = HeuristicEstimateCost(start, goal); // Calculate the heuristic EnemyNutrientNode node = null; // Initialize a node to use // While the frontier isnot empty while (frontier.Length != 0) { node = frontier.First(); // Take the first node in the frontier // If the node is the goal node, then the path is found // Instead of checking after adding the node to the explored set, we check it when it's first generated // The purpose is to save time from looking for a more optimal path if (node.position == goal.position) { return(CalculatePath(node)); } ArrayList neighbours = new ArrayList(); MapManager.Instance.GetNeighbours(node, neighbours); #region CheckNeighbours // Get the Neighbours for (int i = 0; i < neighbours.Count; i++) { // Cost between neighbour nodes EnemyNutrientNode neighbourNode = (EnemyNutrientNode)neighbours[i]; if (!exploredSet.Contains(neighbourNode)) { // Cost from current node to this neighbour node float cost = HeuristicEstimateCost(node, neighbourNode); // Total Cost So Far from start to this neighbour node float totalCost = node.fTotalCost + cost; // Estimated cost for neighbour node to the goal float neighbourNodeEstCost = HeuristicEstimateCost(neighbourNode, goal); // Assign neighbour node properties neighbourNode.fTotalCost = totalCost; neighbourNode.parent = node; neighbourNode.fEstimatedCost = totalCost + neighbourNodeEstCost; // Add the neighbour node to the frontier if not already existed in the frontier if (!frontier.Contains(neighbourNode)) { frontier.Push(neighbourNode); } } } #endregion exploredSet.Push(node); // Add the node to the explored set as it is expanded frontier.Remove(node); // Remove the node from the frontier } // If finished looping and cannot find the goal then return null if (node.position != goal.position) { //Debug.LogError("Goal Not Found"); //Debug.Log ("Last node position:" + node.position); //Debug.Log ("Goal node position:" + goal.position); return(null); } // Calculate the path based on the final node return(CalculatePath(node)); }
// Calculate the estimated Heuristic cost to the goal node private static float HeuristicEstimateCost(EnemyNutrientNode currentNode, EnemyNutrientNode goalNode) { Vector2 vecCost = currentNode.position - goalNode.position; return vecCost.magnitude; }