Watch the video:
Here is the code:
task.wait(5)
local shootModule = require(game.ServerScriptService.NPCShoot)
local PathfindingService = game:GetService("PathfindingService")
local AI = script.Parent
local RP = script.Parent.HumanoidRootPart
local Hum = script.Parent.Humanoid
local Gun = script.Parent:FindFirstChildOfClass("Tool")
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 = 15
local shootTrack = AI.Humanoid.Animator:LoadAnimation(game.ReplicatedStorage.Animations.NPCPistolShoot)
walkAnim.Looped = true
runAnim.Looped = true
walkAnim:Play()
local LastSeenPos
local patrolPath
local RayParams = RaycastParams.new()
RayParams.FilterType = Enum.RaycastFilterType.Exclude
local pathParams = {
AgentHeight = 1,
AgentRadius = 1,
AgentCanJump = false,
Costs = {}
}
for i, v in pairs(game.Workspace:WaitForChild("AvoidPathing"):GetChildren()) do
pathParams.Costs[v] = math.huge
end
local function getPath(destination)
if typeof(destination) ~= "Vector3" then
warn("Destination variable was not a vector3")
end
if destination then
local path = PathfindingService:CreatePath(pathParams)
path:ComputeAsync(RP.Position , destination)
return path
else
warn("Pathfinding fail")
return "Fail"
end
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)
-- Visualization
local rayPart = Instance.new("Part")
rayPart.Size = Vector3.new(0.2, 0.2, rayDirection.Magnitude)
rayPart.CFrame = CFrame.new(RP.Position, target.Position) * CFrame.new(0, 0, -rayPart.Size.Z / 2)
rayPart.Anchored = true
rayPart.CanCollide = false
rayPart.Color = Color3.new(1, 0, 0) -- Red color for the ray
rayPart.Transparency = 0.5
rayPart.Parent = RP.Parent
rayPart.CanQuery = false
rayPart.CanTouch = false
-- Destroy the visualization after a short time
game:GetService("Debris"):AddItem(rayPart, 0.2)
if RayResult and RayResult.Instance then
if RayResult.Instance:IsDescendantOf(target.Parent) then
-- print("line of sight true")
script.Parent["Body Colors"].HeadColor3 = Color3.new(0.192157, 1, 0.0666667)
return true
else
-- print("line of sight false")
script.Parent["Body Colors"].HeadColor3 = Color3.new(1, 0, 0.0156863)
return false
end
end
end
function getTarget()
local closestTarget = nil
local distanceFromClosestTarget = 1000000000
for i, player in pairs(game.Players:GetChildren()) do
local distance = (player.Character.HumanoidRootPart.Position - RP.Position).Magnitude
if distance < distanceFromClosestTarget and player.Character.Humanoid.Health > 0 then
if lineOfSight(player.Character.HumanoidRootPart) then
if player.Character.Humanoid.Health > 0 then
distanceFromClosestTarget = distance
closestTarget = player
end
end
end
end
if closestTarget ~= nil then
return(closestTarget)
else
--task.wait(5)
-- patrol()
end
end
local db = false
local runAnimPlayingStatus = false
local walkAnimPlayingStatus = false
function chaseTarget(target)
local path
path = getPath(target.Character.HumanoidRootPart.Position)
if path ~= "Fail" then
local Waypoints = path:GetWaypoints()
if Waypoints[2] then
Hum:MoveTo(Waypoints[2].Position)
task.spawn(shoot)
if lineOfSight(target.Character.HumanoidRootPart) then
patrol()
else
moveToLastSeen(target.Character.HumanoidRootPart.Position)
end
else
patrol()
return
end
end
end
function moveToLastSeen(location)
local path = getPath(location)
if path ~= "Fail" then
for i, waypoint in pairs(path:GetWaypoints()) do
local humTarget = getTarget()
if humTarget then
patrol()
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()
break
end
end
end
else
patrol()
end
end
function moveTo(target)
local humTarget = getTarget()
if humTarget then
if patrolPath then
patrolPath:Destroy()
end
chaseTarget(humTarget)
return
else
patrolPath = getPath(target)
if patrolPath.Status == Enum.PathStatus.Success then
local Waypoints = patrolPath:GetWaypoints()
for i, waypoint in pairs(Waypoints) do
if i == #patrolPath:GetWaypoints() then
patrol()
break
end
local humTarget = getTarget()
if humTarget then
chaseTarget(humTarget)
break
else
Hum:MoveTo(waypoint.Position)
Hum.MoveToFinished:Wait()
end
end
end
end
end
function patrol()
local ChosenWapoint = math.random(1, #Waypoints)
moveTo(game.Workspace.Waypoints:FindFirstChild(ChosenWapoint).Position)
end
script.Parent.Humanoid.Died:Connect(function()
script:Destroy()
AI.Head.HeadUI:Destroy()
Hum.HealthDisplayDistance = 0
end)
local lastPos = RP.Position
function stuckDetect()
while task.wait(1) do
if (RP.Position - lastPos).Magnitude < 1 and Gun:GetAttribute("Reloading") == false then
warn("AI got stuck falling back")
if patrolPath then
patrolPath:Destroy()
patrol()
end
else
lastPos = RP.Position
end
end
end
function shoot()
local target = getTarget()
if target and (target.Character.HumanoidRootPart.Position - RP.Position).Magnitude <= 20 and db == false then
db = true
shootTrack:Play()
shootModule.Shoot(target,Gun,AI)
task.wait(Gun:GetAttribute("FireRate"))
db = false
end
end
task.spawn(stuckDetect)
patrol()
as you can see in the video the AI goes over models despite having costs of parts surrounding the models set to math.huge which should make it avoid it, I don’t understand why it does this and it doing so breaks the ai completely and in turn the game