1using System;
2using System.Collections.Generic;
3using System.Linq;
4using UnityEngine;
5
6
7public class PathNode
8{
9public Vector2Int GridPosition;
10public bool IsWalkable;
11public float G_Cost;
12public float H_Cost;
13public float F_Cost { get { return G_Cost + H_Cost; } }
14public PathNode ParentNode;
15
16public PathNode(Vector2Int gridPosition, bool isWalkable = true)
17{
18GridPosition = gridPosition;
19IsWalkable = isWalkable;
20G_Cost = float.MaxValue;
21H_Cost = 0;
22ParentNode = null;
23}
24
25public override bool Equals(object obj)
26{
27if (obj is PathNode other)
28{
29return GridPosition == other.GridPosition;
30}
31return false;
32}
33
34public override int GetHashCode()
35{
36return GridPosition.GetHashCode();
37}
38}
39
40
41public class PathfindingGrid
42{
43private PathNode[,] grid;
44private int width;
45private int height;
46
47public PathfindingGrid(int width, int height, bool[,] obstacles)
48{
49this.width = width;
50this.height = height;
51grid = new PathNode[width, height];
52
53for (int x = 0; x < width; x++)
54{
55for (int y = 0; y < height; y++)
56{
57grid[x, y] = new PathNode(new Vector2Int(x, y), !obstacles[x, y]);
58}
59}
60}
61
62public PathNode GetNode(Vector2Int position)
63{
64if (position.x >= 0 && position.x < width && position.y >= 0 && position.y < height)
65{
66return grid[position.x, position.y];
67}
68return null;
69}
70
71public IEnumerable<PathNode> GetNeighbours(PathNode node)
72{
73Vector2Int[] directions = { new Vector2Int(0, 1), new Vector2Int(0, -1), new Vector2Int(1, 0), new Vector2Int(-1, 0),
74new Vector2Int(1, 1), new Vector2Int(1, -1), new Vector2Int(-1, 1), new Vector2Int(-1, -1) };
75
76foreach (var dir in directions)
77{
78Vector2Int neighbourPos = node.GridPosition + dir;
79PathNode neighbour = GetNode(neighbourPos);
80if (neighbour != null && neighbour.IsWalkable)
81{
82yield return neighbour;
83}
84}
85}
86
87public int Width { get { return width; } }
88public int Height { get { return height; } }
89}
90
91
92public class AStarPathfinder
93{
94private PathfindingGrid grid;
95
96public AStarPathfinder(PathfindingGrid grid)
97{
98this.grid = grid;
99}
100
101
102private float CalculateHeuristic(Vector2Int from, Vector2Int to)
103{
104
105
106
107
108
109float dx = Mathf.Abs(from.x - to.x);
110float dy = Mathf.Abs(from.y - to.y);
111return dx + dy;
112}
113
114public List<Vector2Int> FindPath(Vector2Int startPos, Vector2Int endPos)
115{
116PathNode startNode = grid.GetNode(startPos);
117PathNode endNode = grid.GetNode(endPos);
118
119if (startNode == null || endNode == null || !startNode.IsWalkable || !endNode.IsWalkable)
120{
121Debug.LogError("Start or end node is invalid or not walkable.");
122return new List<Vector2Int>();
123}
124
125
126
127List<PathNode> openSet = new List<PathNode>();
128
129
130HashSet<PathNode> closedSet = new HashSet<PathNode>();
131
132
133startNode.G_Cost = 0;
134startNode.H_Cost = CalculateHeuristic(startPos, endPos);
135openSet.Add(startNode);
136
137while (openSet.Count > 0)
138{
139
140openSet.Sort((a, b) => a.F_Cost.CompareTo(b.F_Cost));
141PathNode currentNode = openSet[0];
142
143
144if (currentNode == endNode)
145{
146return ReconstructPath(currentNode);
147}
148
149
150openSet.RemoveAt(0);
151closedSet.Add(currentNode);
152
153
154foreach (PathNode neighbour in grid.GetNeighbours(currentNode))
155{
156
157if (closedSet.Contains(neighbour) || !neighbour.IsWalkable)
158{
159continue;
160}
161
162
163
164float tentativeGCost = currentNode.G_Cost + Vector2Int.Distance(currentNode.GridPosition, neighbour.GridPosition);
165
166
167if (tentativeGCost < neighbour.G_Cost)
168{
169neighbour.ParentNode = currentNode;
170neighbour.G_Cost = tentativeGCost;
171neighbour.H_Cost = CalculateHeuristic(neighbour.GridPosition, endPos);
172
173
174if (!openSet.Contains(neighbour))
175{
176openSet.Add(neighbour);
177}
178
179}
180}
181}
182
183
184Debug.LogWarning("Path not found.");
185return new List<Vector2Int>();
186}
187
188
189private List<Vector2Int> ReconstructPath(PathNode endNode)
190{
191List<Vector2Int> path = new List<Vector2Int>();
192PathNode currentNode = endNode;
193
194while (currentNode != null)
195{
196path.Add(currentNode.GridPosition);
197currentNode = currentNode.ParentNode;
198}
199
200path.Reverse();
201return path;
202}
203
204
205public static void Main(string[] args)
206{
207
208int gridWidth = 10;
209int gridHeight = 10;
210bool[,] obstacles = new bool[gridWidth, gridHeight];
211
212
213for (int i = 0; i < gridWidth; i++) obstacles[i, 5] = true;
214for (int i = 0; i < gridHeight; i++) obstacles[5, i] = true;
215obstacles[3, 3] = true;
216obstacles[4, 3] = true;
217obstacles[5, 3] = true;
218obstacles[6, 3] = true;
219
220PathfindingGrid pathGrid = new PathfindingGrid(gridWidth, gridHeight, obstacles);
221AStarPathfinder pathfinder = new AStarPathfinder(pathGrid);
222
223Vector2Int start = new Vector2Int(0, 0);
224Vector2Int end = new Vector2Int(9, 9);
225
226List<Vector2Int> path = pathfinder.FindPath(start, end);
227
228if (path.Count > 0)
229{
230Console.WriteLine("Path found:");
231foreach (var pos in path)
232{
233Console.Write($"({pos.x},{pos.y}) -> ");
234}
235Console.WriteLine("End");
236}
237else
238{
239Console.WriteLine("Could not find a path.");
240}
241
242
243Vector2Int unreachableEnd = new Vector2Int(5, 5);
244List<Vector2Int> unreachablePath = pathfinder.FindPath(start, unreachableEnd);
245if (unreachablePath.Count == 0)
246{
247Console.WriteLine("Correctly identified unreachable destination.");
248}
249}
250}