Advertisement
SebastianLague

A* Pathfinding Tutorial 03

Dec 19th, 2014
9,039
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 4.78 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4.  
  5. public class Pathfinding : MonoBehaviour {
  6.  
  7.     public Transform seeker, target;
  8.    
  9.     Grid grid;
  10.  
  11.     void Awake() {
  12.         grid = GetComponent<Grid>();
  13.     }
  14.  
  15.     void Update() {
  16.         FindPath(seeker.position,target.position);
  17.     }
  18.  
  19.     void FindPath(Vector3 startPos, Vector3 targetPos) {
  20.         Node startNode = grid.NodeFromWorldPoint(startPos);
  21.         Node targetNode = grid.NodeFromWorldPoint(targetPos);
  22.  
  23.         List<Node> openSet = new List<Node>();
  24.         HashSet<Node> closedSet = new HashSet<Node>();
  25.         openSet.Add(startNode);
  26.  
  27.         while (openSet.Count > 0) {
  28.             Node currentNode = openSet[0];
  29.             for (int i = 1; i < openSet.Count; i ++) {
  30.                 if (openSet[i].fCost < currentNode.fCost || openSet[i].fCost == currentNode.fCost && openSet[i].hCost < currentNode.hCost) {
  31.                     currentNode = openSet[i];
  32.                 }
  33.             }
  34.  
  35.             openSet.Remove(currentNode);
  36.             closedSet.Add(currentNode);
  37.  
  38.             if (currentNode == targetNode) {
  39.                 RetracePath(startNode,targetNode);
  40.                 return;
  41.             }
  42.  
  43.             foreach (Node neighbour in grid.GetNeighbours(currentNode)) {
  44.                 if (!neighbour.walkable || closedSet.Contains(neighbour)) {
  45.                     continue;
  46.                 }
  47.  
  48.                 int newMovementCostToNeighbour = currentNode.gCost + GetDistance(currentNode, neighbour);
  49.                 if (newMovementCostToNeighbour < neighbour.gCost || !openSet.Contains(neighbour)) {
  50.                     neighbour.gCost = newMovementCostToNeighbour;
  51.                     neighbour.hCost = GetDistance(neighbour, targetNode);
  52.                     neighbour.parent = currentNode;
  53.  
  54.                     if (!openSet.Contains(neighbour))
  55.                         openSet.Add(neighbour);
  56.                 }
  57.             }
  58.         }
  59.     }
  60.  
  61.     void RetracePath(Node startNode, Node endNode) {
  62.         List<Node> path = new List<Node>();
  63.         Node currentNode = endNode;
  64.  
  65.         while (currentNode != startNode) {
  66.             path.Add(currentNode);
  67.             currentNode = currentNode.parent;
  68.         }
  69.         path.Reverse();
  70.  
  71.         grid.path = path;
  72.  
  73.     }
  74.  
  75.     int GetDistance(Node nodeA, Node nodeB) {
  76.         int dstX = Mathf.Abs(nodeA.gridX - nodeB.gridX);
  77.         int dstY = Mathf.Abs(nodeA.gridY - nodeB.gridY);
  78.  
  79.         if (dstX > dstY)
  80.             return 14*dstY + 10* (dstX-dstY);
  81.         return 14*dstX + 10 * (dstY-dstX);
  82.     }
  83. }
  84.  
  85. public class Grid : MonoBehaviour {
  86.  
  87.     public LayerMask unwalkableMask;
  88.     public Vector2 gridWorldSize;
  89.     public float nodeRadius;
  90.     Node[,] grid;
  91.  
  92.     float nodeDiameter;
  93.     int gridSizeX, gridSizeY;
  94.  
  95.     void Start() {
  96.         nodeDiameter = nodeRadius*2;
  97.         gridSizeX = Mathf.RoundToInt(gridWorldSize.x/nodeDiameter);
  98.         gridSizeY = Mathf.RoundToInt(gridWorldSize.y/nodeDiameter);
  99.         CreateGrid();
  100.     }
  101.  
  102.     void CreateGrid() {
  103.         grid = new Node[gridSizeX,gridSizeY];
  104.         Vector3 worldBottomLeft = transform.position - Vector3.right * gridWorldSize.x/2 - Vector3.forward * gridWorldSize.y/2;
  105.  
  106.         for (int x = 0; x < gridSizeX; x ++) {
  107.             for (int y = 0; y < gridSizeY; y ++) {
  108.                 Vector3 worldPoint = worldBottomLeft + Vector3.right * (x * nodeDiameter + nodeRadius) + Vector3.forward * (y * nodeDiameter + nodeRadius);
  109.                 bool walkable = !(Physics.CheckSphere(worldPoint,nodeRadius,unwalkableMask));
  110.                 grid[x,y] = new Node(walkable,worldPoint, x,y);
  111.             }
  112.         }
  113.     }
  114.  
  115.     public List<Node> GetNeighbours(Node node) {
  116.         List<Node> neighbours = new List<Node>();
  117.  
  118.         for (int x = -1; x <= 1; x++) {
  119.             for (int y = -1; y <= 1; y++) {
  120.                 if (x == 0 && y == 0)
  121.                     continue;
  122.  
  123.                 int checkX = node.gridX + x;
  124.                 int checkY = node.gridY + y;
  125.  
  126.                 if (checkX >= 0 && checkX < gridSizeX && checkY >= 0 && checkY < gridSizeY) {
  127.                     neighbours.Add(grid[checkX,checkY]);
  128.                 }
  129.             }
  130.         }
  131.  
  132.         return neighbours;
  133.     }
  134.    
  135.  
  136.     public Node NodeFromWorldPoint(Vector3 worldPosition) {
  137.         float percentX = (worldPosition.x + gridWorldSize.x/2) / gridWorldSize.x;
  138.         float percentY = (worldPosition.z + gridWorldSize.y/2) / gridWorldSize.y;
  139.         percentX = Mathf.Clamp01(percentX);
  140.         percentY = Mathf.Clamp01(percentY);
  141.  
  142.         int x = Mathf.RoundToInt((gridSizeX-1) * percentX);
  143.         int y = Mathf.RoundToInt((gridSizeY-1) * percentY);
  144.         return grid[x,y];
  145.     }
  146.  
  147.     public List<Node> path;
  148.     void OnDrawGizmos() {
  149.         Gizmos.DrawWireCube(transform.position,new Vector3(gridWorldSize.x,1,gridWorldSize.y));
  150.  
  151.         if (grid != null) {
  152.             foreach (Node n in grid) {
  153.                 Gizmos.color = (n.walkable)?Color.white:Color.red;
  154.                 if (path != null)
  155.                     if (path.Contains(n))
  156.                         Gizmos.color = Color.black;
  157.                 Gizmos.DrawCube(n.worldPosition, Vector3.one * (nodeDiameter-.1f));
  158.             }
  159.         }
  160.     }
  161. }
  162.  
  163. public class Node {
  164.    
  165.     public bool walkable;
  166.     public Vector3 worldPosition;
  167.     public int gridX;
  168.     public int gridY;
  169.  
  170.     public int gCost;
  171.     public int hCost;
  172.     public Node parent;
  173.    
  174.     public Node(bool _walkable, Vector3 _worldPos, int _gridX, int _gridY) {
  175.         walkable = _walkable;
  176.         worldPosition = _worldPos;
  177.         gridX = _gridX;
  178.         gridY = _gridY;
  179.     }
  180.  
  181.     public int fCost {
  182.         get {
  183.             return gCost + hCost;
  184.         }
  185.     }
  186. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement