I am trying to make an enemy npc that roams my map and can open doors, and chase the player when they get close enough, it sort of works but its very inconsistent. Sometimes he just sits and looks at the player before eventually deciding to chase them, and a lot of times he wont roam to a navigation point (parts around the map that he randomly picks and moves to when he cant find a target so he looks like he is patrolling the map) because the door is 1 stud too low, and I made him unable to jump so he just doesn’t go to the path, leading to a long chain of failed paths meaning he will just sit still for a while. When the player sees the enemy most times he wont even react and when he finally does I run into the previously mentioned issue (it might be the map itself, or the agentparams). I am just wondering how I could make this code run more consistently and make it less messy?
local hum = script.Parent:WaitForChild("Humanoid")
local root = script.Parent:WaitForChild("HumanoidRootPart")
local head = script.Parent:WaitForChild("Head")
root:SetNetworkOwner(nil)
local chase = script.Parent:WaitForChild("Chase")
local chaseAnim = hum:LoadAnimation(chase)
chaseAnim.Priority = Enum.AnimationPriority.Action
local notice1 = script.Parent.UpperTorso.Notice1
local notice2 = script.Parent.UpperTorso.Notice2
local notice3 = script.Parent.UpperTorso.Notice3
local notice4 = script.Parent.UpperTorso.Notice4
local notice5 = script.Parent.UpperTorso.Notice5
local notice6 = script.Parent.UpperTorso.Notice6
local notice8 = script.Parent.UpperTorso.Taunt2
local notice9 = script.Parent.UpperTorso.Taunt3
local notice10 = script.Parent.UpperTorso.Taunt4
local notice11 = script.Parent.UpperTorso.Taunt5
local notice12 = script.Parent.UpperTorso.Taunt6
local notice13 = script.Parent.UpperTorso.Taunt7
local notice14 = script.Parent.UpperTorso.Taunt8
local notice15 = script.Parent.UpperTorso.Taunt9
local sounddb = false
local noticesounds = {notice1, notice2, notice3, notice4, notice5, notice6, notice8, notice9, notice10, notice11, notice12, notice13, notice14, notice15}
local visualizepoints = true
for _, door_part in pairs(workspace.Doors:GetDescendants()) do
if door_part:IsA("BasePart") or door_part:IsA("MeshPart") then
local modifier = Instance.new("PathfindingModifier")
modifier.ModifierId = "Door"
modifier.PassThrough = true
modifier.Parent = door_part
end
end
local agentparams = {
AgentRadius = 1.8,
AgentHeight = 4,
AgentCanJump = false,
Costs = {
Door = 0
}
}
function idle()
local navParts = workspace.NavParts:GetChildren()
local goal = navParts[math.random(1, #navParts)].Position
wait(math.random(1, 5))
local path = game:GetService("PathfindingService"):CreatePath(agentparams)
path:ComputeAsync(root.Position, goal)
local waypoints = path:GetWaypoints()
if visualizepoints == true then
for i, waypoint in pairs(waypoints) do
local part = Instance.new("Part")
part.Shape = "Ball"
part.Material = "Neon"
part.Size = Vector3.new(0.6, 0.6, 0.6)
part.Position = waypoint.Position + Vector3.new(0, 2, 0)
part.Anchored = true
part.CanCollide = false
part.Parent = workspace
game:GetService("Debris"):AddItem(part, 5)
end
end
if path.Status == Enum.PathStatus.Success then
for _, waypoint in ipairs(waypoints) do
hum:MoveTo(waypoint.Position)
local timeOut = hum.MoveToFinished:Wait()
if not timeOut then
print("I'm stuck :(")
idle()
end
end
else
print("Path failed :(")
wait(1)
locateTarget()
idle()
end
end
function locatePath(target)
local path = game:GetService("PathfindingService"):CreatePath(agentparams)
path:ComputeAsync(root.Position, target.Position)
local waypoints = path:GetWaypoints()
if visualizepoints == true then
for i, waypoint in pairs(waypoints) do
local part = Instance.new("Part")
part.Shape = "Ball"
part.Material = "Neon"
part.Size = Vector3.new(0.6, 0.6, 0.6)
part.Position = waypoint.Position + Vector3.new(0, 2, 0)
part.Anchored = true
part.CanCollide = false
part.Parent = workspace
game:GetService("Debris"):AddItem(part, 5)
end
end
if path.Status == Enum.PathStatus.Success then
for _, waypoint in ipairs(waypoints) do
hum:MoveTo(waypoint.Position)
local timeOut = hum.MoveToFinished:Wait(1)
if not timeOut then
print("Path took too long to compute :(")
locatePath(target)
break
end
if checksight(target) then
repeat
print("Moving directly to target!")
hum:MoveTo(target.Position)
attack(target)
wait(0.1)
if target == nil then
break
elseif target.Parent == nil then
break
end
until checksight(target) == false or hum.Health < 1 or target.Parent.Humanoid.Health < 1
break
end
if (root.Position - waypoints[1].Position).magnitude > 20 then
print("Target has moved! Time to generate a new path >:)")
locatePath(target)
break
end
end
end
end
function checksight(target)
local ray = Ray.new(root.Position, (target.Position - root.Position).Unit * 40)
local hit, position = workspace:FindPartOnRayWithIgnoreList(ray, {script.Parent})
if hit then
if hit:IsDescendantOf(target.Parent) and math.abs(hit.Position.Y - root.Position.Y) < 3 then
print("Target located!")
return true
end
end
return false
end
function locateTarget()
local dist = 40
local target = nil
local potentialTargets = {}
local seeTargets = {}
for i, v in ipairs(workspace:GetChildren()) do
local human = v:FindFirstChild("Humanoid")
local torso = v:FindFirstChild("Torso") or v:FindFirstChild("HumanoidRootPart")
if human and torso and v.Name ~= script.Parent.Name then
if (root.Position - torso.Position).magnitude < dist and human.Health > 0 then
table.insert(potentialTargets, torso)
end
end
end
if #potentialTargets > 0 then
for i, v in ipairs(potentialTargets) do
if checksight(v) then
table.insert(seeTargets, v)
elseif #seeTargets == 0 and (root.Position - v.Position).magnitude < dist then
target = v
dist = (root.Position - v.Position).magnitude
end
end
end
if #seeTargets > 0 then
dist = 40
for i, v in ipairs(seeTargets) do
if (root.Position - v.Position).magnitude < dist then
target = v
dist = (root.Position - v.Position).magnitude
end
end
end
if target then
noticesounds[math.random(1, #noticesounds)]:Play()
end
return target
end
function attack(target)
if (root.Position - target.Position).magnitude < 2 then
script.Parent.HumanoidRootPart.Kill:Play()
if target.Parent ~= nil then
target.Parent.Humanoid:TakeDamage(9999)
if chaseAnim.IsPlaying == true then
chaseAnim:Stop()
end
end
wait(0.4)
end
end
function main()
local target = locateTarget()
if target then
hum.WalkSpeed = 13
if chaseAnim.IsPlaying == false then
chaseAnim:Play()
end
locatePath(target)
else
hum.WalkSpeed = 8
if chaseAnim.IsPlaying == true then
chaseAnim:Stop()
end
idle()
end
end
while wait(0.1) do
if hum.Health < 1 then
break
end
main()
end