Problem with npc in publish game

Problem: NPC running to player’s humanoidrootpart then stops doing anything or delaying too much unlike in Roblox studio

local RunService = game:GetService("RunService")
local npc = script.Parent
local humanoid = npc:WaitForChild("Humanoid")
local hrp = npc:WaitForChild("HumanoidRootPart")
local stuck = false
local Chase = script.ChaseValue.Value
local inv = npc.Allpart:FindFirstChild("Head")

--Timing
local lastSoundTime = 0
local soundCooldown = math.random(9, 11)

--Animation
local walkAnim = humanoid.Animator:LoadAnimation(script.Walk)
local attackAnim = humanoid.Animator:LoadAnimation(script.Attack)
local runAnim = humanoid.Animator:LoadAnimation(script.Run)
local idleAnim = humanoid.Animator:LoadAnimation(script.Idle)

local breathing = npc.HumanoidRootPart:WaitForChild("Breathing")
local walk = npc.HumanoidRootPart:WaitForChild("walk")

--sound group
local sounds = {
	npc.HumanoidRootPart:WaitForChild("happy1"),
	npc.HumanoidRootPart:WaitForChild("Happy2"),
	npc.HumanoidRootPart:WaitForChild("happy4"),
	npc.HumanoidRootPart:WaitForChild("happy5"),
	npc.HumanoidRootPart:WaitForChild("Pancake!"),
	npc.HumanoidRootPart:WaitForChild("ScaryBreathing"),
	npc.HumanoidRootPart:WaitForChild("Lion Roar Growl Exhale Low Rumble Breath 1 (SFX)")
}

-- Pathfinding parameters
local pathParams = {
	AgentHeight = 8.8,
	AgentRadius = hrp.Size.X > 0 and hrp.Size.X or hrp.Size.Y,
	AgentCanJump = true,
}

-- Raycast parameters
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Exclude
rayParams.FilterDescendantsInstances = {npc}

local RANGE = script:WaitForChild("Range").Value
local Speed = script:WaitForChild("Runner").Value
local NorSpeed = script:WaitForChild("Walker").Value

local debounce = false

--see Target function
local function canSeeTarget(target)
	local origin = hrp.Position
	local direction = (target.HumanoidRootPart.Position - origin).Unit * RANGE
	local ray = workspace:Raycast(origin, direction, rayParams)
	return ray and ray.Instance:IsDescendantOf(target)
end

