How to make a AI climb trusses?

i want this ai to climb trusses to get to player but never done this before so I need help qwq


it trys to find a dif path to get to player

I tried make it like detect the truss and move to it but it just falls off after 1 secs

local SearchDistance = 150	-- How far a player can be before it detects you

local ZombieDamage = 5		-- How much damage the Zombie inficts towards the player

local canWander = true
local WanderX, WanderZ = 10, 10


function getHumanoid(model)
	for _, v in pairs(model:GetChildren()) do
		if v:IsA'Humanoid' then
			return v
		end
	end
end

local zombie = script.Parent
local human = getHumanoid(zombie)
local hroot = zombie.HumanoidRootPart
local zspeed = hroot.Velocity.magnitude


local pfs = game:GetService("PathfindingService")

function GetPlayerNames()
	local players = game:GetService('Players'):GetChildren()
	local name = nil
	for _, v in pairs(players) do
		if v:IsA'Player' then
			name = tostring(v.Name)
		end
	end
	return name
end

spawn(function()
	while wait() do
	end
end)

function GetPlayersBodyParts(t)
	local torso = t
	if torso then
		local figure = torso.Parent
		for _, v in pairs(figure:GetChildren()) do
			if v:IsA'Part' then
				return v.Name
			end
		end
	else
		return "HumanoidRootPart"
	end
end

function GetTorso(part)
    local chars = game.Workspace:GetChildren()
    local torso = nil
    for _, v in pairs(chars) do
        if v:IsA("Model") and v ~= script.Parent then
            local player = game.Players:GetPlayerFromCharacter(v)
            if player and player.Team == game.Teams["Human"] then
                local charRoot = v:FindFirstChild("HumanoidRootPart")
				if (charRoot.Position - part).magnitude < SearchDistance then
					torso = charRoot
				end
            end
        end
    end
    return torso
end

local cooldownTime = 1  -- Time in seconds between damages
local lastDamageTime = {}  -- Table to store the last damage time for each player

for _, zambieparts in pairs(zombie:GetChildren()) do
	if zambieparts:IsA'Part' then
		zambieparts.Touched:connect(function(p)
			local player = game.Players:GetPlayerFromCharacter(p.Parent)
			if player and p.Parent.Name == GetPlayerNames() and p.Parent.Name ~= zombie.Name then -- damage
				-- Check if the player has a cooldown remaining
				local currentTime = tick()
				if player.Team and player.Team.Name ~= "Transfured" then
					-- Check if the cooldown is over or if player has never been damaged before
					if not lastDamageTime[player.UserId] or currentTime - lastDamageTime[player.UserId] >= cooldownTime then
						-- Damage the player
						local enemy = p.Parent
						local enemyhuman = getHumanoid(enemy)
						enemyhuman:TakeDamage(ZombieDamage)

						-- Update the last damage time for this player
						lastDamageTime[player.UserId] = currentTime
					end
				end
			end
		end)
	end
end


-- no touchy
local path
local waypoint
local oldpoints
local isWandering = 0

if canWander then
	spawn(function()
		while isWandering == 0 do
			isWandering = 1
			local desgx, desgz = hroot.Position.x + math.random(-WanderX, WanderX), hroot.Position.z + math.random(-WanderZ, WanderZ)
			human:MoveTo( Vector3.new(desgx, 0, desgz) )
			wait(math.random(4, 6))
			isWandering = 0
		end
	end)
end

while wait() do
	local enemytorso = GetTorso(hroot.Position)	
	if enemytorso ~= nil then -- if player detected
		isWandering = 1
		local function checkw(t)
			local ci = 3
			if ci > #t then
				ci = 3
			end
			if t[ci] == nil and ci < #t then
				repeat
					ci = ci + 1
					wait()
				until t[ci] ~= nil
				return Vector3.new(1, 0, 0) + t[ci]
			else
				ci = 3
				return t[ci]
			end
		end
		
		path = pfs:FindPathAsync(hroot.Position, enemytorso.Position)
		waypoint = path:GetWaypoints()
		oldpoints = waypoint
		local connection;
		
		local direct = Vector3.FromNormalId(Enum.NormalId.Front)
		local ncf = hroot.CFrame * CFrame.new(direct)
		direct = ncf.p.unit
		local rootr = Ray.new(hroot.Position, direct)
		local phit, ppos = game.Workspace:FindPartOnRay(rootr, hroot)
		
		if path and waypoint or checkw(waypoint) then
			if checkw(waypoint) ~= nil and checkw(waypoint).Action == Enum.PathWaypointAction.Walk then
				human:MoveTo( checkw(waypoint).Position )
				human.Jump = false
			end
			
			if checkw(waypoint) ~= nil and checkw(waypoint).Action == Enum.PathWaypointAction.Jump then
				human.Jump = true
				connection = human.Changed:connect(function()
					human.Jump = true
				end)
				human:MoveTo( checkw(waypoint).Position )
			else
				human.Jump = false
			end
			
			if connection then
				connection:Disconnect()
			end
			
		else
			for i = 3, #oldpoints do
				human:MoveTo( oldpoints[i].Position )	
			end
		end
	elseif enemytorso == nil and canWander then -- if player not detected
		isWandering = 0
		path = nil
		waypoint = nil
		human.MoveToFinished:Wait()
	end
end

Use PathFindService create path with agentparameters’ canclimb to true and then compute it like so:

local pth = Pfs:CreatePath({CanClimb = true})
pth:ComputeAsync(pos1, pos2)

for _ , w in ipairs(pth:GetWayPoints()) do
--handle the waypoints
end

Hope thi s helps

i cant find any “CreatePath” things in my script and when I tried adding it. it broke qwq

image

Createpath is part of PathfindingService. Replace all calls to FindPathAsync with CreatePath because FindPathAsync is deprecated.

its my first time using pathfinding lol but uh. like this?


image

idk what any of these mean qwq. even the doc of these don’t help

i just looked at console: FindPathAsync is not a valid member of Path “Instance”.
but when I change it to just PTH. it does not go after player :<

no, okay, FindPathAsync is deprecated, in favor of CreatePath, both are functions of the PathfindingService.

FindPathAsync uses the default agent parameters, but you can pass custom ones with CreatePath.
Okay so step 1.

Create a path object using CreatePath, allowing the agent to climb:

local pfs = game:GetService "PathfindingService"
local path = pfs:CreatePath({CanClimb = true})

then, we now have an empty path, with custom agent params, we need to now actually compute the path, to do so call ComputeAsync on the newly created path:

path:ComputeAsync(your pos, your pos 1)
--ComputeAsync accepts two positions and returns void(nil)

Now your path has waypoints, use GetWaypoints to enumerate through them:

for _, way in ipairs(path:GetWaypoints()) do
--do smthing
end

now when the agent sees a truss, it will attempt to climb it, because you specified it is allowed to do so.

for more information, look at the docs:
PathfindingService | Documentation - Roblox Creator Hub
Path | Documentation - Roblox Creator Hub

hope this helps!

edit: you obviously have to move to each point in the for loop like so:

for _, way in ipairs(path:GetWaypoints()) do
    if way.Action = Enum.PathWaypointAction.Jump then
        yourhumanoid.Jump = true
    end

    yourhumanoid:MoveTo(way.Position)
end

PathWaypoint | Documentation - Roblox Creator Hub