void FindPath(Vector3 startPos, Vector3 targetPos) { Node_nn startNode = grid.NodeFromWorldPoint(startPos); Node_nn targetNode = grid.NodeFromWorldPoint(targetPos); if (startNode == targetNode) { return; } List <Node_nn> openSet = new List <Node_nn>(); HashSet <Node_nn> closedSet = new HashSet <Node_nn>(); openSet.Add(startNode); while (openSet.Count > 0) { Node_nn node = openSet[0]; for (int i = 1; i < openSet.Count; i++) { if (openSet[i].fCost < node.fCost || openSet[i].fCost == node.fCost) { if (openSet[i].hCost < node.hCost) { node = openSet[i]; } } } openSet.Remove(node); closedSet.Add(node); if (node == targetNode) { RetracePath(startNode, targetNode); return; } foreach (Node_nn neighbour in grid.GetNeighbours(node)) { if (!neighbour.walkable || closedSet.Contains(neighbour)) { continue; } int newCostToNeighbour = node.gCost + GetDistance(node, neighbour); if (newCostToNeighbour < neighbour.gCost || !openSet.Contains(neighbour)) { neighbour.gCost = newCostToNeighbour; neighbour.hCost = GetDistance(neighbour, targetNode); neighbour.parent = node; if (!openSet.Contains(neighbour)) { openSet.Add(neighbour); } } } } }
public List<Node_nn> GetNeighbours(Node_nn node) { List<Node_nn> neighbours = new List<Node_nn>(); // //logic for diagonals - 8 neighbours // for (int x = -1; x <= 1; x++) // { // for (int y = -1; y <= 1; y++) // { // if (x == 0 && y == 0) // continue; // int checkX = node.gridX + x; // int checkY = node.gridY + y; // if (checkX >= 0 && checkX < gridSizeX && checkY >= 0 && checkY < gridSizeY) // { // neighbours.Add(grid[checkX, checkY]); // } // } // } //logic for 4 instead of 8 expected neighbours Vector2Int multiplyDirection = new Vector2Int(); //left right up down, no diagonals for (int a = 0; a < 4; a++) { // too lazy to think of a smart loop, optimize later if you feel like burning some calories switch (a) { case 0: multiplyDirection = new Vector2Int(1,0); break; case 1: multiplyDirection = new Vector2Int(-1,0); break; case 2: multiplyDirection = new Vector2Int(0,1); break; case 3: multiplyDirection = new Vector2Int(0,-1); break; default: break; } int checkX = node.gridX + multiplyDirection.x; int checkY = node.gridY + multiplyDirection.y; if (checkX >= 0 && checkX < gridSizeX && checkY >= 0 && checkY < gridSizeY) { neighbours.Add(grid[checkX, checkY]); } } return neighbours; }
int GetDistance(Node_nn nodeA, Node_nn nodeB) { int dstX = Mathf.Abs(nodeA.gridX - nodeB.gridX); int dstY = Mathf.Abs(nodeA.gridY - nodeB.gridY); if (dstX > dstY) { return(14 * dstY + 10 * (dstX - dstY)); } return(14 * dstX + 10 * (dstY - dstX)); }
void RetracePath(Node_nn startNode, Node_nn endNode) { List <Node_nn> path = new List <Node_nn>(); Node_nn currentNode = endNode; while (currentNode != startNode) { path.Add(currentNode); currentNode = currentNode.parent; } // Vector3[] waypoints = SimplifyPath(path); Vector3[] waypoints = GetLastNodeToFollow(path); // easier and more accurate way Array.Reverse(waypoints); grid.path = path; grid.waypoints = waypoints; if (onlyonce) { for (int i = 0; i < waypoints.Length; i++) { // print("Point no"); // print(i); // print("="); // print(waypoints[i]); } onlyonce = false; } if (waypoints.Length > 0) { seekerObject.transform.position = Vector3.MoveTowards(seekerObject.transform.position, waypoints[0], speed * Time.deltaTime); float dir = seekerObject.transform.position.x - waypoints[0].x; if (dir < 0) { transform.localScale = new Vector3(-1, 1, 1); } else { transform.localScale = new Vector3(1, 1, 1); } } }
void CreateGrid() { grid = new Node_nn[gridSizeX, gridSizeY]; Vector3 worldBottomLeft = transform.position - Vector3.right * gridWorldSize.x / 2 - Vector3.up * gridWorldSize.y / 2; for (int x = 0; x < gridSizeX; x++) { for (int y = 0; y < gridSizeY; y++) { Vector3 worldPoint = worldBottomLeft + Vector3.right * (x * nodeDiameter + nodeRadius) + Vector3.up * (y * nodeDiameter + nodeRadius); // bool walkable = !(Physics2D.OverlapCircle(worldPoint, nodeRadius, unwalkableMask)); bool walkable = tilemap.GetTile(tilemap.WorldToCell(worldPoint)) == null ? true : false; // checking instead if the foreground tilemap has a tile grid[x, y] = new Node_nn(walkable, worldPoint, x, y, walkable?false:true); } } }
public void UpdateTiles() { TempNodeCache.Clear(); RemoveNodeCache.Clear(); for (float x = -lengthRadius; x < lengthRadius; x += 1) { for (float y = -heightRadius; y < heightRadius; y += 1) { getWorldTilesPos = gameObject.transform.position + new Vector3(x + 0.8f, y + 0.59f, 0); // offset values from testing and trying to get it right in the inspector // Debug.Log("getWorldTilesPos "+getWorldTilesPos); nodeCache = GridRef.NodeFromWorldPoint(getWorldTilesPos); TempNodeCache.Add(nodeCache); NodeCollisionCache.Add(nodeCache); nodeCache.walkable = false; } } // compare the tiles that are no longer present and cache them to be removed foreach (Node_nn node in NodeCollisionCache) { if (!TempNodeCache.Contains(node)) // if the moving platform is no longer over a node/tile { RemoveNodeCache.Add(node); if (!node.isStatic) // incase of static/unwalkable background, dont make it walkable { node.walkable = true; } } } // remove tiles that the platform is not over foreach (Node_nn node in RemoveNodeCache) { NodeCollisionCache.Remove(node); } }