-- Services
local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
-- Variables
local zombie = script.Parent
local humanoid = zombie:WaitForChild("Humanoid")
local rootPart = zombie:WaitForChild("HumanoidRootPart")
local TARGET_DISTANCE = 100 -- Max distance to detect players
local PATH_RECOMPUTE_TIME = 0.1 -- Time between path recalculations
local originalPosition = rootPart.Position -- The zombie's spawn position
local safeZones = Workspace:WaitForChild("SafeZones") -- Folder containing all safe
zone parts
-- Function to check if a player is in a safe zone
local function isPlayerInSafeZone(player)
if player.Character and player.Character:FindFirstChild("HumanoidRootPart")
then
local playerPosition = player.Character.HumanoidRootPart.Position
for _, zone in pairs(safeZones:GetChildren()) do
if zone:IsA("BasePart") then
local zoneSize = zone.Size
local zonePosition = zone.Position
-- Calculate the bounds of the safe zone
local minBound = zonePosition - (zoneSize / 2)
local maxBound = zonePosition + (zoneSize / 2)
-- Check if the player's position is within these bounds
if playerPosition.X >= minBound.X and playerPosition.X <=
maxBound.X and
playerPosition.Y >= minBound.Y and playerPosition.Y <=
maxBound.Y and
playerPosition.Z >= minBound.Z and playerPosition.Z <=
maxBound.Z then
return true
end
end
end
end
return false
end
-- Function to find the nearest player
local function findNearestPlayer()
local nearestPlayer = nil
local shortestDistance = TARGET_DISTANCE
for _, player in pairs(Players:GetPlayers()) do
if player.Character and player.Character:FindFirstChild("HumanoidRootPart")
then
-- Skip the player if they are in a safe zone
if isPlayerInSafeZone(player) then
continue
end
local playerPosition = player.Character.HumanoidRootPart.Position
local distance = (playerPosition - rootPart.Position).Magnitude
if distance < shortestDistance then
nearestPlayer = player.Character
shortestDistance = distance
end
end
end
return nearestPlayer
end
-- Function to follow a target
local function followTarget(target)
while target and target:FindFirstChild("HumanoidRootPart") do
local targetPosition = target.HumanoidRootPart.Position
-- Create and compute path
local path = PathfindingService:CreatePath({
AgentRadius = 2, -- Adjust these values to fit the zombie's size
AgentHeight = 5,
AgentCanJump = true,
AgentJumpHeight = 10,
AgentMaxSlope = 45,
})
path:ComputeAsync(rootPart.Position, targetPosition)
if path.Status == Enum.PathStatus.Success then
local waypoints = path:GetWaypoints()
for _, waypoint in pairs(waypoints) do
humanoid:MoveTo(waypoint.Position)
-- Wait for the zombie to reach the waypoint or abort if the target
moves
local reached = humanoid.MoveToFinished:Wait()
-- Check if the target is still valid
if not target.Parent or
isPlayerInSafeZone(Players:GetPlayerFromCharacter(target)) then
return -- Stop following if the target is gone or enters a safe
zone
end
-- If the waypoint requires jumping
if waypoint.Action == Enum.PathWaypointAction.Jump then
humanoid.Jump = true
end
end
else
warn("Pathfinding failed.")
end
-- Recompute the path after a short delay
wait(PATH_RECOMPUTE_TIME)
end
end
-- Main logic
while true do
local target = findNearestPlayer()
if target then
followTarget(target) -- Continuously follow the target
else
-- No players found: return to original position
moveToPosition(originalPosition)
end
wait(PATH_RECOMPUTE_TIME)
end