As a better version to my older script found here this one actually has object permanence, basically the AI is smarter, If you are behind a wall it wont magically know you’re there and it has to maintain line of sigh with you while It’s chasing you. If it looses this line of sight it will go to the last location and go from there, feel free to use it however you want credit my if you’d like
task.wait(1)
local PathfindingService = game:GetService("PathfindingService")
local AI = script.Parent
local RP = script.Parent.HumanoidRootPart
local Hum = script.Parent.Humanoid
local Waypoints = game.Workspace:WaitForChild("Waypoints"):GetChildren()
RP:SetNetworkOwner(nil)
local attackAnim = Hum.Animator:LoadAnimation(script.Attack)
local walkAnim = Hum.Animator:LoadAnimation(script.Walk)
local runAnim = Hum.Animator:LoadAnimation(script.Run)
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Exclude
rayParams.FilterDescendantsInstances = {Hum}
local Damage = 25
local AttackRange = 5
walkAnim.Looped = true
runAnim.Looped = true
walkAnim:Play()
local LastSeenPos
local RayParams = RaycastParams.new()
RayParams.FilterType = Enum.RaycastFilterType.Exclude
local pathParams = {
AgentHeight = 5,
AgentRadius = 3,
AgentCanJump = true,
}
local function getPath(destination)
local path = PathfindingService:CreatePath(pathParams)
path:ComputeAsync(RP.Position, destination)
return path
end
function lineOfSight(target)
local rayDirection = target.Position - RP.Position
local rayParams = RaycastParams.new()
rayParams.FilterDescendantsInstances = {RP.Parent}
local RayResult = workspace:Raycast(RP.Position, rayDirection, rayParams)
if RayResult and RayResult.Instance then
if RayResult.Instance:IsDescendantOf(target.Parent) then
return true
else
return false
end
end
end
function getTarget()
local closestTarget
local distanceFromClosestTarget = 1000000000
for i, player in pairs(game.Players:GetChildren()) do
local distance = (player.Character.HumanoidRootPart.Position - RP.Position).Magnitude
if distance < distanceFromClosestTarget then
distanceFromClosestTarget = distance
closestTarget = player
end
end
return(closestTarget)
end
local db = false
local runAnimPlayingStatus = false
local walkAnimPlayingStatus = false
function chaseTarget(target)
print('chasing')
if runAnimPlayingStatus == false then
walkAnim:Stop()
runAnim:Play()
runAnimPlayingStatus = true
walkAnimPlayingStatus = false
end
local path
path = getPath(target.Character.HumanoidRootPart.Position)
local waypoints = path:GetWaypoints()
Hum:MoveTo(waypoints[2].Position)
local humTarget = getTarget()
local LineOfSight = lineOfSight(humTarget.Character.HumanoidRootPart)
LastSeenPos = humTarget.Character.HumanoidRootPart.Position
if (humTarget.Character.HumanoidRootPart.Position - RP.Position).Magnitude <= 5 and db == false then
db = true
attackAnim:Play()
humTarget.Character.Humanoid:TakeDamage(Damage)
attackAnim.Ended:Wait()
db = false
end
if humTarget and LineOfSight then
chaseTarget(humTarget)
else
moveToLastSeen(LastSeenPos)
end
end
function moveToLastSeen(location)
print('fired')
local path = getPath(location)
for i, waypoint in pairs(path:GetWaypoints()) do
local humTarget = getTarget()
local LineOfSight = lineOfSight(humTarget.Character.HumanoidRootPart)
if humTarget and LineOfSight then
path:Destroy()
chaseTarget(humTarget)
break
else
if walkAnimPlayingStatus == false then
walkAnim:Play()
walkAnimPlayingStatus = true
end
runAnimPlayingStatus = false
runAnim:Stop()
Hum:MoveTo(waypoint.Position)
Hum.MoveToFinished:Wait()
if i == #path:GetWaypoints() then
patrol()
end
end
end
end
function moveTo(target)
local humTarget = getTarget()
local LineOfSight = lineOfSight(humTarget.Character.HumanoidRootPart)
if humTarget and LineOfSight then
chaseTarget(humTarget)
else
local path = getPath(target)
if path.Status == Enum.PathStatus.Success then
for i, waypoint in pairs(path:GetWaypoints()) do
local humTarget = getTarget()
local LineOfSight = lineOfSight(humTarget.Character.HumanoidRootPart)
if humTarget and LineOfSight then
path:Destroy()
chaseTarget(humTarget)
break
else
if walkAnimPlayingStatus == false then
walkAnim:Play()
walkAnimPlayingStatus = true
end
runAnimPlayingStatus = false
runAnim:Stop()
Hum:MoveTo(waypoint.Position)
Hum.MoveToFinished:Wait()
if i == #path:GetWaypoints() then
patrol()
end
end
end
end
end
end
function patrol()
local ChosenWapoint = math.random(1, #Waypoints)
moveTo(game.Workspace.Waypoints:FindFirstChild(ChosenWapoint).Position)
end
patrol()
It isn’t perfect, with more then one player in the game it can have some strange behavior, for example if it losses sight of player A and goes to their last location it will completely ignore player B if it sees them on route to PlayersA last location, however it doesn’t outright break and I posted this so people can adapt it into their own games and maybe learn something from it so yeah.