NPC not walking off ledge

I’ve attempted to switch up lines of codes, anchor and unanchor and so on, no solutions have by far worked. I seek to fix the problem where it doesn’t wan’t to walk off the ledge, its pretty annoying.

I am not going to use raycasting or any form of checking if the player is nearby to ignore using pathfinding due to there being dozens of NPCs at best, just don’t try assisting with this topic.

Help me, please, this is so bothersome and pathfinding is the worst thing to deal with.

If code is actually required, tell me.


Video for reference.

3 Likes

Just to clarify this is roblox pathfinding, not custom nor a free model. (the cars you see were me testing how smart the npc is when walking over obstacles) the red and blue ball are pathfinding links

Yes you may need some extra code
In your pathfinding script, add a table called agent parameters, these basically are some regulations for your path’s agent (your NPC in this case) eg. whether your agent can jump or run. While there are a couple of agent parameters, only two concern this issue. Add this piece of code:

local AgentParams = {
   AgentCanJump = true
   AgentCanClimb = true 
}
local Path = game.PathfindingService:CreatePath(AgentParams)

EXPLANATION
By default, canjump and canclimb are set to false, so your agent (NPC) can’t jump or climb which may be why your NPC can’t fall off (I do see there’s a truss, which falls under canclimb criteria) because either one of them is preventing it from falling. If this doesn’t work then check out the pathfinding docs here for your own reference

I do have agent parameters in my code.

I’ve also tried finding solutions from the pathfinding documents, which did not work.

robloxapp-20240809-1627291.wmv (1.4 MB)
If you saw the video above, that was my own pathfinding script and the NPC did fall off the ledge (my path didn’t use any agent params). So it’s probably a problem with your npc or code

I can help you out with your code if you want me to

Yea I would appreciate it, how will you help anyways?

I’ll try and list out important pieces of code for you. Anyway, do you have a function where you ray cast to see if your NPC can see the player? If you do then you should probably comment it out.

I did list that i did not want any form of raycasting to detect NPCs seeing players.

simple awnser no i dont have raycasting

Could you like, show me your main code? I’ll try and see the parts you need to change

--((Services))
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService('Players')
local PathfindingService = game:GetService("PathfindingService")

--((Variables))
local SimplePath = require(ServerStorage.SimplePath)
local NPC = script.Parent
local Animator = NPC.Humanoid:FindFirstChild("Animator")
local Animation = ServerStorage.Anims.Attack
local AnimationLoaded = Animator:LoadAnimation(Animation)
local WooshSFX = NPC.HumanoidRootPart.Woosh

local Extraspeed = script.Parent:GetAttribute("AttackSlowdown")

--((Attack Function))
local function AttackFX()
	WooshSFX:Play()
	AnimationLoaded:Play()
end

for _,v in pairs(script.Parent:GetDescendants()) do
	if (v:IsA("BasePart")) then
		v:SetNetworkOwner(nil)
	end
end
local AgentParams = {
	AgentRadius = 2,
	AgentHeight = 5,
	WaypointSpacing = 3,
	AgentCanJump = true,
	AgentCanClimb = true
}

local path = PathfindingService:CreatePath(AgentParams)

local NearestPLR, NearestDist, NearestAttackDist, Damage = nil, nil, nil, nil

while task.wait() do
	if NPC.Humanoid.Health > 0 then

		NearestPLR, NearestDist, NearestAttackDist, Damage = nil, NPC:GetAttribute("SearchRange"), NPC:GetAttribute("AttackDistance"), NPC:GetAttribute("Damage")


		for _, plr in workspace:GetChildren() do
			if plr ~= nil then
				if plr:FindFirstChild("IsPlayer") or plr:FindFirstChild("IsCore") then
					local dist = (NPC.PrimaryPart.Position - plr.PrimaryPart.Position).Magnitude		

					if dist < NearestDist then

						NearestPLR = plr
						NearestDist = dist

						if dist < NearestAttackDist then
							AttackFX()
							NPC.Humanoid.WalkSpeed = NPC.Humanoid.WalkSpeed - Extraspeed
							task.wait(0.4)
							local Coroutine = coroutine.wrap(function()
								local dist2 = (NPC.PrimaryPart.Position - plr.PrimaryPart.Position).Magnitude		
								if dist2 < NearestAttackDist then
									local hum = plr:FindFirstChild("Humanoid")
									hum:TakeDamage(Damage)
								end
								NPC.Humanoid.WalkSpeed = NPC.Humanoid.WalkSpeed + Extraspeed
								task.wait(1.5)
							end)
							Coroutine()
						end	
					end
				end	
			end
		end
	end

	if NearestPLR ~= nil then	
		local function followPath()
			local waypoints
			local nextWaypointIndex
			
			-- Compute the path
			path:ComputeAsync(NPC.PrimaryPart.Position - Vector3.new(0, NPC.PrimaryPart.Size.Y/0.75, 0), NearestPLR.PrimaryPart.Position)
			local function a()
				for i, v in path:GetWaypoints() do
					local part = Instance.new("Part")
					part.Position = v.Position
					part.Anchored = true
					part.Parent = workspace.Debris
					part.Material = "Neon"
					part.BrickColor = BrickColor.new("Really red")
					part.Size = Vector3.new(0.2,0.2,0.2)
					part.CanCollide = false
					task.wait(.1)
					part:Destroy()
				end
			end
			task.spawn(a)
			
			waypoints = path:GetWaypoints()
			
			nextWaypointIndex = 2
			NPC.Humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
			NPC.Humanoid.MoveToFinished:Connect(function()
			end)
		end
		followPath(NearestPLR.PrimaryPart.Position)
	end
