Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
2

Why do we need an if statement in this code?

Asked by 5 years ago

I made a kill brick script as I am just getting started in scripting. I have a few problems...

Why does this work perfectly?:

brick = script.Parent

function onTouched(hit)
    if hit.Parent:FindFirstChild("Humanoid") then
        hit.Parent.Humanoid.Health = 0
    end
end

brick.Touched:Connect(onTouched)

However, this:

brick = script.Parent

function onTouched(hit)
    hit.Parent:FindFirstChild("Humanoid").Health = 0
end

brick.Touched:Connect(onTouched)

Outputs an error:

Workspace.Part.Script:4: attempt to index a nil value

Also, when I don't add a ":FindFirstChild":

brick = script.Parent

function onTouched(hit)
    hit.Parent.Humanoid.Health = 0
end

brick.Touched:Connect(onTouched)

This outputs the following error:

Humanoid is not a valid member of Workspace

Could someone please explain why this is occurring?

I am also confused as to why while having the error, the script still works perfectly fine, it does the job that I expected

0
Hit could be a different object than a part of a character, like a part of a model. KDarren12 705 — 5y
0
it checks if a humanoid exists before running code that requires the humanoid to exist, hence avoiding an error theking48989987 2147 — 5y
0
But my question is, why does the other code that DOESN'T check if a humanoid exist work (while giving you an error)? c0deflex 12 — 5y

2 answers

Log in to vote
1
Answered by 5 years ago

That is because, not only players can touch the brick, but bricks can touch bricks. If you want to change a property of the humanoid of a player when they touch, you first gotta check if the thing that touched the brick really is a player.

brick = script.Parent

function onTouched(hit)
    if hit.Parent:FindFirstChild("Humanoid") then
        hit.Parent.Humanoid.Health = 0
    end
end

brick.Touched:Connect(onTouched)

Lets decompile the script a little.

The function onTouched runs everytime something touches the brick.

That means if the brick touches the ground it will run the code inside the function.

All player characters in roblox have a humanoid. "hit" is the object that hit the brick.

If the character of a player were to touch the brick, you would do hit.Parent to get to the character because either the legs, arms, torso, head, cosmetics etc. has to touch the brick.

And those objects are a child of the character.

So if my leg touches the brick, we would find the parent of the leg, which is the character. Next that comes up is FindFirstChild.

When you do FindFirstChild, you're trying to find a child of a object that is named what you put inside the brackets. As in the example, FindFirstChild("Humanoid") will try to find an object named "Humanoid".

If FindFirstChild("Humanoid") is not successful of finding an object named "Humanoid", the it will return nil, meaning it is "nothing".

The if statement checks if there is something that is called "Humanoid" inside of the parent of the part.

If there is nothing called "Humanoid", in other words, if its nil, it will not run the code that is inside that if statement, but run past it.

If there is something named "Humanoid", then it will run the code inside the if statement.

So why does the other scripts error?

Thats because you're trying to change the property of an object that does not exist.

As mentioned before, the if statement skips the code inside of it if the object is nil, but if you jump right to hit.Parent:FindFirstChild("Humanoid").Health = 0, then that means you're not checking if the object is existing.

Say the baseplate touches your brick and you write:

hit.Parent:FindFirstChild("Humanoid").Health = 0

Okay, first baseplate, then we go up to workspace and then we try to find an object called "Humanoid" in workspace. Oh, wait! Humanoid is not existing! But why is the player trying to change the health of "Nil"? He should have checked if the object existed before changing the value! And thats when the game complains.

It Says: "I can't change health of something that does not exist!"

I hope this made you undestand a little better why you'll require those extra lines of code. Please call me out if I'm totally wrong of something, if there is something I should add, or if you got more questions.

I guess that's all I have to say.

Happy scripting!

Waterfox

0
Thanks! This is exactly what I was looking for, I appreciate that you took your time to explain this to me. You broke it down in a very detailed yet simple manner, very beginner-friendly. Again, thanks! c0deflex 12 — 5y
0
Glad you understood. (: TheWaterFoox 255 — 5y
Ad
Log in to vote
0
Answered by 5 years ago
Edited 5 years ago

.Touched is likely firing for other parts touching your part, such as the baseplate. Naturally, the baseplate.Parent doesn't have a humanoid, so searching for a humanoid in it (hit.Parent:FindFirstChild("Humanoid")) returns nil. The "nil value" is Health, because Health is not a property of nil. In short, you're trying to modify a property of nothing.

Your third is breaking because of the same problem (the part touching the baseplate, which doesn't have a humanoid), but demonstrates the difference between :FindFirstChild and a direct index, hit.Parent.Humanoid, being that the script will throw an error if you try to directly index something that doesn't exist. So instead of complaining about the "nil value" - the missing property - it's complaining about "Humanoid" not existing in the workspace.

Your first script works because you're only making changes if you're sure whatever you try to index actually exists, by first checking if hit.Parent:FindFirstChild("Humanoid") before you actually index the humanoid (hit.Parent.Humanoid.Health = 0).

https://developer.roblox.com/en-us/api-reference/function/Instance/FindFirstChild https://developer.roblox.com/en-us/articles/Nil

Answer this question