So I’m making an enemy NPC that finds the nearest player and gets to them while avoiding obstacles and such. I made some code but for some reason it’s not working and the dummy just stands still and doesn’t move at all, theres no prints or errors in the output either.
local pathfindingService = game:GetService("PathfindingService")
local StartingPoint = script.Parent.PrimaryPart
local humanoid = script.Parent.Humanoid
local root = script.Parent.HumanoidRootPart
local smallest, enemy = math.huge, nil
local Path:Path
Path = pathfindingService:CreatePath()
for _, otherCharacter in pairs(workspace:GetChildren()) do
if otherCharacter:FindFirstChild("HumanoidRootPart") and otherCharacter ~= script.Parent then
local distance = (root.Position - otherCharacter.HumanoidRootPart.Position).Magnitude
if distance < 60 and distance < smallest then
smallest = distance
enemy = otherCharacter
end
end
end
local function computePath(startGoal:Vector3, endGoal:Vector3)
local RetriesLeft = 20--20 retries
local RetryInterval = 3--delay 3 seconds each time it fails
for i = RetriesLeft, 1, -1 do
Path:ComputeAsync(startGoal,endGoal)
if Path.Status == Enum.PathStatus.Success then
return Path
else
warn("Path failed to compute, retrying...")
task.wait(RetryInterval)
end
end
error("Path failed to compute")--this will run if the loop is finished or all the retries failed
end
local function WalkHumanoid(humanoid:Humanoid, startGoal:Vector3, endGoal:Vector3)
local Path = computePath(startGoal,endGoal)
--setting up path properties
local WayPoints = Path:GetWaypoints()
local CurrectWayPointIndex = 2 --the point to go after the first point as the first waypoint is just the start position
--setup connections
local MoveToFinishConnection:RBXScriptConnection
local PathBlockedConnection:RBXScriptConnection
PathBlockedConnection = Path.Blocked:Connect(function(blockedWaypointIndex)
warn(blockedWaypointIndex,CurrectWayPointIndex)
if blockedWaypointIndex >= CurrectWayPointIndex then--a waypoint ahead of us is blocked! recompute the path
--disconnect the events
MoveToFinishConnection:Disconnect()
PathBlockedConnection:Disconnect()
humanoid.WalkToPoint = StartingPoint.Position --make our humanoid stop walking at its current position and cancel it's movement to the next waypoint
WalkHumanoid(humanoid,StartingPoint.Position,endGoal)
end
end)
MoveToFinishConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached then--if the humanoid reach the waypoint within 8 seconds
if CurrectWayPointIndex < #WayPoints then--if we have not cycle through the last waypoint
CurrectWayPointIndex += 1--we increase the index by 1 so that the humanoid moves to the next waypoint
humanoid:MoveTo(WayPoints[CurrectWayPointIndex].Position)--and the same thing
if WayPoints[CurrectWayPointIndex].Action == Enum.PathWaypointAction.Jump then
humanoid.Jump = true
end
else
print("Path reached!")
MoveToFinishConnection:Disconnect()--disconnect the unnecessary event to avoid memory leaks
end
else--failed to reach waypoint within 8 seconds, the dummy probably is stuck, so let's recompute it!
MoveToFinishConnection:Disconnect()
WalkHumanoid(humanoid,StartingPoint.Position,endGoal)--we are changing our start goal and replacing it to the current position of our dummy instead of reusing the old one
end
end)
--Visualize waypoints
for _, point:PathWaypoint in ipairs(WayPoints) do
local part = Instance.new("Part")
part.Anchored = true
part.CanCollide = false
part.Material = Enum.Material.Neon
part.Color = Color3.fromRGB(255,255,255)
part.Position = point.Position--PathWaypoint objects have a property named Position which describes their position in the form of Vector3.
part.Parent = workspace
end
-- make humanoid walk
humanoid:MoveTo(WayPoints[CurrectWayPointIndex].Position)
if WayPoints[CurrectWayPointIndex].Action == Enum.PathWaypointAction.Jump then
humanoid.Jump = true
end
end
WalkHumanoid(humanoid, StartingPoint.Position, enemy.HumanoidRootPart.Position)
The script only checks the players once. The NPC will not follow, even if a character spawns later. Instead, turn the player locating bit into its own function:
function getNearestEnemy()
local enemyFound = false
for _, otherCharacter in pairs(workspace:GetChildren()) do
if otherCharacter:FindFirstChild("HumanoidRootPart") and otherCharacter ~= script.Parent then
local distance = (root.Position - otherCharacter.HumanoidRootPart.Position).Magnitude
if distance < 60 and distance < smallest then
smallest = distance
enemy = otherCharacter
enemyFound = true
end
end
end
if not enemyFound then enemy = nil end
end
Then, in a loop, run the getNearestEnemy, check for an enemy, and if an enemy is present, run WalkHumanoid:
while true do
task.wait(1)
getNearestEnemy()
if enemy then
WalkHumanoid(humanoid, StartingPoint.Position, enemy.HumanoidRootPart.Position)
end
end
Hey, thanks for your help but for some reason theres an issue, it goes to you but then randomly stops and takes a while to start following you again, heres some footage:
Ok so the MoveToFinishConnection variable is only in the HumanoidMove function so it’s unknown, should I just move it to the start or will that maybe affect something?
so remove MoveToFinishConnection:Disconnect() and just put WalkHumanoid(humanoid, StartingPoint.Position, enemy.HumanoidRootPart.Position) after print(“Path reached!”)
It still seems to have the same problem and just crashed my game for some reason, this is my code incase I didn’t do your edit properly:
local pathfindingService = game:GetService("PathfindingService")
local StartingPoint = script.Parent.PrimaryPart
local humanoid = script.Parent.Humanoid
local root = script.Parent.HumanoidRootPart
local smallest, enemy = math.huge, nil
local Path:Path
Path = pathfindingService:CreatePath()
function getNearestEnemy()
local enemyFound = false
for _, otherCharacter in pairs(workspace:GetChildren()) do
if otherCharacter:FindFirstChild("HumanoidRootPart") and otherCharacter ~= script.Parent then
local distance = (root.Position - otherCharacter.HumanoidRootPart.Position).Magnitude
if distance < 60 and distance < smallest then
smallest = distance
enemy = otherCharacter
enemyFound = true
end
end
end
if not enemyFound then enemy = nil end
end
local function computePath(startGoal:Vector3, endGoal:Vector3)
local RetriesLeft = 20--20 retries
local RetryInterval = 3--delay 3 seconds each time it fails
for i = RetriesLeft, 1, -1 do
Path:ComputeAsync(startGoal,endGoal)
if Path.Status == Enum.PathStatus.Success then
return Path
else
warn("Path failed to compute, retrying...")
task.wait(RetryInterval)
end
end
error("Path failed to compute")--this will run if the loop is finished or all the retries failed
end
local function WalkHumanoid(humanoid:Humanoid, startGoal:Vector3, endGoal:Vector3)
local Path = computePath(startGoal,endGoal)
--setting up path properties
local WayPoints = Path:GetWaypoints()
local CurrectWayPointIndex = 2 --the point to go after the first point as the first waypoint is just the start position
--setup connections
local MoveToFinishConnection:RBXScriptConnection
local PathBlockedConnection:RBXScriptConnection
PathBlockedConnection = Path.Blocked:Connect(function(blockedWaypointIndex)
warn(blockedWaypointIndex,CurrectWayPointIndex)
if blockedWaypointIndex >= CurrectWayPointIndex then--a waypoint ahead of us is blocked! recompute the path
--disconnect the events
MoveToFinishConnection:Disconnect()
PathBlockedConnection:Disconnect()
humanoid.WalkToPoint = StartingPoint.Position --make our humanoid stop walking at its current position and cancel it's movement to the next waypoint
WalkHumanoid(humanoid,StartingPoint.Position,endGoal)
end
end)
MoveToFinishConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached then--if the humanoid reach the waypoint within 8 seconds
if CurrectWayPointIndex < #WayPoints then--if we have not cycle through the last waypoint
CurrectWayPointIndex += 1--we increase the index by 1 so that the humanoid moves to the next waypoint
humanoid:MoveTo(WayPoints[CurrectWayPointIndex].Position)--and the same thing
if WayPoints[CurrectWayPointIndex].Action == Enum.PathWaypointAction.Jump then
humanoid.Jump = true
end
else
print("Path reached!")
WalkHumanoid(humanoid, StartingPoint.Position, enemy.HumanoidRootPart.Position)
end
else--failed to reach waypoint within 8 seconds, the dummy probably is stuck, so let's recompute it!
MoveToFinishConnection:Disconnect()
WalkHumanoid(humanoid,StartingPoint.Position,endGoal)--we are changing our start goal and replacing it to the current position of our dummy instead of reusing the old one
end
end)
--Visualize waypoints
for _, point:PathWaypoint in ipairs(WayPoints) do
--[[local part = Instance.new("Part")
part.Anchored = true
part.CanCollide = false
part.Material = Enum.Material.Neon
part.Color = Color3.fromRGB(255,255,255)
part.Position = point.Position--PathWaypoint objects have a property named Position which describes their position in the form of Vector3.
part.Parent = workspace--]]
end
-- make humanoid walk
humanoid:MoveTo(WayPoints[CurrectWayPointIndex].Position)
if WayPoints[CurrectWayPointIndex].Action == Enum.PathWaypointAction.Jump then
humanoid.Jump = true
end
end
while true do
task.wait(1)
getNearestEnemy()
if enemy then
WalkHumanoid(humanoid, StartingPoint.Position, enemy.HumanoidRootPart.Position)
end
end
local pathfindingService = game:GetService("PathfindingService")
local StartingPoint = script.Parent.PrimaryPart
local humanoid = script.Parent.Humanoid
local root = script.Parent.HumanoidRootPart
local smallest, enemy = math.huge, nil
local Path:Path
Path = pathfindingService:CreatePath()
function getNearestEnemy()
local enemyFound = false
for _, otherCharacter in pairs(workspace:GetChildren()) do
if otherCharacter:FindFirstChild("HumanoidRootPart") and otherCharacter ~= script.Parent then
local distance = (root.Position - otherCharacter.HumanoidRootPart.Position).Magnitude
if distance < 60 and distance < smallest then
smallest = distance
enemy = otherCharacter
enemyFound = true
end
end
end
if not enemyFound then enemy = nil end
end
local function computePath(startGoal:Vector3, endGoal:Vector3)
local RetriesLeft = 20--20 retries
local RetryInterval = 3--delay 3 seconds each time it fails
for i = RetriesLeft, 1, -1 do
Path:ComputeAsync(startGoal,endGoal)
if Path.Status == Enum.PathStatus.Success then
return Path
else
warn("Path failed to compute, retrying...")
task.wait(RetryInterval)
end
end
print("Path failed to compute")--this will run if the loop is finished or all the retries failed
end
local function WalkHumanoid(humanoid:Humanoid, startGoal:Vector3, endGoal:Vector3)
local Path = computePath(startGoal,endGoal)
--setting up path properties
local WayPoints = Path:GetWaypoints()
local CurrectWayPointIndex = 2 --the point to go after the first point as the first waypoint is just the start position
--setup connections
local MoveToFinishConnection:RBXScriptConnection
local PathBlockedConnection:RBXScriptConnection
PathBlockedConnection = Path.Blocked:Connect(function(blockedWaypointIndex)
warn(blockedWaypointIndex,CurrectWayPointIndex)
if blockedWaypointIndex >= CurrectWayPointIndex then--a waypoint ahead of us is blocked! recompute the path
--disconnect the events
MoveToFinishConnection:Disconnect()
PathBlockedConnection:Disconnect()
humanoid.WalkToPoint = StartingPoint.Position --make our humanoid stop walking at its current position and cancel it's movement to the next waypoint
WalkHumanoid(humanoid,StartingPoint.Position,endGoal)
end
end)
MoveToFinishConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached then--if the humanoid reach the waypoint within 8 seconds
if CurrectWayPointIndex < #WayPoints then--if we have not cycle through the last waypoint
CurrectWayPointIndex += 1--we increase the index by 1 so that the humanoid moves to the next waypoint
humanoid:MoveTo(WayPoints[CurrectWayPointIndex].Position)--and the same thing
if WayPoints[CurrectWayPointIndex].Action == Enum.PathWaypointAction.Jump then
humanoid.Jump = true
end
else
print("Path reached!")
MoveToFinishConnection:Disconnect()
getNearestEnemy()
end
else--failed to reach waypoint within 8 seconds, the dummy probably is stuck, so let's recompute it!
MoveToFinishConnection:Disconnect()
WalkHumanoid(humanoid,StartingPoint.Position,endGoal)--we are changing our start goal and replacing it to the current position of our dummy instead of reusing the old one
end
end)
--Visualize waypoints
for _, point:PathWaypoint in ipairs(WayPoints) do
--[[local part = Instance.new("Part")
part.Anchored = true
part.CanCollide = false
part.Material = Enum.Material.Neon
part.Color = Color3.fromRGB(255,255,255)
part.Position = point.Position--PathWaypoint objects have a property named Position which describes their position in the form of Vector3.
part.Parent = workspace--]]
end
-- make humanoid walk
humanoid:MoveTo(WayPoints[CurrectWayPointIndex].Position)
if WayPoints[CurrectWayPointIndex].Action == Enum.PathWaypointAction.Jump then
humanoid.Jump = true
end
end
while true do
task.wait(0.5)
getNearestEnemy()
if enemy then
WalkHumanoid(humanoid, StartingPoint.Position, enemy.HumanoidRootPart.Position)
end
end
Hm, it still has the same issue but now I see it prints “Path reached!” multiple times after reaching me and then it just starts bugging and stops, only to kinda twitch every now and then.
local pathfindingService = game:GetService("PathfindingService")
local StartingPoint = script.Parent.PrimaryPart
local humanoid = script.Parent.Humanoid
local root = script.Parent.HumanoidRootPart
local smallest, enemy = math.huge, nil
local Path:Path
Path = pathfindingService:CreatePath()
function getNearestEnemy()
smallest = math.huge --Reset Smallest
local enemyFound = false
for _, otherCharacter in pairs(workspace:GetChildren()) do
if otherCharacter:FindFirstChild("HumanoidRootPart") and otherCharacter ~= script.Parent then
local distance = (root.Position - otherCharacter.HumanoidRootPart.Position).Magnitude
if distance < 60 and distance < smallest then
smallest = distance
enemy = otherCharacter
enemyFound = true
end
end
end
if not enemyFound then enemy = nil end
end
local function WalkHumanoid(humanoid:Humanoid, startGoal:Vector3, endGoal:Vector3)
repeat Path:ComputeAsync(startGoal,endGoal) until Path.Status == Enum.PathStatus.Success
local WayPoints = Path:GetWaypoints()
local CurrectWayPointIndex = 2 --the point to go after the first point as the first waypoint is just the start position
local MoveToFinishConnection:RBXScriptConnection
local PathBlockedConnection:RBXScriptConnection
PathBlockedConnection = Path.Blocked:Connect(function(blockedWaypointIndex)
warn(blockedWaypointIndex,CurrectWayPointIndex)
if blockedWaypointIndex >= CurrectWayPointIndex then--a waypoint ahead of us is blocked! recompute the path
--disconnect the events
MoveToFinishConnection:Disconnect()
PathBlockedConnection:Disconnect()
humanoid.WalkToPoint = StartingPoint.Position --make our humanoid stop walking at its current position and cancel it's movement to the next waypoint
WalkHumanoid(humanoid,StartingPoint.Position,endGoal)
end
end)
MoveToFinishConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached then--if the humanoid reach the waypoint within 8 seconds
if CurrectWayPointIndex < #WayPoints then--if we have not cycle through the last waypoint
CurrectWayPointIndex += 1--we increase the index by 1 so that the humanoid moves to the next waypoint
humanoid:MoveTo(WayPoints[CurrectWayPointIndex].Position)--and the same thing
if WayPoints[CurrectWayPointIndex].Action == Enum.PathWaypointAction.Jump then
humanoid.Jump = true
end
else
print("Path reached!")
MoveToFinishConnection:Disconnect()
PathBlockedConnection:Disconnect()
end
else--failed to reach waypoint within 8 seconds, the dummy probably is stuck, so let's recompute it!
MoveToFinishConnection:Disconnect()
PathBlockedConnection:Disconnect()
end
end)
humanoid:MoveTo(WayPoints[CurrectWayPointIndex].Position)
if WayPoints[CurrectWayPointIndex].Action == Enum.PathWaypointAction.Jump then
humanoid.Jump = true
end
end
while true do
task.wait(0.5)
getNearestEnemy()
if enemy then
WalkHumanoid(humanoid, StartingPoint.Position, enemy.HumanoidRootPart.Position)
end
end
Oh wow! That worked well now the only problem is that it’s kinda choppy but I can just make a new topic for that. Thank you so much man for helping me this whole time.