I’m trying to create an NPC system. At first, it works fine, but after a while, it stops working and won’t move anymore
Script
local npc = script.Parent
local humanoid = npc:FindFirstChild("Humanoid")
local initialPosition = npc.PrimaryPart.Position
local randomWalkRadius = 0 -- Raio de andar aleatoriamente
local detectionRadius = 50 -- Raio de detecção do jogador
local followRadius = 150 -- Raio máximo para seguir o jogador (baseado na initialPosition)
local canJump = true -- Define se o NPC pode pular ou não
local CanNotWalkInPublic = false
local pathfindingService = game:GetService("PathfindingService")
local randomMoveWaitTimeMin = 1
local randomMoveWaitTimeMax = 10
local isMovingRandomly = false
local isFollowingPlayer = false
-- Configurações do Pathfinding
local agentParameters = {
AgentRadius = 5, -- Raio do NPC (ajuste conforme o tamanho do NPC)
AgentHeight = 5, -- Altura do NPC (ajuste conforme o tamanho do NPC)
AgentCanJump = canJump, -- Define se o NPC pode pular
AgentCanClimb = true, -- Define se o NPC pode escalar
AgentMaxSlopeAngle = 80, -- Ângulo máximo de inclinação que o NPC pode subir
}
-- Verifica se o jogador está olhando para o NPC
local function isPlayerLooking(player)
if not CanNotWalkInPublic then return false end -- Se WalkInPublic for falso, ignora essa verificação
local playerRootPart = player.Character and player.Character:FindFirstChild("HumanoidRootPart")
if playerRootPart then
local npcDirection = (npc.PrimaryPart.Position - playerRootPart.Position).Unit
local playerLookDirection = playerRootPart.CFrame.LookVector
local dotProduct = npcDirection:Dot(playerLookDirection)
return dotProduct > 0.5
end
return false
end
-- Ancorar ou desancorar todas as Parts do NPC
local function setNPCAnchored(state)
for _, part in ipairs(npc:GetDescendants()) do
if part:IsA("BasePart") and part ~= npc.PrimaryPart then
part.Anchored = state
end
end
end
-- Verifica se o jogador está dentro do raio de detecção
local function isPlayerInDetectionRadius()
for _, player in pairs(game.Players:GetPlayers()) do
local playerRootPart = player.Character and player.Character:FindFirstChild("HumanoidRootPart")
if playerRootPart then
local distance = (playerRootPart.Position - npc.PrimaryPart.Position).Magnitude
if distance <= detectionRadius then
return player
end
end
end
return nil
end
-- Movimento aleatório
function moveRandomly()
if isMovingRandomly then return end
isMovingRandomly = true
local retries = 0
local moved = false
while not moved and retries < 5 and not isFollowingPlayer do
local targetPosition = initialPosition + Vector3.new(
math.random(-randomWalkRadius, randomWalkRadius),
0,
math.random(-randomWalkRadius, randomWalkRadius)
)
local path = pathfindingService:CreatePath(agentParameters)
path:ComputeAsync(npc.PrimaryPart.Position, targetPosition)
if path.Status == Enum.PathStatus.Success then
local waypoints = path:GetWaypoints()
if #waypoints > 0 then
for _, waypoint in ipairs(waypoints) do
if isFollowingPlayer then break end
humanoid:MoveTo(waypoint.Position)
if waypoint.Action == Enum.PathWaypointAction.Jump then
humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
end
local precision = 6
local dist = (npc.PrimaryPart.Position - waypoint.Position).Magnitude
repeat
task.wait()
dist = (npc.PrimaryPart.Position - waypoint.Position).Magnitude
until dist <= precision or isFollowingPlayer
end
moved = true
end
else
retries = retries + 1
end
end
if not isFollowingPlayer and moved then
local waitTime = math.random(randomMoveWaitTimeMin, randomMoveWaitTimeMax)
local startTime = tick()
while tick() - startTime < waitTime and not isFollowingPlayer do
if isPlayerInDetectionRadius() then
break
end
wait(0.1)
end
end
isMovingRandomly = false
end
-- Seguir jogador
function followPlayer(player)
if isFollowingPlayer then return end -- Evita múltiplas execuções simultâneas
isFollowingPlayer = true
local playerRootPart = player.Character and player.Character:FindFirstChild("HumanoidRootPart")
if playerRootPart then
local distanceToInitialPosition = (playerRootPart.Position - initialPosition).Magnitude
if distanceToInitialPosition > followRadius then
-- Se o jogador estiver fora do raio de seguimento, volta para a posição inicial
humanoid:MoveTo(initialPosition)
isFollowingPlayer = false
return
end
local path = pathfindingService:CreatePath(agentParameters)
path:ComputeAsync(npc.PrimaryPart.Position, playerRootPart.Position)
if path.Status == Enum.PathStatus.Success then
local waypoints = path:GetWaypoints()
if #waypoints > 0 then
for _, waypoint in ipairs(waypoints) do
if not isFollowingPlayer then break end -- Interrompe se parar de seguir o jogador
if isPlayerLooking(player) then
humanoid:MoveTo(npc.PrimaryPart.Position)
setNPCAnchored(true)
isFollowingPlayer = false
return
else
setNPCAnchored(false)
end
humanoid:MoveTo(waypoint.Position)
if waypoint.Action == Enum.PathWaypointAction.Jump then
humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
end
local precision = 6 -- Precisão ajustada para 6
local dist = (npc.PrimaryPart.Position - waypoint.Position).Magnitude
repeat task.wait() dist = (npc.PrimaryPart.Position - waypoint.Position).Magnitude until dist <= precision or not isFollowingPlayer
end
end
end
end
isFollowingPlayer = false
end
local function resetNPC()
setNPCAnchored(false)
humanoid:MoveTo(initialPosition)
isMovingRandomly = false
isFollowingPlayer = false
end
-- Comportamento
function npcBehavior()
while npc and npc.Parent and humanoid and humanoid.Health > 0 do
local closestPlayer = isPlayerInDetectionRadius()
if closestPlayer then
if isPlayerLooking(closestPlayer) then
setNPCAnchored(true)
humanoid:MoveTo(npc.PrimaryPart.Position)
else
setNPCAnchored(false)
followPlayer(closestPlayer)
end
else
setNPCAnchored(false)
moveRandomly()
end
end
end
npcBehavior()