Path Finding Zombie System, bugging

Video :slight_smile:

I want to achieve:

That the zombie opens door, follows player

Here’s a testing game:
ZombiePathFindingServiceNotWorkingCorrectly.rbxl (128,5 KB)

It uses a bit of raycast, Magnitude calculation

Extra information:

When it opens door it keeps walking against door , thats what I am trying to fix.

Ai Script
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 collectionservice = game:GetService("CollectionService")

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 clone = script.Parent:Clone()


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 ipairs(waypoints) do
			if waypoint.Action == Enum.PathWaypointAction.Jump then
				myHuman.Jump = true
			end
			
			local doors = collectionservice:GetTagged("Door")
			for i,v in pairs(doors) do
				if (script.Parent.HumanoidRootPart.Position-v.Center.Position).Magnitude < v.MaxDistance.Value then
					if v.Open.Value == false then
						local a = require(v.OpenDoor)
						a:opendoor(script.Parent)
						wait(.3)
					end
				end
			end
			
			myHuman:MoveTo(waypoint.Position)
			--local timeOut = myHuman.MoveToFinished:Wait(1)
			--if not timeOut then
			--	myHuman.Jump = true
			--	print("Path too long!")
			--	findPath(target)
			--	break
			--end
			if checkSight(target) then
				repeat
					print("Moving directly to the target")
					myHuman:MoveTo(target.Position)
					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
				print("Target has moved, generating new path")
				findPath(target)
				break
			end
		end
	end
end



function checkSight(target)
	local ray = Ray.new(myRoot.Position, (target.Position - myRoot.Position).Unit * 5)
	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
			print("I can see the target")
			return true
		end
	end
	return false
end

function findTarget()
	local dist = 300
	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 (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 ipairs(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 ipairs(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

local debonce = false

for i,v in pairs(script.Parent:GetChildren()) do
	if v:IsA("BasePart") then
		v.Touched:connect(function(hit)
			local plr = game.Players:GetPlayerFromCharacter(hit.Parent)
			if plr and not debonce then
				debonce=true
				hit.Parent.Humanoid:TakeDamage(25)
				wait(.3)
				debonce=false
			end
		end)
	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()
	if target then
		myHuman.WalkSpeed = 12
		findPath(target)
	end
end

while wait(0.1) do
	if myHuman.Health < 1 then
		break
	end
	main()
end

















Door Module
local module = {}

local open = false
local debounce = false

local distance = script.Parent.MaxDistance.Value

local function rotatedoor(xd)
	local start = script.Parent.PrimaryPart.CFrame
	local finish = script.Parent.PrimaryPart.CFrame * CFrame.Angles(0,math.rad(xd),0)
	for i=0,1,.1 do
		local cfm = start:Lerp(finish,i)
		script.Parent:SetPrimaryPartCFrame(cfm)
		wait()
	end
	script.Parent:SetPrimaryPartCFrame(finish)
end

local function opendoor()
	if open then 
		rotatedoor(-90)
	else
		rotatedoor(90)
	end
end

function module:opendoor(char)
	if char then
		if (char.HumanoidRootPart.Position-script.Parent.Center.Position).Magnitude > distance then
			return
		end else return
	end
	if not debounce then
		debounce=true
		open=not open
		opendoor()
		debounce=false
	end
	script.Parent.Open.Value=open
end

return module
Door Script
local module = require(script.Parent.OpenDoor)

local collectionservice = game:GetService("CollectionService")

collectionservice:AddTag(script.Parent,"Door")

script.Parent.RemoteEvent.OnServerEvent:Connect(function(plr)

module:opendoor(plr.Character)

end)

Could you share the script? I think you could easily implement something in the path finding part of the script that checks for paths around objects.

The Path.Blocked event could be useful here. The Character Pathfinding | Roblox Creator Documentation article provides information as to how you could implement it.

He litteraly uploaded his .rblx file. Can’t you open it?

I can, but it’s almost always better to just have the code posted.

There you go.

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 collectionservice = game:GetService("CollectionService")

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 clone = script.Parent:Clone()

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 ipairs(waypoints) do

if waypoint.Action == Enum.PathWaypointAction.Jump then

myHuman.Jump = true

end

local doors = collectionservice:GetTagged("Door")

for i,v in pairs(doors) do

if (script.Parent.HumanoidRootPart.Position-v.Center.Position).Magnitude < v.MaxDistance.Value then

if v.Open.Value == false then

local a = require(v.OpenDoor)

a:opendoor(script.Parent)

wait(.3)

end

end

end

myHuman:MoveTo(waypoint.Position)

--local timeOut = myHuman.MoveToFinished:Wait(1)

--if not timeOut then

-- myHuman.Jump = true

-- print("Path too long!")

-- findPath(target)

-- break

--end

if checkSight(target) then

repeat

print("Moving directly to the target")

myHuman:MoveTo(target.Position)

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

print("Target has moved, generating new path")

findPath(target)

break

end

end

end

end

function checkSight(target)

local ray = Ray.new(myRoot.Position, (target.Position - myRoot.Position).Unit * 5)

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

print("I can see the target")

return true

end

end

return false

end

function findTarget()

local dist = 300

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 (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 ipairs(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 ipairs(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

local debonce = false

for i,v in pairs(script.Parent:GetChildren()) do

if v:IsA("BasePart") then

v.Touched:connect(function(hit)

local plr = game.Players:GetPlayerFromCharacter(hit.Parent)

if plr and not debonce then

debonce=true

hit.Parent.Humanoid:TakeDamage(25)

wait(.3)

debonce=false

end

end)

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()

if target then

myHuman.WalkSpeed = 12

findPath(target)

end

end

while wait(0.1) do

if myHuman.Health < 1 then

break

end

main()

end

I added the Scripts for everyone.

There you go check above.

As I said, the Path.Blocked event would be the best way to deal with this kind of issue. The article I linked can help with that and provides ample examples which you can use in your own script.

local function onPathBlocked(blockedWaypointIndex)
	if blockedWaypointIndex > currentWaypointIndex then
		followPath(destination)
	end
end

path.Blocked:Connect(onPathBlocked)