Watch the video for it to make sense
As you can see the AI gets stuck on objects of certain height, in the script im aware that agent height is set to 0.01 however this is necessary as otherwise it will break and not be able to detect paths even when there is clearly a viable path available. So i need a way for it to not get stuck on those objects without the AgentHeight value being modified
script:
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.Pistol
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 RayParams = RaycastParams.new()
RayParams.FilterType = Enum.RaycastFilterType.Exclude
local pathParams = {
AgentHeight = 0.01,
AgentRadius = 0.01,
AgentCanJump = true,
}
local function getPath(destination)
if destination then
print('Get path fired')
local path = PathfindingService:CreatePath(pathParams)
path:ComputeAsync(RP.Position - Vector3.new(0,RP.Size.Y/2,0), 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
return true
else
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
distanceFromClosestTarget = distance
closestTarget = player
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)
if target.Character.Humanoid.Health > 0 then
if runAnimPlayingStatus == false then
walkAnim:Stop()
runAnim:Play()
runAnimPlayingStatus = true
walkAnimPlayingStatus = false
end
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)
local humTarget = getTarget()
local LineOfSight = lineOfSight(humTarget.Character.HumanoidRootPart)
LastSeenPos = humTarget.Character.HumanoidRootPart.Position
if (humTarget.Character.HumanoidRootPart.Position - RP.Position).Magnitude <= 20 and db == false then
if AI.Humanoid.Health > 0 and Gun:GetAttribute("Reloading") == false and humTarget.Character.Humanoid.Health > 0 then
runAnim:Stop()
shootTrack:Play()
db = true
shootModule.Shoot(target, Gun, AI)
runAnim:Play()
task.delay(1, function()
db = false
end)
patrol()
else
--patrol()
end
end
if humTarget and LineOfSight then
chaseTarget(humTarget)
else
if humTarget.Character.Humanoid.Health > 0 then
moveToLastSeen(LastSeenPos)
else
patrol()
end
end
else
local ChosenWapoint = math.random(1, #Waypoints)
moveTo(game.Workspace.Waypoints:FindFirstChild(ChosenWapoint).Position)
warn("Path Failed to compute falling back")
moveTo()
end
else
end
else
task.wait(1)
patrol()
end
end
function moveToLastSeen(location)
local path = getPath(location)
if path ~= "Fail" 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
else
end
end
function moveTo(target)
local humTarget = getTarget()
if humTarget ~= nil then
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
else
print("Hum target is nil")
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()
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")
--patrol()
else
lastPos = RP.Position
end
end
end
task.spawn(stuckDetect)
patrol()