Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Variable is nil, and I can't figure out why?

So I have this NPC, and it works, unless you walk behind it or around it. I get the error 'Workspace.NewNpc.Dummy.AI:94: attempt to index global 'prs' (a nil value)'.

The script's really long, sorry if this hurts your eyes.

local ts = game:GetService("TweenService")

local event = Instance.new("BindableEvent")

event.Name = ("StartAttacking")

event.Parent = script.Parent.Parent

  

wait(5)

  

script.Parent.AttackingPlayer.Value = ""

  

local range = 20

  

local function searchforplayer()

local ray = Ray.new(script.Parent.HumanoidRootPart.CFrame.Position, script.Parent.HumanoidRootPart.CFrame.LookVector * 500)

local hrp = script.Parent.HumanoidRootPart.Position

local num = 8

local part = game.Workspace:FindPartOnRay(ray)

local person = nil

if part then

if part.Parent:FindFirstChild("Humanoid") then

if game.Players:FindFirstChild(part.Parent.Name) then

print("Found player!")

print(part.Parent.Name)

person = part.Parent

end

end

end

if person == nil then

local region = Region3.new(Vector3.new(hrp.X - num, hrp.Y - num, hrp.Z - num), Vector3.new(hrp.X + num, hrp.Y + num, hrp.Z + num))

local parts = game.Workspace:FindPartsInRegion3(region)

for a, b in pairs(parts) do

if b.Name == ("HumanoidRootPart") then

print(b.Name)

person = b.Parent

end

end

else

return person()

end

if person ~= nil then

return person

end

end

  

while true do

if script.Parent.AttackingPlayer.Value == "" then

print("Searching...")

if searchforplayer() == nil then

while searchforplayer() == nil do

wait(0.1)

if searchforplayer() ~= nil then

script.Parent.AttackingPlayer.Value = searchforplayer().Name

script.Parent.Head["!Gui"].Frame.TextLabel.Visible = true

script.Parent.Humanoid.JumpPower = 48

script.Parent.Humanoid.Jump = true

wait(1)

script.Parent.Head["!Gui"].Frame.TextLabel.Visible = false

script.Parent.Humanoid.JumpPower = 0

break

end

end

end

end

local path = game:GetService("PathfindingService"):CreatePath()

if script.Parent.AttackingPlayer.Value ~= ("") then

local prs = game.Workspace:FindFirstChild(script.Parent.AttackingPlayer.Value)

end

if script.Parent.AttackingPlayer.Value ~= ("") then

event:Fire(script.Parent.AttackingPlayer.Value)

end

range = math.huge

path:ComputeAsync(script.Parent.HumanoidRootPart.Position, prs.HumanoidRootPart.Position)

local points = path:GetWaypoints()

local player = game.Workspace:FindFirstChild(script.Parent.AttackingPlayer.Value)

script.Parent.Parent.Points:ClearAllChildren()

for a, b in pairs(points) do

part = Instance.new("Part")

part.CanCollide = false

part.Size = Vector3.new(1,1,1)

part.Position = b.Position

part.Anchored = true

part.Transparency = 1

part.Parent = script.Parent.Parent.Points

end

if path.Status == Enum.PathStatus.Success then

  

for a, b in pairs(points) do

script.Parent.Humanoid:MoveTo(part.Position)

if b.Action == Enum.PathWaypointAction.Jump then

script.Parent.Humanoid.Jump = true

end

end

end

end

I get this error if I stand in front of the guy, or be around him. Any help?

2 answers

✓ Accepted answer

Using :FindFirstChild() does not always return something. Before calculating a path, check to see if prs exists.

if prs then
    -- Code for pathfinding
end

When you say that a variable is local, it only exists in the scope you define it. In other words, because you define local prs in the if block, prs does not exist outside of that if block! prs will never be a non-nil value. To fix this, specify that prs is local outside the if statement, in the same scope that you later use it:

	local prs
	if script.Parent.AttackingPlayer.Value ~= ("") then
		prs = game.Workspace:FindFirstChild(script.Parent.AttackingPlayer.Value)
	end

SaltyIceberg is correct that you must also check to see if prs is non-nil.

Some other problems with this script:

  • return person() will fail, since person is not a function. Right after that, you have if person ~= nil then return person end, which makes the return person() redundant (in addition to being incorrect). Remove the else return person() part.
  • You have if searchforplayer() == nil then followed by while searchforplayer() == nil then, but you can just remove the if staement (along with the corresponding end) since while will not run its code even once if the condition is false
  • You should try to avoid running functions (especially ones that are complicated) more than necessary. You can save the result of calling searchforplayer() to a variable so you can access the player's name:
