I want my NPC to be able to climb a truss but it doesn’t seem to work.
local RunService = game:GetService("RunService")
local PathfindingService = game:GetService("PathfindingService")
local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")
local WalkSpeed = humanoid.WalkSpeed
local DestinationsFolder = workspace:WaitForChild("Destinations")
local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection
local currentPath = nil
local loopConnetion
local function randomWaypoint()
local waypoint = DestinationsFolder:GetChildren()
local random = waypoint[math.random(1, #waypoint)]
return random
end
local function WalkTo(destination)
local pathParams = {
AgentHeight = character:GetExtentsSize().Y,
AgentRadius = (character:GetExtentsSize().X + character:GetExtentsSize().Z)/4,
AgentCanJump = true,
AgentCanClimb = true,
Costs = {
Danger = math.huge,
Climb = 2,
}
}
local path = PathfindingService:CreatePath(pathParams)
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination.Position)
end)
waypoints = {}
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
if blockedWaypointIndex >= nextWaypointIndex then
blockedConnection:Disconnect()
WalkTo(destination)
end
end)
if success and path.Status == Enum.PathStatus.Success then
waypoints = path:GetWaypoints()
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
WalkTo(randomWaypoint())
currentPath = nil
end
end)
end
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
if waypoints[nextWaypointIndex].Action == Enum.PathWaypointAction.Jump then
humanoid.Jump = true
end
elseif not success and path.Status ~= Enum.PathStatus.Success then
humanoid:MoveTo(destination.Position)
elseif success and path.Status == Enum.PathStatus.NoPath then
if reachedConnection then
reachedConnection:Disconnect()
end
end
end
loopConnetion = RunService.Heartbeat:Connect(function()
if currentPath == nil then
WalkTo(randomWaypoint())
currentPath = randomWaypoint()
else
WalkTo(currentPath)
end
if humanoid.Health <= 0 and loopConnetion then
loopConnetion:Disconnect()
end
end)
As @Dede_4242 mentioned, it’s all in the documentation as well.
If you’ve changed your script then post it so we can see exactly what’s going on. Statements such as “Like I changed a bit of the code” don’t really tell us anything about what you’ve changed.
Somewhat late but I believe a hacky solution to this problem is setting nextWaypointIndex to 3 instead of 2 on line 66.
I think this problem is caused by the fact that humanoid.MoveToFinished passes true even if the humanoid is not at the same y level as the destination point, meaning it will walk up to the ladder, think that it successfully reached the target waypoint, add 1 to the nextWaypointIndex (making it 3, the waypoint at the top of the ladder) and then begin moving to waypoint 3, except immediately after this it will set the nextWaypointIndex to 2, and begin moving towards waypoint 2, which overwrites the movement to waypoint 3.
It will then reach waypoint 2, and, ofcourse, humanoid.MoveToFinished will say that it reached waypoint 2, which will set it to move to waypoint 3, only for it to then be overwritten by moving to waypoint 2.
So if it just always sets it to waypoint 3, it would climb the ladder in this specific case.
I think.
Probably.
It works but now it errors. attempt to index nil with ‘Position’.
local function WalkTo(destination)
local pathParams = {
AgentHeight = character:GetExtentsSize().Y,
AgentRadius = (character:GetExtentsSize().X + character:GetExtentsSize().Z)/4,
AgentCanJump = true,
AgentCanClimb = true,
Costs = {
Danger = math.huge,
Climb = 2,
}
}
local path = PathfindingService:CreatePath(pathParams)
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination.Position)
end)
waypoints = {}
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
if blockedWaypointIndex >= nextWaypointIndex then
blockedConnection:Disconnect()
WalkTo(destination)
end
end)
if success and path.Status == Enum.PathStatus.Success then
waypoints = path:GetWaypoints()
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
WalkTo(randomWaypoint())
currentPath = nil
reachedConnection:Disconnect()
end
end)
end
nextWaypointIndex = 3
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
if waypoints[nextWaypointIndex].Action == Enum.PathWaypointAction.Jump then
humanoid.Jump = true
end
elseif not success and path.Status ~= Enum.PathStatus.Success then
humanoid:MoveTo(destination.Position)
elseif success and path.Status == Enum.PathStatus.NoPath then
if reachedConnection then
reachedConnection:Disconnect()
end
end
end
Sorry for again being late, I genuinely cannot think of how to properly solve this problem, so here’s another extremely hacky solution: Rather than setting the nextWaypointIndex to 3 instead of 2 (which runs into the risk of it looking for a third waypoint when there are only 2 waypoints at the end), you can add an if statement to see if it found the next waypoint in the Humanoid.MoveToFinished event, which looks like this.
local RunService = game:GetService("RunService")
local PathfindingService = game:GetService("PathfindingService")
local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")
local WalkSpeed = humanoid.WalkSpeed
local DestinationsFolder = workspace:WaitForChild("Destinations")
local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection
local foundNextWaypoint = false
local currentPath = nil
local loopConnetion
local function randomWaypoint()
local waypoint = DestinationsFolder:GetChildren()
local random = waypoint[math.random(1, #waypoint)]
return random
end
local function WalkTo(destination)
local pathParams = {
AgentHeight = character:GetExtentsSize().Y,
AgentRadius = (character:GetExtentsSize().X + character:GetExtentsSize().Z)/4,
AgentCanJump = true,
AgentCanClimb = true,
Costs = {
Danger = math.huge,
Climb = 2,
}
}
local path = PathfindingService:CreatePath(pathParams)
local success, errorMessage = pcall(function()
path:ComputeAsync(character.PrimaryPart.Position, destination.Position)
end)
waypoints = {}
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
if blockedWaypointIndex >= nextWaypointIndex then
blockedConnection:Disconnect()
WalkTo(destination)
end
end)
if success and path.Status == Enum.PathStatus.Success then
waypoints = path:GetWaypoints()
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
foundNextWaypoint = true
else
WalkTo(randomWaypoint())
currentPath = nil
foundNextWaypoint = false
end
end)
end
if foundNextWaypoint==false then
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
if waypoints[nextWaypointIndex].Action == Enum.PathWaypointAction.Jump then
humanoid.Jump = true
end
end
elseif not success and path.Status ~= Enum.PathStatus.Success then
humanoid:MoveTo(destination.Position)
elseif success and path.Status == Enum.PathStatus.NoPath then
if reachedConnection then
reachedConnection:Disconnect()
end
end
end
loopConnetion = RunService.Heartbeat:Connect(function()
if currentPath == nil then
WalkTo(randomWaypoint())
currentPath = randomWaypoint()
else
WalkTo(currentPath)
end
if humanoid.Health <= 0 and loopConnetion then
loopConnetion:Disconnect()
end
end)