end

If you want me to shorten it into only the AI part, I’ll go ahead.

I don’t see any things blatantly wrong with your script. Try these however,

  1. Just remove the agent params temporarily and see if it makes a difference
  2. In the line path:ComputeAsync(NPC.PrimaryPart.Position - Vector3.new(0, NPC.PrimaryPart.Size.Y/0.75, 0), NearestPLR.PrimaryPart.Position), remove the vector3 statement. Are you subtracting it to like, put the zombie on the ground?

It was someone else’s solution of a problem for their NPC and I was trying it, but it didn’t work.

Removing the Vector3 statement didn’t work.

Removing the agent parameters didn’t work, both of these didn’t work at all, what could be the problem?

I will show you my script, then see if they are any major diffs
(Im using OOP)

local PaOOP = {}
local players = game:GetService('Players')
local pathfindingService = game:GetService('PathfindingService')
PaOOP.__index = PaOOP
function PaOOP:new(bot : Model)
	self = setmetatable({}, PaOOP)
	self.bot = bot
	return self
end
function PaOOP:CanSeeCharacter(player)
	local rp = RaycastParams.new()
	rp.FilterDescendantsInstances = {self.bot}
	rp.FilterType = Enum.RaycastFilterType.Exclude
	local hrp = self.bot.HumanoidRootPart
	local ray = workspace:Raycast(hrp.Position,(player.Character.HumanoidRootPart.Position - hrp.Position).Unit * 100,rp)
	if ray then
		if ray.Instance:IsDescendantOf(player.Character) then
			return true
		else
			return false
		end
	else
		return false
	end
end
function PaOOP:GetNearestPlayer(bpos: Vector3)
	local sdist = 100
	local np 
	for i, player in pairs(players:GetPlayers()) do
		if not player.Character then continue end
		local dist = (bpos - player.Character.HumanoidRootPart.Position).Magnitude
		if dist <= sdist --[[and self:CanSeeCharacter(player)]] then
			sdist = dist
			np = player
		end
	end
	return np
end
function PaOOP:TargetPlayer()
	local path = pathfindingService:CreatePath()
	local fwaypoints = workspace.Waypoints:GetChildren()
	local player = self:GetNearestPlayer(self.bot.HumanoidRootPart.Position)
	if player ~= nil then
		path:ComputeAsync(self.bot.HumanoidRootPart.Position,player.Character.HumanoidRootPart.Position)
		if path.Status == Enum.PathStatus.Success then
			local waypoints = path:GetWaypoints()
			for i, w in pairs(waypoints) do
				self.bot.Humanoid:MoveTo(w.Position) 
			end
		else
			self.bot.Humanoid:MoveTo(workspace.SpawnLocation.Position)
		end
	else
		self.bot.Humanoid:MoveTo(fwaypoints[math.random(1,#fwaypoints)].Position)
		self.bot.Humanoid.MoveToFinished:Wait()
	end
end
return PaOOP

As you can see, I didn’t write a lot of code so I really can’t tell the issue with your script

Do you think it might be outside of the script? I can’t find what’s wrong with mine in any way.

Yours might be working due to raycasting, I cannot efficiently use raycasting to find the player if there are no obstacles due to my plans of having dozens of NPCs, what I mean is the raycasts will be blocked by the NPCs, and getting all the NPCs in the raycast parameters would lag the game a hefty amount as your possibly getting hundreds of parts each raycast. Unless you know a solution, I’m dumbfounded.

You could try and see if my problem occurs when you don’t raycast if possible.

It could be outside… maybe check your NPC, or you could try this (Its not clean but it kinda makes him fall off, it uses a ray)

for i,waypoint in path:GetWaypoints() do
   if not workspace:Raycast(waypoint.Position, Vector3.new(0,-1,0)) then -- Make the direction as small as possible
      NPC.PrimaryPart:ApplyImpulse(-(NPC.PrimaryPart.CFrame.RightVector) * 5) -- [[Its negative
right vector bc for some reason that is the front vector of HumRootPart]]--
   end
end

Basically it raycast downwards from the waypoint and if there isn’t a ray (It doesn’t hit anything) then you force the NPC forwards, making him fall down)
Like I said, this isn’t very clean but it’s the only solution I can think of rn given the circumstances