if script.Parent.AttackingPlayer.Value == "" then
		print("Searching...")
		local player
		while true do
			player = searchforplayer()
			if player then break end
			wait(0.1)
		end
		script.Parent.AttackingPlayer.Value = player.Name
		script.Parent.Head["!Gui"].Frame.TextLabel.Visible = true
		script.Parent.Humanoid.JumpPower = 48
		script.Parent.Humanoid.Jump = true
		wait(1)
		script.Parent.Head["!Gui"].Frame.TextLabel.Visible = false
		script.Parent.Humanoid.JumpPower = 0
	end
  • if script.Parent.AttackingPlayer.Value ~= ("") then makes no sense because the code before it guarantees that AttackingPlayer will exist
  • range = math.huge could just be set once at the top of the script (where it currently says local range = 20)
  • You should assign AttackingPlayer to a local variable instead of saying script.Parent.AttackingPlayer every time
  • prs.HumanoidRootPart might not exist if the player (for instance) fell off the edge of the map; you should use FindFirstChild there
  • No point in having both prs and player both point to the player's character model (rename prs to player and remove the repetition)
  • When having the NPC follow the pathfinding result:
    • You don't want to use pairs, or else it'll attempt to follow the path out of order!
    • You don't have the script wait until the NPC actually gets to the checkpoint, you just tell it to start moving towards each checkpoint. You need to either have a loop where you wait until the NPC stops moving and/or gets close to its target.

Aside from the last point, I fixed the above in the following:

local ts = game:GetService("TweenService")
local event = Instance.new("BindableEvent")
event.Name = ("StartAttacking")
event.Parent = script.Parent.Parent
  
wait(5)

local attackingPlayer = script.Parent.AttackingPlayer  
attackingPlayer.Value = ""
  
local range = math.huge
  
local function searchforplayer()
	local ray = Ray.new(script.Parent.HumanoidRootPart.CFrame.Position, script.Parent.HumanoidRootPart.CFrame.LookVector * 500)
	local hrp = script.Parent.HumanoidRootPart.Position
	local num = 8
	local part = game.Workspace:FindPartOnRay(ray)
	local person = nil
	if part then
		if part.Parent:FindFirstChild("Humanoid") then
			if game.Players:FindFirstChild(part.Parent.Name) then
				print("Found player!")
				print(part.Parent.Name)
				person = part.Parent
			end
		end
	end
	if person == nil then
		local region = Region3.new(Vector3.new(hrp.X - num, hrp.Y - num, hrp.Z - num), Vector3.new(hrp.X + num, hrp.Y + num, hrp.Z + num))
		local parts = game.Workspace:FindPartsInRegion3(region)
		for a, b in pairs(parts) do
			if b.Name == ("HumanoidRootPart") then
				print(b.Name)
				person = b.Parent
			end
		end
	end
	if person then
		return person
	end
end
  
while true do
	if attackingPlayer.Value == "" then
		print("Searching...")
		local player
		while true do
			player = searchforplayer()
			if player then break end
			wait(0.1)
		end
		attackingPlayer.Value = player.Name
		script.Parent.Head["!Gui"].Frame.TextLabel.Visible = true
		script.Parent.Humanoid.JumpPower = 48
		script.Parent.Humanoid.Jump = true
		wait(1)
		script.Parent.Head["!Gui"].Frame.TextLabel.Visible = false
		script.Parent.Humanoid.JumpPower = 0
	end
	local path = game:GetService("PathfindingService"):CreatePath()
	local player = game.Workspace:FindFirstChild(attackingPlayer.Value)
	event:Fire(attackingPlayer.Value)
	local playerHRP = prs:FindFirstChild("HumanoidRootPart")
	if playerHRP then
		path:ComputeAsync(script.Parent.HumanoidRootPart.Position, playerHRP.Position)
		local points = path:GetWaypoints()
		script.Parent.Parent.Points:ClearAllChildren()
		for a, b in pairs(points) do
			part = Instance.new("Part")
			part.CanCollide = false
			part.Size = Vector3.new(1,1,1)
			part.Position = b.Position
			part.Anchored = true
			part.Transparency = 1
			part.Parent = script.Parent.Parent.Points
		end
		if path.Status == Enum.PathStatus.Success then
			for a, b in ipairs(points) do
				script.Parent.Humanoid:MoveTo(part.Position)
				if b.Action == Enum.PathWaypointAction.Jump then
					script.Parent.Humanoid.Jump = true
				end
			end
		end
	end
end

This discussion is preserved as it was. New answers, comments, and votes are closed.