Recently I’ve been working on a backrooms themed game where the exit of each level teleports you to the next one by changing the primary part’s CFrame via :SetPrimaryPartCFrame(). Problem is, after teleporting to any level with NPCs that are supposed to chase you, these just simply ignore you and continue wandering around. I’ve tried changing the AI, searching on the dev forum, yet nothing seems to work.
Currently the NPCs use a slightly modified version of Y3llow Mustang’s Zombie AI, which I’ll leave here:
Code
local myHuman = script.Parent:WaitForChild("Humanoid")
local myRoot = script.Parent:WaitForChild("HumanoidRootPart")
local head = script.Parent:WaitForChild("Head")
local lowerTorso = script.Parent:WaitForChild("LowerTorso")
local grab = script.Parent:WaitForChild("Grab")
local grabAnim = myHuman:LoadAnimation(grab)
grabAnim.Priority = Enum.AnimationPriority.Action
local grabSound = head:WaitForChild("Attack")
local screamSound = head:WaitForChild("Scream")
local moanSound = head:WaitForChild("Moan")
local clone = script.Parent:Clone()
function walkRandomly()
local xRand = math.random(-20,20)
local zRand = math.random(-20,20)
local goal = myRoot.Position + Vector3.new(xRand,0,zRand)
local path = game:GetService("PathfindingService"):CreatePath()
path:ComputeAsync(myRoot.Position, goal)
local waypoints = path:GetWaypoints()
if math.random(20) == 1 then
moanSound:Play()
end
if path.Status == Enum.PathStatus.Success then
for _, waypoint in pairs(waypoints) do
if waypoint.Action == Enum.PathWaypointAction.Jump then
myHuman.Jump = true
end
myHuman:MoveTo(waypoint.Position)
local timeOut = myHuman.MoveToFinished:Wait(1)
if not timeOut then
myHuman.Jump = true
walkRandomly()
end
end
else
wait(1)
walkRandomly()
end
end
function findPath(target)
local path = game:GetService("PathfindingService"):CreatePath()
path:ComputeAsync(myRoot.Position,target.Position)
local waypoints = path:GetWaypoints()
if path.Status == Enum.PathStatus.Success then
for _, waypoint in pairs(waypoints) do
if waypoint.Action == Enum.PathWaypointAction.Jump then
myHuman.Jump = true
end
myHuman:MoveTo(waypoint.Position)
local timeOut = myHuman.MoveToFinished:Wait(1)
if not timeOut then
myHuman.Jump = true
findPath(target)
break
end
if checkSight(target) then
repeat
myHuman: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 myHuman.Health < 1 or target.Parent.Humanoid.Health < 1
break
end
if (myRoot.Position - waypoints[1].Position).magnitude > 20 then
findPath(target)
break
end
end
end
end
function checkSight(target)
local ray = Ray.new(myRoot.Position, (target.Position - myRoot.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 - myRoot.Position.Y) < 3 then
return true
end
end
return false
end
function findTarget()
local dist = 50
local target = nil
local potentialTargets = {}
local seeTargets = {}
for i,v in pairs(workspace:GetChildren()) do
local human = v:FindFirstChildOfClass("Humanoid")
local torso = v:FindFirstChild("UpperTorso")
if human and torso and v.Name ~= script.Parent.Name then
if (myRoot.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 pairs(potentialTargets) do
if checkSight(v) then
table.insert(seeTargets, v)
elseif #seeTargets == 0 and (myRoot.Position - v.Position).magnitude < dist then
target = v
dist = (myRoot.Position - v.Position).magnitude
end
end
end
if #seeTargets > 0 then
dist = 200
for i,v in pairs(seeTargets) do
if (myRoot.Position - v.Position).magnitude < dist then
target = v
dist = (myRoot.Position - v.Position).magnitude
end
end
end
if target then
if math.random(20) == 1 then
screamSound:Play()
end
end
return target
end
function attack(target)
if (myRoot.Position - target.Position).magnitude < 5 then
grabAnim:Play()
grabSound:Play()
if target.Parent ~= nil then
target.Parent.Humanoid:TakeDamage(25)
end
wait(0.4)
end
end
function died()
wait(5)
clone.Parent = workspace
game:GetService("Debris"):AddItem(script.Parent,0.1)
end
myHuman.Died:Connect(died)
lowerTorso.Touched:Connect(function(obj)
if not obj.Parent:FindFirstChild("Humanoid") then
myHuman.Jump = true
end
end)
function main()
local target = findTarget()
print(target)
if target then
myHuman.WalkSpeed = 10
findPath(target)
else
myHuman.WalkSpeed = 7
walkRandomly()
end
end
spawn(function()
while wait() do
if myHuman.Health < 1 then
break
end
main()
end
end)
Sorry for the bump, but could anyone please take a look at the script?
Been trying several things to fix it, including briefly disabling and re-enabling the AI, but nothing seems to work…
local TweenService = game:GetService("TweenService")
local Exits = {}
for i,v in pairs(workspace:GetChildren()) do
if v.Name == "Level1Entrance" then
table.insert(Exits,v)
end
end
script.Parent.Triggered:Connect(function(plr)
local Tween = TweenService:Create(plr.PlayerGui.MainGUI.BlackScreen,TweenInfo.new(2),{BackgroundTransparency = 0}):Play()
wait(2)
local Teleporter = Exits[math.random(1, #Exits)]
plr.Character:SetPrimaryPartCFrame(Teleporter.SpawnPlace.CFrame)
wait(2)
local Tween = TweenService:Create(plr.PlayerGui.MainGUI.BlackScreen,TweenInfo.new(2),{BackgroundTransparency = 1}):Play()
for i,v in pairs(workspace:GetDescendants()) do
if v.Name == "AI" and v:IsA("Script") then
v.Disabled = true
delay(0.1,function()
v.Disabled = false
end)
end
end
end)
ok, going back to the findTarget function, have you put any print statements in the loop to see if it is even detecting any players in the workspace? And have it print the distance, to see what distance they are. Only do this for the npc’s in the room that they are ignoring you.
Try this for the AI, see if it makes any difference… ALSO remove from your spawn script, the part where it Disable, and Enable the AI scripts.
local myHuman = script.Parent:WaitForChild("Humanoid")
local myRoot = script.Parent:WaitForChild("HumanoidRootPart")
local head = script.Parent:WaitForChild("Head")
local lowerTorso = script.Parent:WaitForChild("LowerTorso")
local grab = script.Parent:WaitForChild("Grab")
local grabAnim = myHuman:LoadAnimation(grab)
grabAnim.Priority = Enum.AnimationPriority.Action
local grabSound = head:WaitForChild("Attack")
local screamSound = head:WaitForChild("Scream")
local moanSound = head:WaitForChild("Moan")
local clone = script.Parent:Clone()
function walkRandomly()
local xRand = math.random(-20,20)
local zRand = math.random(-20,20)
local goal = myRoot.Position + Vector3.new(xRand,0,zRand)
local path = game:GetService("PathfindingService"):CreatePath()
path:ComputeAsync(myRoot.Position, goal)
local waypoints = path:GetWaypoints()
if math.random(20) == 1 then
moanSound:Play()
end
if path.Status == Enum.PathStatus.Success then
for _, waypoint in pairs(waypoints) do
if waypoint.Action == Enum.PathWaypointAction.Jump then
myHuman.Jump = true
end
myHuman:MoveTo(waypoint.Position)
local timeOut = myHuman.MoveToFinished:Wait(1)
if not timeOut then
myHuman.Jump = true
end
end
end
end
function findPath(target)
local path = game:GetService("PathfindingService"):CreatePath()
path:ComputeAsync(myRoot.Position,target.Position)
local waypoints = path:GetWaypoints()
if path.Status == Enum.PathStatus.Success then
for _, waypoint in pairs(waypoints) do
if waypoint.Action == Enum.PathWaypointAction.Jump then
myHuman.Jump = true
end
myHuman:MoveTo(waypoint.Position)
local timeOut = myHuman.MoveToFinished:Wait(1)
if not timeOut then
myHuman.Jump = true
return
end
if checkSight(target) then
repeat
myHuman: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 myHuman.Health < 1 or target.Parent.Humanoid.Health < 1
break
end
if (myRoot.Position - waypoints[1].Position).magnitude > 20 then
return
end
end
end
end
function checkSight(target)
local ray = Ray.new(myRoot.Position, (target.Position - myRoot.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 - myRoot.Position.Y) < 3 then
return true
end
end
return false
end
function findTarget()
local dist = 50
local target = nil
local potentialTargets = {}
local seeTargets = {}
for i,v in pairs(game.Players:GetPlayers()) do
if v and v.Character and v.Character:FindFirstChild("Humanoid") then
local human = v.Character.Humanoid
local hrp = v.Character.PrimaryPart
if (myRoot.Position - hrp.Position).magnitude < dist and human.Health > 0 then
table.insert(potentialTargets,hrp)
end
end
end
if #potentialTargets > 0 then
for i,v in pairs(potentialTargets) do
if checkSight(v) then
table.insert(seeTargets, v)
end
end
end
if #seeTargets > 0 then
dist = 200
for i,v in pairs(seeTargets) do
if (myRoot.Position - v.Position).magnitude < dist then
target = v
dist = (myRoot.Position - v.Position).magnitude
end
end
end
if target then
if math.random(20) == 1 then
screamSound:Play()
end
end
return target
end
function attack(target)
if (myRoot.Position - target.Position).magnitude < 5 then
grabAnim:Play()
grabSound:Play()
if target.Parent ~= nil then
target.Parent.Humanoid:TakeDamage(25)
end
wait(0.4)
end
end
function died()
wait(5)
clone.Parent = workspace
game:GetService("Debris"):AddItem(script.Parent,0.1)
end
myHuman.Died:Connect(died)
lowerTorso.Touched:Connect(function(obj)
if not obj.Parent:FindFirstChild("Humanoid") then
myHuman.Jump = true
end
end)
function main()
local target = findTarget()
print(target)
if target then
myHuman.WalkSpeed = 10
findPath(target)
else
myHuman.WalkSpeed = 7
walkRandomly()
end
end
spawn(function()
while wait() do
if myHuman.Health < 1 then
break
end
main()
end
end)
Thanks, I’ll try this now.
The reason for disabling and re-enabling the AI was that it seemed to work while testing on Studio, but testing on Player didn’t work.
Hmmm… That didn’t seem to work, even tried disabling StreamingEnabled since the player teleports from a pretty large distance (from the yellow square to the gray one, dummies on the middle baseplate for comparison):