Trouble with A* Pathfinding

The example file place from which I had copied the code from works perfectly fine. However, this error is thrown when I try to run the game.
After doing some debugging, I had noticed the code I had copied from which worked perfectly fine in it’s own place but lags a lot when copied and pasted into my own place.
image

Line 131 in question:
image

The example file:
A Pathfinding.rbxl (25.8 KB)

My place:
Pathfinding Algorithms.rbxl (28.6 KB)

Add a wait() to the while loop.

2 Likes

If you took a look at the files I posted, the code I had referred to didn’t have a wait function in this while loop.

You are expecting too much out of scripting support lol.

Anyways, make sure the goal is reached to ensure the path has a solution in the first place before tracing back the path.

And ensuring the while condition follows the general psuedo code:

While currentPath ~= start do
--find path

One time I printed it out and it just went back and forth between start and goal because I messed up the while condition, I suggest putting a wait() and printing it out to make sure the logic follows.

I highly recommend this resource, the best visual A star tutorial on the web:

And looking at the path construction psuedo code:

The code to reconstruct paths is simple: follow the arrows backwards from the goal to the start. A path is a sequence of edges, but often it’s easier to store the nodes:

current = goal 
path = []
while current != start: 
   path.append(current)
   current = came_from[current]
path.append(start) # optional
path.reverse() # optional

I believe you are missing this line specifically

   current = came_from[current]

which is causing the recursion error.

2 Likes

Shameless self bump
Studio freezes whenever I try to print out the previous node, adding wait() to the while loop does little to help this either.
Strangely enough, when I published the file I had copied the code from, that place begins to experience a lot of lag as well.

Wouldn’t this just be Temp = Temp.previous in my case?

Not really because your loop isn’t check Temp, it’s checking Temp.previous which is unchanged.

It should be

Temp.previous = cameFrom[Temp.previous]

But you didn’t show your full code :facepunch: so I don’t know what variable is your cameFrom dictionary.

Don’t screen shot

Then I have no clue what cameFrom is supposed to be.
And I seriously don’t understand why you can’t just download the place file.

--local OpenList = workspace:WaitForChild("Path"):GetChildren()
local OpenList = {}
local CloseList = {}
local Grid = {}

-- Rows and columns in a grid
local Rows = 100
local Columns = 100

local Start_Node
local End_Node

local Path = {}

-- Module
local NodeModule = require(script:WaitForChild("NodeModule"))

local function SetUp()	-- Createa a grid to use for pathfinding
	for x = 1, Rows do		
		Grid[x] = {} 
		for y = 1, Columns do
			local IsPath = true	-- 1,1 and 100,100 are not path nodes as they are the start and end
			if x == 1 and y == 1 then	-- Starting node
				IsPath = false
			end
			if x == Rows and y == Columns then	-- End node
				IsPath = false
			end
			Grid[x][y] = NodeModule.new(x, y, IsPath)	-- Construct an object class for the node called Grid[x][y]
		end
	end
	for x = 1, Rows do
		for y = 1, Columns do
			Grid[x][y]:Show()	 -- VIsualize the node
			Grid[x][y]:AddNeighbours(Grid)
		end
		if x%5 == 0 then	
			-- e.g: 10%5 = 0, or 15%5 = 0, so multiples of 5
			-- I have no idea why you need this
			wait(0.1)
		end
	end
end

local function RemoveFromTable(OpenList, CurrentNode)
	for i = 1, #OpenList do
		if OpenList[i] == CurrentNode then
			-- if its the current node remove it
			table.remove(OpenList, i)
			break
		end
	end
end

local function Is_Valid_Neighbour(List, NeighbourNode)
	for i = 1, #List do
		if List[i] == NeighbourNode then
			return true
		end
	end
	return false
end

local function Start()
	Start_Node = Grid[1][1]
	End_Node = Grid[Rows][Columns]

	table.insert(OpenList, Start_Node)

	while #OpenList > 0 do
		
		wait()
		if #OpenList > 0 then

			local Min = 1
			for i = 1, #OpenList do
				if OpenList[i].f < OpenList[Min].f then	-- Still dont really understand this bit
					Min = i	
				end
			end
			-- Get the current node
			-- let the currentNode equal the node with the least f value
			local CurrentNode = OpenList[Min]
			-- if currentNode is the goal
			if CurrentNode == End_Node then
				break
			end

			RemoveFromTable(OpenList, CurrentNode)	
			table.insert(CloseList, CurrentNode)	

			local Neighbours = CurrentNode.neighbours

			for i = 1, #Neighbours do
				-- Neighbour is one object, Neighbours is the table
				local Neighbour = Neighbours[i]
				local NewPath = false

				if not Is_Valid_Neighbour(CloseList, Neighbours) and not Neighbour.Wall then
					local _TempG = CurrentNode.g + 1
					if Is_Valid_Neighbour(OpenList, Neighbour) then
						if _TempG < Neighbour.g then	-- if current node g is less than neighbour node g, but what does that mean?
							Neighbour.g = _TempG
							NewPath = true
						end
					else
						Neighbour.g = _TempG
						NewPath = true
						table.insert(OpenList, Neighbour)
					end
				end
				if NewPath then
					Neighbour:Heuristic(End_Node)
					Neighbour.f = Neighbour.g + Neighbour.h
					Neighbour.previous = CurrentNode
				end
			end
			-- visualize the nodes
			for i = 1, #CloseList do
				CloseList[i]:ShowClosed()
			end
			for i = 1, #OpenList do
				OpenList[i]:ShowOpen()
			end

			Path = {}
			local Temp = CurrentNode
			table.insert(Path, Temp)	-- insert path node into the table
			local Value = 1

			while Temp.previous do	-- Insert path nodes into path table
				-- exhaused allowed exectuion time
				Value += 1
				table.insert(Path, Temp.previous)
				Temp = Temp.previous
			end
			
			for i = 1, #Path do
				Path[i]:ShowPath()
			end

		end

	end

end

SetUp()
wait(1)
Start()


Because it’s a lot of work, I’m busy with an A star pathfinding commision right now at the moment in fact :laughing: enough to get paid for.

I suggest looking at this excellent community resource which formats the A star path finding better and modularizing it according to the RedBlob games A star path finding article with the aformentioned data structures PriorityQueue.

If you don’t have a cameFrom dictionary then you might need to add on.

Removing the while loop, everything else works perfectly fine. If anyone has any suggestions or alternatives to construct a path, it’d be appreciated.