In pairs(players) for npc script ddn't work!

Hellow Fella Dev,

I am making a monster in studio for my future horror game. But the In pairs code didn’t work and I don’t know why. Please help.

The AI script:

local caty = script.Parent
local humanoid = caty.Humanoid
caty.PrimaryPart:SetNetworkOwner(nil)

local function IsTarget()
	local players = game:GetService("Players")
	local maximum = 80
	local nearestTarget
	
	for player in pairs(players) do
		player.PlayerAdded:Connect(function(Player)
			Player.CharacterAdded:Connect(function(Character)
				if Character then
					local target = Character
					local distance = (caty.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude
					
					if distance < maximum then
						nearestTarget = target
						maximum = distance
					end
				end
			end)
		end)
	end
	
	return nearestTarget
end

local function PathSystem(destination)
	local PathfindingService = game:GetService("PathfindingService")
	
	local ParamsTable = {
		["AgentRadius"] = 8,
		["AgentHeight"] = 4.6,
		["AgentCanJump"] = false
	}
	
	local Path = PathfindingService:CreatePath(ParamsTable)
	Path:ComputeAsync(caty.HumanoidRootPart.Position, destination.Position)
	
	return Path
end

local function Kill(target)
	local distance = (caty.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude
	
	if distance > 3 then
		humanoid:MoveTo(target.HumanoidRootPart.Position)
	else
		local attackAnim = humanoid:LoadAnimation(script.AttackAnim)
		attackAnim:Play()
		attackAnim.Completed:Wait()
		target.Humanoid.Health = 0
	end
end

local function WalkTo(destination)
	local Path = PathSystem(destination)
	
	if Path.Status == Enum.PathStatus.Success then
		for way in pairs(Path:GetWaypoints()) do
			local target = IsTarget()
			if target and target.Humanoid.Health > 0 then
				Kill(target)
				break
			else
				humanoid:MoveTo(way.Position)
				humanoid.MoveToFinished:Wait()
			end
		end
	else
		humanoid:MoveTo(destination.Position - (caty.HumanoidRootPart.CFrame.LookVector))
	end
end

function Loops()
	local pathWay = workspace.PathWay:GetChildren()
	local randomWay = math.random(1, #pathWay)
	WalkTo(pathWay[randomWay])
end

while wait(2) do
	Loops()
end

I appreciate your help!

2 Likes

any error on the output???

1 Like

Yesimage

try
for player in pairs(players:GetChildren()) do

Correction: do Players:GetPlayers() instead, it’s more safer than GetChildren().

image

You’re only specifying the index, change to for _, player in pairs().

My pathfinding system is better. You can use this since it’s faster.

https://www.roblox.com/library/6723923521/Pathfinding-script

Also go to this line

	local players = game:GetService("Players")

and replace with

	local players = game:GetService("Players"):GetChildren()

and u dont need to add the Player.PlayerAdded event either.

Just do player.CharacterAdded event but even then you’re going to cause a memory leak.

still image

You are trying to loop over an instance. You are trying to loop over the Players instance, which isn’t a table. You want to loop over Players:GetPlayers(), which returns a table.

Additionally, PlayerAdded is an event of Players (the service), not an event for a Player instance.

You’re also connecting events and then trying to return stuff. That’s not going to work.

What you should do is get rid of all of the event stuff, and just loop over players:GetPlayers(). Then, to get the character, you can do Player.Character or Player.CharacterAdded:Wait().

The Wait function is a function on events, just like Connect. Unlike connect, Wait waits for the event to fire.

Player.Character or Player.CharacterAdded:Wait() means it will look at the Player.Character property, which, will be set to nil if the player doesn’t have a character yet. So, if the player doesn’t have a character, its like nil or Player.CharacterAdded:Wait(), so it will wait for a character to be added with the event.

When you connect to an event, the game does not wait for the event to fire, the event will just fire your callback function whenever that thing happens. So, whenever a player’s character gets added CharacterAdded is fired so your callback gets called. It won’t fire the event unless a character is being added after you connect, so if a Character exists it will not call your function.

if i were u i would make it
local Players = game:GetService(“Players”)

for i,v inpairs (game.Workspace:GetChildren()) do
if i:FindFirstChild(“Humanoid”) then
if Players:GetPlayerFromCharacter(i) then

SHow me how your for loop code line looks like now.

local caty = script.Parent
local humanoid = caty.Humanoid
caty.PrimaryPart:SetNetworkOwner(nil)

local function IsTarget()
	local players = game:GetService("Players"):GetChildren()
	local maximum = 80
	local nearestTarget
	
	for _, player in pairs(players) do
		player.PlayerAdded:Connect(function(Player)
			Player.CharacterAdded:Connect(function(Character)
				if Player.Character then
					local target = Player.Character
					local distance = (caty.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude

					if distance < maximum then
						nearestTarget = target
						maximum = distance
					end
				end	
			end)
	end)
end
	
	return nearestTarget
end

local function PathSystem(destination)
	local PathfindingService = game:GetService("PathfindingService")
	
	local ParamsTable = {
		["AgentRadius"] = 8,
		["AgentHeight"] = 4.6,
		["AgentCanJump"] = false
	}
	
	local Path = PathfindingService:CreatePath(ParamsTable)
	Path:ComputeAsync(caty.HumanoidRootPart.Position, destination.Position)
	
	return Path
end

local function Kill(target)
	local distance = (caty.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude
	
	if distance > 3 then
		humanoid:MoveTo(target.HumanoidRootPart.Position)
	else
		local attackAnim = humanoid:LoadAnimation(script.AttackAnim)
		attackAnim:Play()
		attackAnim.Completed:Wait()
		target.Humanoid.Health = 0
	end
end

local function WalkTo(destination)
	local Path = PathSystem(destination)
	
	if Path.Status == Enum.PathStatus.Success then
		for way in pairs(Path:GetWaypoints()) do
			local target = IsTarget()
			if target and target.Humanoid.Health > 0 then
				Kill(target)
				break
			else
				humanoid:MoveTo(way.Position)
				humanoid.MoveToFinished:Wait()
			end
		end
	else
		humanoid:MoveTo(destination.Position - (caty.HumanoidRootPart.CFrame.LookVector))
	end
end

function Loops()
	local pathWay = workspace.PathWay:GetChildren()
	local randomWay = math.random(1, #pathWay)
	WalkTo(pathWay[randomWay])
end

while wait(2) do
	Loops()
end

This is not at all a good way to do this.

You should not be looping over the children in the workspace to get players. Instead you should do this:

local Players = game:GetService("Players")

for _, player in ipairs(Players:GetPlayers()) do
    local character = player.Character or player.CharacterAdded:Wait()
    -- Code
end
1 Like

The player Instance doesn’t be have that event, remove that code line so the player will be connected to CharacterAdded event, if that’s what you want.

There are many more issues than this, I pointed them out in my reply above.

@YTDevlog
The loop doesn’t have an index (it has to be for _, player in or for someNameForTheIndex, player in ). You are trying to loop over players which is an instance, you can’t do that. You have to do pairs(players:GetPlayers()). PlayerAdded is an event on the Players service, not on a Player. PlayerAdded fires whenever a new player is added, what you are doing is connecting an event for every player in the game, and, that will use up memory and make your code run multiple times, which you don’t want.

You should do what I said in my post above to fix this stuff.