Trusses & pathdinding NPC's

I created a path finding a using the documentation this and it works pretty well… trusses. it just acts strange around them getting stuck in a loop or outright refusing to climb them. This is a problem as the script is meant to be for a zombie rush game where large a quantity of zombies are traversing a complex map.

The code. it’s used inside a server Script inside a dummy.

local PathfindingService = game:GetService("PathfindingService")
local RunService = game:GetService("RunService")

local path = PathfindingService:CreatePath({
	AgentRadius = 1.5,
	AgentHeight = 5,
	AgentCanJump = true,
	AgentCanClimb = true,
	WaypointSpacing = 6,
	Costs = {
		Climb = 10,  -- Cost of the climbing path; default is 1
		Jump = 50
	}
})

local character = script.Parent
local rootPart = character:WaitForChild("HumanoidRootPart")
rootPart:SetNetworkOwner(nil)
local humanoid = character:WaitForChild("Humanoid")

local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection

local climbingTruss = false

rootPart.Touched:Connect(function(obj)
	if obj:IsA("TrussPart") then
		climbingTruss = true
	else
		climbingTruss = false
	end
end)

local function followPath(destination)
	-- Compute the path
	local success, errorMessage = pcall(function()
		path:ComputeAsync(character.PrimaryPart.Position, destination)
	end)

	if success and path.Status == Enum.PathStatus.Success then
		-- Get the path waypoints
		waypoints = path:GetWaypoints()
		
		-- Detect if path becomes blocked
		blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
			-- Check if the obstacle is further down the path
			if blockedWaypointIndex >= nextWaypointIndex then
				-- Stop detecting path blockage until path is re-computed
				blockedConnection:Disconnect()
				-- Call function to re-compute new path
				followPath(destination)
			end
		end)

		-- Detect when movement to next waypoint is complete
		if not reachedConnection then
			reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
				if reached and nextWaypointIndex < #waypoints then
					-- Increase waypoint index and move to next waypoint
					
					if waypoints[nextWaypointIndex+1].Action == Enum.PathWaypointAction.Jump then
						humanoid.Jump = true
						print("jumped")
					end

					nextWaypointIndex += 1
					humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
				end
			end)
		end

		-- Initially move to second waypoint (first waypoint is path start; skip it)

		nextWaypointIndex = 2
		humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
	else
		warn("Path not computed!", errorMessage)
	end
end

function getNearestCharacter()
	local nearestCharacter, nearestDistance
	for _, player in pairs(game:GetService("Players"):GetPlayers()) do
		local character = player.Character
		local distance = player:DistanceFromCharacter(rootPart.Position)
		if not character or 
			distance > 512 or
			(nearestDistance and distance >= nearestDistance)
		then
			continue
		end
		nearestDistance = distance
		nearestCharacter = character
	end
	return nearestCharacter
end


while true do
	if blockedConnection then
		blockedConnection:Disconnect()
	end

	local player = getNearestCharacter()

	if player then
		if climbingTruss == false then
			if (rootPart.Position - player.HumanoidRootPart.Position).magnitude < 12 then
				humanoid:MoveTo(player.HumanoidRootPart.Position)
				task.wait(.1)
			else
				followPath(player.HumanoidRootPart.Position)
			end
		else
			humanoid:MoveTo(player.HumanoidRootPart.Position)
		end
	end
	task.wait(.1)
end

How do I improve upon this without having to write path finding using A*?

1 Like