i ve wasted 2 days and still have not figure this issue
what i want is when a npc whose chasing player but he is far away from his primary position like 100 studs
i want him to pathfind his way to his position and not following the player until he gets back
my issue : when the npc returns he starts movinf randomly and the variable thats controllers whether he should return or not starts to change rapdility between true and false
local PFS = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local Debris = game:GetService("Debris")
local PathHandler = {}
PathHandler.OriginalPositions = {}
-- Set player WalkSpeed on join
Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
local humanoid = character:WaitForChild("Humanoid")
humanoid.WalkSpeed = 50
end)
end)
function PathHandler.IsInVision(monster, targetCharacter)
-- Set field of view in degrees; adjust as needed.
local fovAngle = 45
local threshold = math.cos(math.rad(fovAngle))
local direction = (targetCharacter.PrimaryPart.Position - monster.PrimaryPart.Position).Unit
local lookVector = monster.PrimaryPart.CFrame.LookVector
local dot = lookVector:Dot(direction)
return dot >= threshold
end
-- Internal function to visualize waypoints
local function VisualizeWaypoints(waypoints, duration)
duration = duration or 5 -- default duration is 5 seconds
for _, waypoint in ipairs(waypoints) do
local marker = Instance.new("Part")
marker.Name = "WaypointMarker"
marker.Shape = Enum.PartType.Ball
marker.Material = Enum.Material.Neon
marker.Color = Color3.fromRGB(255, 0, 0) -- bright red
marker.Size = Vector3.new(1, 1, 1)
marker.Anchored = true
marker.CanCollide = false
marker.Position = waypoint.Position
marker.Parent = workspace
Debris:AddItem(marker, duration)
end
end
-- Attempts to follow the target character by computing a path and moving the NPC along it
function PathHandler.FollowPlayer(monster, targetCharacter)
-- Get the monster's dimensions for agent parameters
local extents = monster:GetExtentsSize()
local x = extents.Y -- Using Y as height (adjust if needed)
local y = math.max(extents.X, extents.Z) / 2 -- Approximate horizontal radius
local agency = {
AgentRadius = x,
AgentHeight = y
}
-- Create and compute the path using the monster's PrimaryPart
local path = PFS:CreatePath(agency)
path:ComputeAsync(monster.PrimaryPart.Position, targetCharacter.PrimaryPart.Position)
if path.Status == Enum.PathStatus.Success then
local waypoints = path:GetWaypoints()
VisualizeWaypoints(waypoints)
-- Connect the Blocked event once
local blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
print("Path is blocked at waypoint:", blockedWaypointIndex)
-- Optionally: Recalculate the path here if needed.
end)
-- Start from waypoint 2 (assuming waypoint 1 is the starting position)
local currentWaypointIndex = 2
if currentWaypointIndex <= #waypoints then
monster.Humanoid:MoveTo(waypoints[currentWaypointIndex].Position)
end
-- Wait for the NPC to reach each waypoint before moving on
local moveConnection
moveConnection = monster.Humanoid.MoveToFinished:Connect(function(reached)
if reached then
currentWaypointIndex = currentWaypointIndex + 1
if currentWaypointIndex <= #waypoints then
monster.Humanoid:MoveTo(waypoints[currentWaypointIndex].Position)
else
-- Completed the path; disconnect events.
moveConnection:Disconnect()
blockedConnection:Disconnect()
end
else
moveConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
else
warn("Pathfinding failed with status:", path.Status)
end
end
function PathHandler.ReturnHome(monster,originalCFrame)
if originalCFrame then
local homeTarget = {PrimaryPart = {Position = originalCFrame.Position}}
PathHandler.FollowPlayer(monster, homeTarget)
end
end
-- Checks for the nearest player and, if within range, calls FollowPlayer on that character
function PathHandler.CheckNearestPlayer(monster:Model)
-- First, check if the monster is too far from its original home position.
local IsReturning = monster:GetAttribute("IsReturning")
local originalCFrame = PathHandler.OriginalPositions[monster]
if originalCFrame then
local distFromHome = (monster.PrimaryPart.Position - originalCFrame.Position).Magnitude
local MaxAway = monster:GetAttribute("MaxAway")
if distFromHome > MaxAway then
monster:SetAttribute("IsReturning", true)
end
if monster:GetAttribute("IsReturning") then
PathHandler.ReturnHome(monster,originalCFrame)
if (monster.PrimaryPart.Position - originalCFrame.Position).Magnitude <= 5 then
monster:SetAttribute("IsReturning", false)
end
return
end
end
local players = Players:GetPlayers()
if #players > 0 or IsReturning == false then
local MaxDist = monster:GetAttribute("MaxDist")
for _, player in ipairs(players) do
local character = player.Character
-- Ensure the character exists, has a Humanoid, and a PrimaryPart
if character and character:FindFirstChildWhichIsA("Humanoid") and character.PrimaryPart then
local distance = (monster.PrimaryPart.Position - character.PrimaryPart.Position).Magnitude
if distance < 8 or (distance < MaxDist and PathHandler.IsInVision(monster, character)) then
PathHandler.FollowPlayer(monster, character)
end
end
end
end
end
function PathHandler.Start(monster,monsterCframe)
task.spawn(function()
PathHandler.OriginalPositions[monster] = monsterCframe
while true do
if monster:GetAttribute("IsReturning") == true then
task.wait()
continue
end
PathHandler.CheckNearestPlayer(monster)
task.wait()
end
end)
end
return PathHandler