So I come back to pathfinding a year later to see if it is any less horrible than it was when I first had to learn it and well I must say to my disappointment nothing has changed. Monsters are still completely unable to detect if your character or waypoint is at an elevation
local stranger = script.Parent
local humanoid = stranger.Humanoid
local PathfindingService = game:GetService("PathfindingService")
local RunService = game:GetService("RunService")
stranger.PrimaryPart:SetNetworkOwner(nil)
local function canSeeTarget(target)
local origin = stranger.HumanoidRootPart.Position
local direction = (target.HumanoidRootPart.Position - stranger.HumanoidRootPart.Position).unit * 40
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {stranger}
local result = workspace:Raycast(origin, direction, raycastParams)
if result then
local hit = result.Instance
if hit and hit:IsDescendantOf(target) then
return true
end
end
return false
end
local function findTarget()
local players = game.Players:GetPlayers()
local maxDistance = 75
local nearestTarget = nil
for index, player in pairs(players) do
if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
local target = player.Character
local distance = (stranger.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude
if distance < maxDistance and canSeeTarget(target) then
nearestTarget = target
maxDistance = distance
end
end
end
return nearestTarget
end
local function getPath(destination)
local pathParams = {
["AgentHeight"] = 6,
["AgentRadius"] = 2,
["AgentCanJump"] = true
}
local path = PathfindingService:CreatePath()
path:ComputeAsync(stranger.HumanoidRootPart.Position, destination.Position, pathParams)
return path
end
local function attack(target)
local distance = (stranger.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude
if distance > 3 then
--refuses to detect when at elevation
humanoid:MoveTo(target.HumanoidRootPart.Position)
else
target.Humanoid.Health = 0
end
end
local function walkTo(destination)
local path = getPath(destination)
if path.Status == Enum.PathStatus.Success then
for index, waypoint in pairs(path:GetWaypoints()) do
local target = findTarget()
if target then
print("Target Found", target.Name)
attack(target)
return
else
print("Moving to", waypoint.Position)
humanoid:MoveTo(waypoint.Position)
humanoid.MoveToFinished:Wait()
end
end
else
print("Failed to find a path to the destination")
end
end
local function patrol()
local waypoints = workspace.Waypoints:GetChildren()
local randomNum = math.random(1, #waypoints)
walkTo(waypoints[randomNum])
end
while true do
patrol()
RunService.Heartbeat:Wait()
end
Yes it does. We can agree to disagree on the descriptive thing. It’s not hard to understand that the NPC can’t walk to waypoints or characters who are at an elevation on the Y axis…
So, :MoveTo is called then? The issue could be that you are calling :MoveTo too frequently and it is constantly starting and stopping in it’s tracks.
As you can see in the picture, definitely not the problem here. You can clearly see they are indeed stuck, despite the fact there is a safe path to take towards me.
You want them to jump? That has nothing to do with PathfindingService, because you aren’t pathfinding to the player. If you were, however, you could add
if Waypoint.Action == Enum.PathWaypointAction.Jump then
stranger.Humanoid.Jump = true
end
, to your path loop.
You need to use PathfindingService instead of :MoveTo, because otherwise you’re NPCs won’t know when they should jump. If you don’t want to use Pathfinding for attacking, then the best you can do is have them jump if the player is above them:
if target.HumanoidRootPart.Position.Y > stranger.HumanoidRootPart.Position.Y then
stranger.Humanoid.Jump = true
end
That doesn’t work either and I know it doesn’t because I had copied one that has the waypoint action jump in it and people like myself noticed it doesn’t work and it wouldn’t even try to jump not like it has a jumpheight problem it just doesn’t take the correct path + it doesn’t jump so uhh yeah it definitely is both a pathfinding AND a moving problem with npc’s
I can definitely dig up the code for the one that pathfinds and I can send it here since you insist it works but i’m telling you it doesn’t I tried it already
Okay yeah so this one is supposed to at least make the waypoints work and it doesn’t. The NPC does not jump. It does not pathfind correctly and gets stuck the exact same way the other one does.
local PathfindingService = game:GetService("PathfindingService")
local npc = script.Parent
local humanoid = npc:WaitForChild("Humanoid")
local hrp = npc:WaitForChild("HumanoidRootPart")
hrp:SetNetworkOwner(nil)
local walkAnim = humanoid.Animator:LoadAnimation(script.Walk)
local attackAnim = humanoid.Animator:LoadAnimation(script.Attack)
local pathParams = {
AgentHeight = 5,
AgentRadius = 3,
AgentCanJump = true,
}
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Blacklist
rayParams.FilterDescendantsInstances = {npc}
local lastPos
local animPlaying = false
local RANGE = 60
local DAMAGE = 30
local function canSeeTarget(target)
local orgin = hrp.Position
local direction = (target.HumanoidRootPart.Position - hrp.Position).Unit * RANGE
local ray = workspace:Raycast(orgin, direction, rayParams)
if ray and ray.Instance then
if ray.Instance:IsDescendantOf(target) then
return true
else
return false
end
else
return false
end
end
local function findTarget()
local players = game.Players:GetPlayers()
local maxDistance = RANGE
local nearestTarget
for i, player in pairs(players) do
if player.Character then
local target = player.Character
local distance = (hrp.Position - target.HumanoidRootPart.Position).Magnitude
if distance < maxDistance and canSeeTarget(target) then
nearestTarget = target
maxDistance = distance
end
end
end
return nearestTarget
end
local function getPath(destination)
local path = PathfindingService:CreatePath(pathParams)
path:ComputeAsync(hrp.Position, destination.Position)
return path
end
local function attack(target)
local distance = (hrp.Position - target.HumanoidRootPart.Position).Magnitude
local debounce = false
if distance > 5 then
humanoid:MoveTo(target.HumanoidRootPart.Position)
else
if debounce == false then
debounce = true
npc.Head.AttackSound:Play()
attackAnim:Play()
target.Humanoid.Health -= DAMAGE
task.wait(0.5)
debounce = false
end
end
end
local function walkTo(destination)
local path = getPath(destination)
if path.Status == Enum.PathStatus.Success then
for i, waypoint in pairs(path:GetWaypoints()) do
path.Blocked:Connect(function()
path:Destroy()
end)
if animPlaying == false then
walkAnim:Play()
animPlaying = true
end
attackAnim:Stop()
local target = findTarget()
if target and target.Humanoid.Health > 0 then
lastPos = target.HumanoidRootPart.Position
attack(target)
break
else
if waypoint.Action == Enum.PathWaypointAction.Jump then
humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
end
if lastPos then
humanoid:MoveTo(lastPos)
humanoid.MoveToFinished:Wait()
lastPos = nil
break
else
humanoid:MoveTo(waypoint.Position)
humanoid.MoveToFinished:Wait()
end
end
end
else
return
end
end
local function patrol()
local waypoints = workspace.Waypoints:GetChildren()
local randomNum = math.random(1, #waypoints)
walkTo(waypoints[randomNum])
end
while task.wait(0.2) do
patrol()
end
The code you showed does not ever try to jump in the attack function. It is not a problem with PathfindingService, because the attack function doesn’t use PathfindingService. You’ll need to use something like I showed if you are not going to use PathfindingService in your attack function (specifically the code I gave that compares the height of the Player and your NPC).
What don’t you understand? The attack function isn’t the problem here. I can stand completely away from it, let it never get called, and the part where it uses pathfindingservice does… not… work. In fact, I’d be wasting your time, my time, and everybody’s time to make it work when we can’t even get the waypoints part to work. Let’s fix that first, then it won’t be a waste of everyone’s time to fix the attack part.
There is no code to handle jumping in your path loop either, so even if PathfindingService tells you a Waypoint is a Jump waypoint, your code does not handle it. You can add a condition to your loop to fix that:
for _, waypoint in path:GetWaypoints() do
local target = findTarget()
if target then
print("Target Found", target.Name)
attack(target)
return
else
print("Moving to", waypoint.Position)
if waypoint.Action == Enum.PathWaypointAction.Jump then
print("Jumping!")
humanoid.Jump = true
end
humanoid:MoveTo(waypoint.Position)
humanoid.MoveToFinished:Wait()
end
end
Yes and I saw it try to jump and it failed miserably it didn’t jump high enough. That’s completely besides the point though. You see, the monsters are being totally stupid and not taking the correct path to the waypoint. Seeing them jump high is the equivalent of them being really dumb exploiters which 100% has a negative effect on the overall fun of the game.
I was just wondering why you used a MoveTo(target) instead of a WalkTo(target) since WalkTo does call the getPath and use pathfinding while MoveTo does not ( I think, I’m not too well versed in pathfinding )