Looping Function Producing Errors

I’m trying to make a guarding script that rotates you to the nearest player, however, when there is no other player with a ball to rotate to, it produces an error on every input.

local function Finder()
    local balls = {}
    local players = workspace.Players
        for i, v in pairs(players:GetDescendants()) do
            if (v:IsA("BasePart") and v.Name == "Ball") then
                table.insert(balls, v)
            end    
        end
        return balls
    end

local function GetBaller()

 

    local list = Finder()    
    local baller = nil
    local dist = 99999
    local temp = nil
    local human = nil
    local temp2 = nil
    local pos = Root.Position
    
    for i = 1, #list do
        temp2 = list[i]
        temp = temp2
        
        if (temp ~= nil) then
            local mag = (temp.Position - pos).magnitude
            
            if mag < dist then
                dist = mag
                baller = temp
            end
        end
    end
        return baller.Parent
    end

In order to avoid nil errors, how can I call these functions and then use them in:

    local baller = GetBaller()
    local ballerroot = baller.HumanoidRootPart

Which I call in Input functions. Without getting millions of nil errors that baller.Parent does not exist when there is no other player

1 Like

There are a few things you could do, for instance, checking if list is nil or not. This is because in your script you’re relying on list to have some sort of value. You could also implement pcalls for extra error guard if you would like. If I misunderstood anything your if you don’t understand what I’m suggesting, feel free to let me know :slight_smile:

Read more about pcalls here (although just making sure list isn’t empty should suffice)

Also in the future make sure to provide the errors that it produces!

2 Likes

Replace

return baller.Parent

with

if baller == nil then
	return nil
else
	return baller.Parent
end

(Just a check to make sure that baller isnt nil so that it does have a Parent property)

1 Like

This won’t necessarily work because from what I see, list is returning empty/nil, which would mean it would error at for i = 1, #list do temp2 = list[i] because the script is trying to look through the returned table, which is possibly, well, nothing.

1 Like

I also noticed that, if I was the programmer I would have done:

for i,v in pairs(list) do
	local mag = (v.Position - pos).magnitude
	if mag < dist then
		dist = mag
		baller = v
	end
end

(Would only go through the list if there is items in it)

Edit: I also don’t see the point for the temp2 variable.

2 Likes

As i see “Root” is not defined.

1 Like

I’ll read more about pcalls, thank you for that!

Root is defined outside of the function as

local Root = game.Players.LocalPlayer.Character:WaitForChild("HumanoidRootPart")

In the end, I was left with this:

local function GetBaller()

 

    local list = Finder()    
    local baller = nil
    local dist = 99999
    local temp = nil
    local human = nil
    local temp2 = nil
    local pos = Root.Position
    
   	for i,v in pairs(list) do
	local mag = (v.Position - pos).magnitude
		if mag < dist then
		dist = mag
		baller = v
		end
		
    end
	    if baller == nil then
			return nil
		else
			return baller.Parent
		end
end

The error I am now left with is: Workspace.SpaceHex.Guard:137: attempt to index nil with ‘HumanoidRootPart’

I just rewrote the whole thing (there looked to be quite a few unnecessary or unused variables)

local Root = game:GetService("Players").LocalPlayer.Character:WaitForChild("HumanoidRootPart")
local function GetClosest()
	local closest = {nil, math.huge}
	for i,v in pairs(game:GetService("Players"):GetPlayers()) do
		if v.Character ~= nil and v.Character:FindFirstChild("Ball") then
			if (Root.Position - v.Character.Ball.Position).Magnitude < closest[2] then
				closest = {v, (Root.Position - v.Character.Ball.Position).Magnitude}
			end
		end
	end
return closest[1]
end

(Depending on the location of the Ball , you may need to change the location on line 5.

1 Like

This can just be simplified to just this:

return baller and baller.Parent

For more information on how this works, read this article on conditional statements without the if keyword.

1 Like

Use

local plr = game.Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local Root = char:WaitForChild("HumanoidRootPart")
1 Like

I do understand how this works, I just use the other way to make it easier for potentially new programmers to understand.

1 Like

and in order to avoid the: attempt to call a nil value error - what would i replace:

	local baller = GetClosest()
	local ballerroot = baller.HumanoidRootPart

with?

baller.HumanoidRootPart may not run if there is no other valid players, in order to fix this I would do:

local ballerroot = GetClosest()
if ballerroot ~= nil then
	ballerroot = ballerroot.Character.HumanoidRootPart
	--put code for ballerroot here
end

I’m now getting the error HumanoidRootPart is not a valid member of Player, does GetClosest() get the player or it’s character?

Yes, get closest gets the player instead of the character.
I editted my last post to fix this issue

1 Like