Roblox A* pathfinding is really laggy on bigger distances, How would i optimize it?

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!
    I have created an A* path and want to achieve 2 things,
  1. is it possible to remove from open list the nodes that are not adjecent to the current node without ruining my pathfinding? if so how would i do that?
  2. optimize to make it run faster.
  1. What is the issue? Include screenshots / videos if possible!
    The issue is that when i remove the nodes that are not adjecent to the current node, the path is getting stuck on walls.

  2. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    i have tried to add for i,node in pairs(opentable) table.remove(opentable,i) if its not the current and is not adjecent to the current, path is breaking inside the wall.
    thi is the project
    astar.rbxl (52.2 KB)

I cant find a solution to make it work with less lag between the sessions, i dont want to loop between each waypoint because it wont make my path dynamic
the full code is here:


-- A* Pathfinding Algorithm in Lua (3D with Vector3)

-- Function to calculate the Euclidean distance between two Vector3 points
function calculateDistance(v1, v2)
	return (v2 - v1).Magnitude
end
local function roundToStep(pos : Vector3)
	return Vector3.new(math.floor(pos.X/3)*3+1.5,math.floor(pos.Y/3)*3+1.5, math.floor(pos.Z/3)*3+1.5)
end
local Blocks = {}
for i,v in pairs(workspace.Map:GetChildren()) do
	for x= -v.Size.X / 2 ,v.Size.X / 2-3,3 do
		for y= -v.Size.Y / 2 - 6 ,v.Size.Y / 2-3,3 do
			for z= -v.Size.Z / 2 ,v.Size.Z / 2-3,3 do
				Blocks[roundToStep(v.Position+Vector3.new(x,y,z))] = v

			end
		end
	end
end
-- A* Pathfinding function for 3D grid
function astar3D(start, goal)
	start = roundToStep(start)
	goal = roundToStep(goal)
	local openSet = {start}
	local closedSet = {}
	local cameFrom = {}

	local gScore = {}
	local fScore = {}

	gScore[start] = 0
	fScore[start] = calculateDistance(start, goal)

	while #openSet > 0 do
		-- Find the node with the lowest fScore in openSet
		local current = openSet[1]
		for i = 2, #openSet do
			if fScore[openSet[i]] < fScore[current] then
				current = openSet[i]
			end
			print(#openSet)
		end

		-- Goal reached, reconstruct path
		if current == goal then
			local path = {current}
			while cameFrom[current] do
				current = cameFrom[current]
				table.insert(path, 1, current)
				
			end
			return path
		end
		
		-- Move current from openSet to closedSet
		for i, node in ipairs(openSet) do
			if node == current then
				table.remove(openSet, i)
				break
			end
		end
		
		--table.insert(closedSet, current)
		closedSet[current] = current
		-- Explore neighbors
		local neighbors = {
			current + Vector3.new(3, 0, 0),
			current + Vector3.new(-3, 0, 0),
			current + Vector3.new(0, 3, 0),
			current + Vector3.new(0, -3, 0),
			current + Vector3.new(0, 0, 3),
			current + Vector3.new(0, 0, -3)
		}

		for _, neighbor in ipairs(neighbors) do
			if closedSet[neighbor] == nil and  Blocks[roundToStep(neighbor)] == nil then
				local tentative_gScore = gScore[current] + 1 -- Assuming uniform cost for simplicity

				if not contains(openSet, neighbor) or tentative_gScore < (gScore[neighbor] or math.huge) then
					cameFrom[neighbor] = current
					gScore[neighbor] = tentative_gScore
					fScore[neighbor] = gScore[neighbor] + calculateDistance(neighbor, goal)

					if not contains(openSet, neighbor) then
						table.insert(openSet, neighbor)
					end
				end
			end
		end
	end

	-- No path found
	return nil
end

-- Helper function to check if a table contains a specific Vector33 element
function contains(table, element)
	for _, value in ipairs(table) do
		if value == element then
			return true
		end
	end
	return false
end

-- Example usage
local start = Vector3.new(1, 1, 1)
local goal = Vector3.new(1, 1, 31)
local obstacles = {}

for i,v in pairs(workspace.Map:GetChildren()) do
	table.insert(obstacles, v.Position)
end
local currentPart
while wait(0.1) do
	
	if not currentPart then
		print(3)
		currentPart = workspace.start
	end
	local path = astar3D(currentPart.Position, workspace.target.Position)
	if path and #path >=2 then
		print("Path found:")
		local a = Instance.new("Part")
		a.Size = Vector3.new(3,3,3)
		a.Position = path[2]
		a.Anchored = true
		a.CanCollide = false
		a.Parent = workspace
		a.Material = Enum.Material.SmoothPlastic
		a.Color = Color3.new(0, 0, 0.498039)
		currentPart = a
	else
		print("No path found.")
	end
end
print(#openSet)

thats what the issue was