Pathfinding.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. public class Pathfinding {
  6. private const int MOVE_STRAIGHT_COST = 10;
  7. private const int MOVE_DIAGONAL_COST = 14;
  8. public static Pathfinding instance { get; private set; }
  9. private GridXZ<PathNode> grid;
  10. private List<PathNode> openList;
  11. private List<PathNode> closedList;
  12. public Pathfinding(int widht, int height) {
  13. instance = this;
  14. grid = new GridXZ<PathNode>(widht, height, 10f, Vector3.zero, (GridXZ<PathNode> g, int x, int y) => new PathNode(g, x, y));
  15. }
  16. public GridXZ<PathNode> GetGrid() {
  17. return grid;
  18. }
  19. public List<Vector3> FindPath(Vector3 startWorldPosition, Vector3 enWorldPosition) {
  20. grid.GetXZ(startWorldPosition, out int startX, out int startZ);
  21. grid.GetXZ(enWorldPosition, out int endX, out int endZ);
  22. List<PathNode> path = FindPath(startX, startZ, endX, endZ);
  23. if (path == null) {
  24. return null;
  25. } else {
  26. List<Vector3> vectorPath = new List<Vector3>();
  27. foreach (PathNode pathNode in path) {
  28. vectorPath.Add(new Vector3(pathNode.x, pathNode.z) * grid.GetCellSize() + Vector3.one * grid.GetCellSize() * .5f);
  29. }
  30. return vectorPath;
  31. }
  32. }
  33. public List<PathNode> FindPath(int startX, int startZ, int endX, int endZ) {
  34. PathNode startNode = grid.GetGridObject(startX, startZ);
  35. PathNode endNode = grid.GetGridObject(endX, endZ);
  36. if (endNode == null || startNode == null) {
  37. return null;
  38. }
  39. openList = new List<PathNode> { startNode };
  40. closedList = new List<PathNode>();
  41. for (int x = 0; x < grid.GetWidth(); x++) {
  42. for (int z = 0; z < grid.GetHeight(); z++) {
  43. PathNode pathNode = grid.GetGridObject(x, z);
  44. pathNode.gCost = int.MaxValue;
  45. pathNode.CalculateFCost();
  46. pathNode.cameFromNode = null;
  47. }
  48. }
  49. startNode.gCost = 0;
  50. Debug.Log("endX: " + endX + " endY: " + endZ);
  51. startNode.hCost = CalculateDistanceCost(startNode, endNode);
  52. startNode.CalculateFCost();
  53. while (openList.Count > 0) {
  54. PathNode currentNode = GetLowestFCostNode(openList);
  55. if (currentNode == endNode) {
  56. // Reached final node
  57. // PathfindingDebugStepVisual.Instance.TakeSnapshot(grid, currentNode, openList, closedList);
  58. // PathfindingDebugStepVisual.Instance.TakeSnapshotFinalPath(grid, CalculatePath(endNode));
  59. return CalculatePath(endNode);
  60. }
  61. openList.Remove(currentNode);
  62. closedList.Add(currentNode);
  63. foreach (PathNode neighbourNode in GetNeighbourList(currentNode)) {
  64. if (closedList.Contains(neighbourNode)) continue;
  65. if (!neighbourNode.isWalkable) {
  66. closedList.Add(neighbourNode);
  67. continue;
  68. }
  69. int tentativeGCost = currentNode.gCost + CalculateDistanceCost(currentNode, neighbourNode);
  70. if (tentativeGCost < neighbourNode.gCost) {
  71. neighbourNode.cameFromNode = currentNode;
  72. neighbourNode.gCost = tentativeGCost;
  73. neighbourNode.hCost = CalculateDistanceCost(neighbourNode, endNode);
  74. neighbourNode.CalculateFCost();
  75. if (!openList.Contains(neighbourNode)) {
  76. openList.Add(neighbourNode);
  77. }
  78. }
  79. // PathfindingDebugStepVisual.Instance.TakeSnapshot(grid, currentNode, openList, closedList);
  80. }
  81. }
  82. // Out of nodes on the open list
  83. return null;
  84. }
  85. public PathNode GetNode(int x, int z) {
  86. return grid.GetGridObject(x, z);
  87. }
  88. private List<PathNode> GetNeighbourList(PathNode currentNode) {
  89. List<PathNode> neighbourList = new List<PathNode>();
  90. if (currentNode.x - 1 >= 0) {
  91. // Left
  92. neighbourList.Add(GetNode(currentNode.x - 1, currentNode.z));
  93. // Left Down
  94. if (currentNode.z - 1 >= 0) neighbourList.Add(GetNode(currentNode.x - 1, currentNode.z - 1));
  95. // Left Up
  96. if (currentNode.z + 1 < grid.GetHeight()) neighbourList.Add(GetNode(currentNode.x - 1, currentNode.z + 1));
  97. }
  98. if (currentNode.x + 1 < grid.GetWidth()) {
  99. // Right
  100. neighbourList.Add(GetNode(currentNode.x + 1, currentNode.z));
  101. // Right Down
  102. if (currentNode.z - 1 >= 0) neighbourList.Add(GetNode(currentNode.x + 1, currentNode.z - 1));
  103. // Right Up
  104. if (currentNode.z + 1 < grid.GetHeight()) neighbourList.Add(GetNode(currentNode.x + 1, currentNode.z + 1));
  105. }
  106. // Down
  107. if (currentNode.z - 1 >= 0) neighbourList.Add(GetNode(currentNode.x, currentNode.z - 1));
  108. // Up
  109. if (currentNode.z + 1 < grid.GetHeight()) neighbourList.Add(GetNode(currentNode.x, currentNode.z + 1));
  110. return neighbourList;
  111. }
  112. private List<PathNode> CalculatePath(PathNode endNode) {
  113. List<PathNode> path = new List<PathNode>();
  114. path.Add(endNode);
  115. PathNode currentNode = endNode;
  116. while (currentNode.cameFromNode != null) {
  117. path.Add(currentNode.cameFromNode);
  118. currentNode = currentNode.cameFromNode;
  119. }
  120. path.Reverse();
  121. return path;
  122. }
  123. private int CalculateDistanceCost(PathNode a, PathNode b) {
  124. int xDistance = Mathf.Abs(a.x - b.x);
  125. int yDistance = Mathf.Abs(a.z - b.z);
  126. int remaining = Mathf.Abs(xDistance - yDistance);
  127. return MOVE_DIAGONAL_COST * Mathf.Min(xDistance, yDistance) + MOVE_STRAIGHT_COST * remaining;
  128. }
  129. private PathNode GetLowestFCostNode(List<PathNode> pathNodeList) {
  130. PathNode lowestFCostNode = pathNodeList[0];
  131. for (int i = 1; i < pathNodeList.Count; i++) {
  132. if (pathNodeList[i].fCost < lowestFCostNode.fCost) {
  133. lowestFCostNode = pathNodeList[i];
  134. }
  135. }
  136. return lowestFCostNode;
  137. }
  138. }