So I have an NPC. And it wont stop doing this:
robloxapp-20220818-1722081.wmv (552.3 KB)
Here’s the script (Not mine)
--@ItsBasicallyDenis (contact me on Discord (Benis#0800) or on Twitter (@basicallyrbx) if you experience any issues!)
--This is a very customizable & easy-to-use pathfinding script, can be used for anything that follows players around!
-------- NOTE: If you changed any of the "IMPORTANT SETTINGS" and want to reset all to default, set resetSettingsToDefault to true!
----- Please don't change any parts of the code unless you know what you're doing!
-- DO NOT COPY THIS SCRIPT AND USE IT AS YOUR OWN!
--[[ Update log V1.01:
- Added stopNearPlayer, moveIfNoPath, waitBeforeStart, requiresSight and createWaypointParts settings;
- Significantly optimised the script by cleaning up threads & more;
- Bug fixes.
]]
--[[ Update log V1.02:
- Bug fixes;
- Signifcant Optimizations.
]]
local t = tick()
local pathFindingService = game:GetService("PathfindingService")
local players = game:GetService("Players")
-- Set-up variables (change them to your custom needs!):
local maxDistance = 100 -- Max distance that the NPC looks for targets in, if maxDistance is 150 and a player is 151 studs away, it will not target it!
local npc = script.Parent
local hum = npc:WaitForChild("Humanoid")
local hrp = npc:WaitForChild("HumanoidRootPart")
local req = require(script.ModuleScript)
-----------------
-- Character Variables:
local Health = 100 -- default is 100
local WalkSpeed = 16 -- default is 16
local JumpPower = 50 -- default is 50
-----------------
-- IMPORTANT SETTINGS!
local animateNPC = true -- Set to true to automatically animate the NPC (works with both R6 and R15 models!)
-----------------
local printNotifications = false -- Set to true if you want this script to print when the NPC moves, jumps, etc. (useful for debugging!)
-----------------
local stopNearPlayer = true -- Stops if closer than 3 studs of the target (might stun the NPC for a few seconds when changing directions fast!)
-----------------
local createWaypointParts = false -- Creates a semi-transparent green part for every waypoint (parts are destroyed after 2.5 seconds!)
-----------------
local requiresSight = true -- In order for the NPC to go towards the target, it needs to see it first (also automatically reduces maxDistance!)
-----------------
local moveIfNoPath = false -- Set to true to move 15 studs away if path.Status is not Success (might break movement if npc can't get to target!)
-----------------
local moveToWait = true -- Set to false if you don't want to wait for the MoveTo function to finish everytime (smoother npc movement but broken pathfinding!)
-----------------
local waitBeforeStart = false -- Wait 5-10 seconds before starting the AI (might prevent some start lag!)
-----------------
local resetSettingsToDefault = false -- Set to true to reset all settings to default once the NPC starts!
-----------------
-- Boring part:
-------------------------------------------------------------------------------------
function wander()
while true do
wait(math.random(5, 9))
if not req.following then
script.Parent.Humanoid:MoveTo(Vector3.new(math.random(-947, 947), 0, math.random(-1008, 1008)))
end
end
end
local function CanSeeTarget(target)
local ray = Ray.new(hrp.Position,(target.HumanoidRootPart.Position - hrp.Position).unit * 100) -- create the ray
local hit,pos = workspace:FindPartOnRay(ray,npc) -- find parts that the ray hit
if hit then -- if the ray hit a part then
if hit:IsDescendantOf(target) then -- if the part is part of the target's character then
return true -- return true
end
end
return false -- if no target was found, return false
end
local function FindTarget()
local target
local maxDis = maxDistance
for i, plr in pairs(players:GetPlayers()) do -- loop through the current players
if plr.Character then -- if the current player has a character then
local distance = (hrp.Position - plr.Character.HumanoidRootPart.Position).Magnitude -- check the distance between npc and player
if requiresSight then
if distance <= maxDis and CanSeeTarget(plr.Character) then
target = plr.Character
maxDis = distance
else
wander()
end
else
if distance <= maxDis then -- if the distance is less than the maxDistance variable then
target = plr.Character -- target acquired
maxDis = distance -- set the new maxDis to the current distance, so if a player is closer than this one, we choose him instead
else
wander()
end
end
end
end
return target -- return the target
end
if resetSettingsToDefault then -- if resetSettingsToDefault is set to true, we reset all settings to default
animateNPC = true
printNotifications = false
stopNearPlayer = false
requiresSight = false
moveToWait = true
createWaypointParts = false
moveIfNoPath = false
waitBeforeStart = false
end
if animateNPC then
local anim
for i, v in pairs(npc:GetChildren()) do -- loop through all of the npc's children
if v.Name == "Animate" or v.Name == "Animation" and v:IsA("BaseScript") then -- if we find another "Animate" script then
v:Destroy() -- we destroy it
end
end
if hum.RigType == Enum.RigType.R15 then -- if the character is R15 then
anim = script.AnimateR15 -- give it the R15 animation script
script.AnimateR6:Destroy()
else -- if the character is R6 then
anim = script.AnimateR6 -- give it the R6 animation script
script.AnimateR15:Destroy()
end
anim.Name = "Animate" -- rename the script to "Animate"
anim.Parent = npc -- parent the script to the NPC
anim.Disabled = false -- enable the script
end
-----------------
hum.UseJumpPower = true
hum.JumpPower = JumpPower
hum.WalkSpeed = WalkSpeed
hum.MaxHealth = Health
hum.Health = Health
npc.PrimaryPart = hrp
npc.PrimaryPart:SetNetworkOwner(nil) -- Set the PrimaryPart's Network Owner to the Server (prevents lag!)
-----------------
if waitBeforeStart then task.wait(math.random(5,10)) end
local oldPath
coroutine.resume(coroutine.create(function()
game:GetService("RunService").Heartbeat:Connect(function()
local target = FindTarget() -- find the target
if target then -- if there is a target, proceed with following it
if target:FindFirstChild("HumanoidRootPart") then target = target.HumanoidRootPart end
if printNotifications then print("Found target: "..target.Parent.Name) end
local path = pathFindingService:CreatePath() -- create a new path
path:ComputeAsync(hrp.Position,target.Position) -- compute the best path from the NPC to the TARGET
if oldPath then -- if there's an old path, we destroy it and we replace it with the new one
if path ~= oldPath then
oldPath:Destroy()
oldPath = path
if printNotifications then print("Destroyed old path and replaced it with a new one!") end
end
else
oldPath = path -- if this is the first ever path, we set the old path to the current one
end
local waypoints = path:GetWaypoints() -- we get the path's waypoints
local cor
if path and waypoints then -- if we have waypoints then
if path.Status == Enum.PathStatus.Success then -- if the path is a success then
for i, waypoint in pairs(waypoints) do -- loop through the waypoints
cor = coroutine.resume(coroutine.create(function() -- create a seperate thread for each waypoint
-----------------
if createWaypointParts then -- if createWaypointParts is set to true, then we create a part for each waypoint!
local part = Instance.new("Part")
part.Anchored = true
part.CanCollide = false
part.Color = Color3.fromRGB(119, 255, 8)
part.Transparency = .75
part.Position = waypoint.Position
part.Parent = workspace
task.delay(2.5,function()
part:Destroy()
end)
end
-----------------
if waypoint.Action == Enum.PathWaypointAction.Jump then -- if the waypoint requires the NPC to jump
if printNotifications then print("Jumped!") end
hum.Jump = true -- jump
end
if waypoint.Action == Enum.PathWaypointAction.Walk then -- if the waypoint requires the NPC to walk
hum:ChangeState(Enum.HumanoidStateType.Running) -- walk
end
if printNotifications then print("Walking to "..tostring(waypoint.Position).."!") end
if (hrp.Position - target.Position).Magnitude <= 3 and stopNearPlayer then -- if stopNearPlayer is on, then stop the NPC
hum:MoveTo(hrp.Position)
else -- else, move the NPC normally towards the target
hum:MoveTo(waypoint.Position)
end
if moveToWait then hum.MoveToFinished:Wait() end
cor = nil -- clean up the thread
end))
end
else -- if path was not a success, and moveIfNoPath is set to true, then we move the NPC 15 studs away
if moveIfNoPath then
if printNotifications then print("Path was not succsessful, moving 15 studs away!") end
hum:MoveTo(target.Position - (hrp.CFrame.LookVector * 15))
end
end
end
end
end)
end))
if printNotifications then print("Benis' Pathfinding AI script has successfully loaded in "..tostring(tick() - t).." seconds!") end
So it wanders when it cant see the player by the distance. But instead, its just spinning around…
this is the wander part if you don’t want to find it:
function wander()
while true do
wait(math.random(5, 9))
if not req.following then
script.Parent.Humanoid:MoveTo(Vector3.new(math.random(-947, 947), 0, math.random(-1008, 1008)))
end
end
end