--get a random sound
local function getRandomSound()
	local randomValue = math.random(1, 100)
	if randomValue <= 80 then
		return sounds[7]  -- Predetermined sound
	else
		return sounds[math.random(1, #sounds)]  -- Random sound from the list
	end
end

-- play a random sound
local function playRandomSound()
	local currentTime = tick()
	if currentTime - lastSoundTime >= soundCooldown then
		local soundToPlay = getRandomSound()
		soundToPlay:Play()
		lastSoundTime = currentTime
	end
end

-- find the nearest target
local function findTarget()
	local players = game.Players:GetPlayers()
	local nearestTarget
	local maxDistance = RANGE

	if inv.Transparency == 0 then
		for _, player in pairs(players) do
			if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
				local target = player.Character
				local distance = (hrp.Position - target.HumanoidRootPart.Position).Magnitude

				if distance < maxDistance and canSeeTarget(target) then
					local attackableValue = player:FindFirstChild("Attackable")

					if attackableValue and attackableValue.Value == true and target.Humanoid.Health > 0 then
						nearestTarget = target
						maxDistance = distance
						humanoid.WalkSpeed = Speed
						playRandomSound()
					end
				end
			end
		end
	end
	return nearestTarget
end

--  get path to a destination
local function getPath(destination)
	local path = PathfindingService:CreatePath(pathParams)
	path:ComputeAsync(hrp.Position, destination.Position)
	return path
end

--  attack a target
local function attack(target)
	local distance = (hrp.Position - target.HumanoidRootPart.Position).Magnitude
	local player = game.Players:GetPlayerFromCharacter(target)
	local attackableValue = player and player:FindFirstChild("Attackable")

	if attackableValue and attackableValue.Value == true then
		if distance <= 4 then 
			if not debounce then
				debounce = true
				attackAnim:Play()
				target.Humanoid.Health = 0 
				attackAnim.Stopped:Wait()
				debounce = false
				Chase = false
				wait(0.5) 
				Chase = true
			end
		else
			humanoid:MoveTo(target.HumanoidRootPart.Position)
		end
	end
end


local function idle()
	walkAnim:Stop()
	local idleTime = math.random(5, 7)
	humanoid.WalkSpeed = 0
	breathing:Play()
	walk:Stop()
	walkAnim:Stop()
	runAnim:Stop()
	idleAnim:Play()
	wait(idleTime)
	walk:Play()
	breathing:Stop()
	idleAnim:Stop()
	walkAnim:Play()
	humanoid.WalkSpeed = NorSpeed
end

local function walkTo(destination)
	local path = getPath(destination)

	if path.Status == Enum.PathStatus.Success then
		for _, waypoint in pairs(path:GetWaypoints()) do
			if waypoint.Action == Enum.PathWaypointAction.Jump then
				humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
			end

			local target = findTarget()

			if target and target.Humanoid.Health > 0 then
				local currentTargetPosition = target.HumanoidRootPart.Position

				if canSeeTarget(target) then
					humanoid:MoveTo(currentTargetPosition)
					runAnim:Play()
					walkAnim:Stop()
					humanoid.MoveToFinished:Wait()
					attack(target)
					break
				end
			end

			humanoid:MoveTo(waypoint.Position)
			humanoid.MoveToFinished:Wait()

			if math.random() < 0.05 then
				idle()
			end
		end
	end
end

local function patrol()
	if Chase then
		local waypoints = workspace.Waypoints:GetChildren()
		local randomNum = math.random(1, #waypoints)
		walkTo(waypoints[randomNum])
		walkAnim:Play()
		runAnim:Stop()
	end
end

-- check vase interaction
local function checkVase()
	local vaseFolder = workspace:FindFirstChild("VaseandTable")
	local vase = vaseFolder and vaseFolder:FindFirstChild("VaseTable").Vase
	if vase and vase.TouchValue.Value == true then
		local vasePosition = vase.Position
		if (hrp.Position - vasePosition).Magnitude <= 1000 then
			local path = getPath(vase)
			if path.Status == Enum.PathStatus.Success then
				for _, waypoint in pairs(path:GetWaypoints()) do
					if waypoint.Action == Enum.PathWaypointAction.Jump then
						humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
					end

					humanoid:MoveTo(waypoint.Position)
					humanoid.MoveToFinished:Wait()

					local target = findTarget()
					if target then
						attack(target)
						return
					end
				end
				vase.TouchValue.Value = false -- Reset the BoolValue
				idle()
			end
		end
	end
end

--check Eye Trap interaction
local function EyeTrap()
	local eyeFolder = workspace:FindFirstChild("EyeMonsterTrapFolder")
	local eyeMonster = eyeFolder and eyeFolder:FindFirstChild("EyeMonster")
	local eyeTrapValue = eyeMonster and eyeMonster.Hunting.EyeCheckValue
	local eyeTrap = eyeMonster and eyeMonster.HumanoidRootPart

	if eyeTrap and eyeTrapValue.Value == true then
		local eyePosition = eyeTrap.Position
		if (hrp.Position - eyePosition).Magnitude <= 1000 then
			local path = getPath(eyeTrap)
			if path.Status == Enum.PathStatus.Success then
				for _, waypoint in pairs(path:GetWaypoints()) do
					if waypoint.Action == Enum.PathWaypointAction.Jump then
						humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
					end

					humanoid:MoveTo(waypoint.Position)
					humanoid.MoveToFinished:Wait()

					local target = findTarget()
					if target then
						attack(target)
						return
					end
				end
				eyeTrapValue.Value = false 
			end
		end
	end
end

-- Main loop
while RunService.Heartbeat:Wait(0.1) do
	patrol()
	checkVase()
	EyeTrap()
end

after testing without any wall/decorate it work again.(publish server)

still unlike in studio something might cause this to happen?

setting AgentHeight lower actually fixing npc’s problem (right now)

part of the reason could be that player characters on the server are always behind what the actual player sees
You can predict their position by adding their velocity to your move to position

humanoid:MoveTo(target.HumanoidRootPart.Position + target.HumanoidRootPart.Velocity*5)

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.