Please watch the video
As you can see there is a door, the door is just a model which consists of two parts, collision groups are set up as such that the ai cant even collide with the door but still it sometimes just cannot pathfind over the door when its laying on the ground. Ignore the terrible voice lines I’ll have good ones eventually, anyways the green/red head of the ai represents whether or not they have a line of sight on me, if they do its green otherwise its red.
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 RayParams = RaycastParams.new()
RayParams.FilterType = Enum.RaycastFilterType.Exclude
local pathParams = {
AgentHeight = 3,
AgentRadius = 1,
AgentCanJump = true,
WaypointSpacing = 2.5,
}
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
chaseTarget(humTarget)
return
else
local path = getPath(target)
if path.Status == Enum.PathStatus.Success then
local Waypoints = path:GetWaypoints()
for i, waypoint in pairs(Waypoints) do
if i == #path: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")
--RP.Position += RP.CFrame.LookVector * 2
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()