(Advanced) Help needed making this A* run faster

What extra calculations i can remove/change to make it faster?
For now the timer(tick-s) is around 3 seconds, how could i reduce it?

-- A* Pathfinding in ROBLOX with Vector3 Nodes

local function Heuristic(a, b)
	-- Use Manhattan distance as the heuristic
	return (math.abs(a.X - b.X) + math.abs(a.Y - b.Y) + math.abs(a.Z - b.Z))
end

local function GetNeighbors(node)
	-- Define your neighbors function here
	-- For simplicity, let's assume the neighbors are directly adjacent on the grid
	local neighbors = {}
	local offsets = {
		Vector3.new(1, 0, 0), Vector3.new(-1, 0, 0),
		Vector3.new(0, 1, 0), Vector3.new(0, -1, 0),
		Vector3.new(0, 0, 1), Vector3.new(0, 0, -1)
	}

	for _, offset in pairs(offsets) do
		local inPart = #workspace:getPartBoundsInRadius(node + offset, 0.001) > 0
		if inPart == false then
			table.insert(neighbors, node + offset)
			
		end
	end

	return neighbors
end

local function AStar(start, goal)
	local openSet = {[start] = true}
	local cameFrom = {}
	local gScore = {[start] = 0}
	local fScore = {[start] = Heuristic(start, goal)}

	while next(openSet) do
		-- Find the node in openSet with the lowest fScore
		local current
		for node in pairs(openSet) do
			if not current or fScore[node] < fScore[current] then
				current = node
			end
		end
		if current == goal then
			-- Reconstruct path
			local totalPath = {current}
			while cameFrom[current] do
				current = cameFrom[current]
				table.insert(totalPath, 1, current)
			end
			return totalPath
		end
		local offsets = {
			Vector3.new(1, 0, 0), Vector3.new(-1, 0, 0),
			Vector3.new(0, 1, 0), Vector3.new(0, -1, 0),
			Vector3.new(0, 0, 1), Vector3.new(0, 0, -1)
		}
		openSet[current] = nil
		for _, offset in pairs(offsets) do
			local neighbor = current + offset
			local inPart = #workspace:getPartBoundsInRadius(neighbor, 0.001) > 0
			if inPart == false then
				local tentative_gScore = gScore[current] + (neighbor - current).Magnitude
				if not gScore[neighbor] or tentative_gScore < gScore[neighbor] then
					-- This path to neighbor is better than any previous one
					cameFrom[neighbor] = current
					gScore[neighbor] = tentative_gScore
					fScore[neighbor] = gScore[neighbor] + Heuristic(neighbor, goal)
					openSet[neighbor] = true
				end
			end
			
		end
	end

	-- Return an empty table if there is no path
	return {}
end
wait(5)
local s = tick()

-- Define your start and goal points
local start = Vector3.new(1, 1, 1)
local goal = Vector3.new(40, 40, 40)

-- Run the A* algorithm
local path = AStar(start, goal)
-- Output the path
for _, node in ipairs(path) do
	print(node)
	
end
s = tick()-s
print(s)```

Try caching the results of GetPartBoundsInRadius, basically if you already have figured out the inPart value for a specific neighbor, don’t calculate it again if you re-encounter it(this is for a single run of A*, don’t cache the values for multiple independent calls of A*). Also you can avoid running the function GetPartBoundsInRadius for certain occassions by changing the priority of your if statements. Basically you can check for not gScore[neighbor] or tentative_gScore < gScore[neighbor] first, and only if that’s true run the function to figure out if it’s in part or not.

Basically try to minimize the GetPartBoundsInRadius calls. It’s the only thing out of place within your code, so it might provide a few performance boosts(and if I’m not mistaken it’s also being called quite a lot).

1 Like

Doesnt really reduces. it still gets on same result.
is this the code you mean:

for _, offset in pairs(offsets) do		
	local neighbor = current + offset
	if  blocked[neighbor] ~= true then
		local inPart = #workspace:getPartBoundsInRadius(neighbor, 0.001) > 0
		if inPart == false then
			local tentative_gScore = gScore[current] + (neighbor - current).Magnitude
			if not gScore[neighbor] or tentative_gScore < gScore[neighbor] then
				-- This path to neighbor is better than any previous one
				cameFrom[neighbor] = current
				gScore[neighbor] = tentative_gScore
				fScore[neighbor] = gScore[neighbor] + Heuristic(neighbor, goal)
				openSet[neighbor] = true
			end
		else
			blocked[neighbor] = true
		end
	end		
end

also is there anything else i can use to reduce the wait time?

You are looping and sorting through all the possible next nodes every iteration and not using a priority queue?

I would take a look into that.

2 Likes

Oh wow thanks! that recudes the wait time by 10X. i will post the full code in #resources:community-resources if it gets attention

1 Like

No problem, got the idea from redblob games a star tutorial. Ill leave a link to it here as its too good not to share.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.