In this question, I will be focusing mainly on :FindFirstChild()
and :WaitForChild()
. Often I am confused and uncertain as to whether or not I should use one, or neither, of the listed methods. Because :FindFirstChild()
returns nil when the object is not found, I am sure that I should not use it like this:
local box = game.Workspace:FindFirstChild("Model").box
Because :FindFirstChild()
returns nil, the variable definition will error. If I am doing it that way, why not just do:
local box = game.Workspace.Model.box
I can see using :FindFirstChild()
if the name has spaces, but I could just do something like this:
local box = game.Workspace["Box Model"].box
If I want to use :FindFirstChild()
without it erroring, I end up needing to do checks all along the way like this:
local boxModel = game.Workspace:FindFirstChild("Box Model") if boxModel then local boxHolder = boxModel:FindFirstChild("Box Holder") if boxHolder then box = boxHolder:FindFirstChild("box") if box then -- code end end end
That method just seems extremely inefficient. Another thing I have done to be careful is this:
local players = game:GetService("Players") players.PlayerRemoving:Connect(function(player) local canSave = player;FindFirstChild("CanSave") if canSave and canSave.Value then -- canSave is a BoolValue --code end end
There must be a better or more efficient and intelligent way to go about using :FindFirstChild()
.
I have been told :WaitForChild()
is for the client when waiting for things that have not spawned in yet. This makes sense, until I talked to someone on the discord (this is the code that was in the discussion):
local text = script.Parent local players = game:GetService("Players") local player = players.LocalPlayer local contentProvider = game:GetService("ContentProvider") local loaded = player:WaitForChild("Loaded") local connection while contentProvider.RequestQueueSize > 0 and not loaded.Value do for i = 1, 3 do text.Text = "Loading"..string.rep(".",i) wait(.5) end end local backpackDisplay = player.PlayerGui.StatsGui.Backpack.Display require(backpackDisplay) text.Parent.Visible = false
The backpackDisplay was not working correctly and I was uncertain why because the loop should have waited till everything had loaded in. After asking on the ScriptingHelpers discord I was informed that RequestQueueSize
did not count GUI stuff, but only assets. In order to fix this the person recommended using :WaitForChild
, which made sense. I then became confused as to where I should place the :WaitForChild
. I tried doing this and it worked:
local text = script.Parent local players = game:GetService("Players") local player = players.LocalPlayer local contentProvider = game:GetService("ContentProvider") local loaded = player:WaitForChild("Loaded") local connection while contentProvider.RequestQueueSize > 0 and not loaded.Value do for i = 1, 3 do text.Text = "Loading"..string.rep(".",i) wait(.5) end end local backpackDisplay = player.PlayerGui:WaitForChild("StatsGui").Backpack.Display require(backpackDisplay) text.Parent.Visible = false
I went back and asked the guy who answered who answered my question originally and he said that was all that was needed. Why did I not need to do:
local backpackDisplay = player.PlayerGui:WaitForChild("StatsGui"):WaitForChild("Backpack"):WaitForChild("Display")
or, as one of the options I listed with the :WaitForChild()
, why not do this:
local statsGui = player.PlayerGui:WaitForChild("StatsGui") if statsGui then local backpack = statsGui:WaitForChild("Backpack") if backpack then local display = backpack:WaitForChild("Display") if display then require(display) end end end
All of these questions berate me whenever I am writing scripts involving objects, which as you may guess, is pretty much every time I script in Roblox Studio. Any help would be much appreciated. Thanks!
FindFirstChild
is only necessary when you want to confirm that an object actually exists. If you directly index it via .
, it will error. FindFirstChild
would just return nil. In your first example, you do
local box = game.Workspace:FindFirstChild("Model").box
This is rather pointless. Because you index box without any additional checks to verify Model exists, you are assuming that it will be there. The better way to write this is
local box = game.Workspace.ModelFindFirstChild("box")
The second example using brackets is fine, and its a valid point. Your third example can be simplified, although it is not recommended
local boxModel = game.Workspace:FindFirstChild("Box Model") if boxModel then local boxHolder = boxModel:FindFirstChild("Box Holder") if boxHolder then box = boxHolder:FindFirstChild("box") if box then -- code end end end
If you know the object exists but don't know when it will exist of you're afraid that it won't when you attempt to index, use WaitForChild
. If you are this unsure about an object existing at every stage, you can do one of two things.
1) Rewrite something else so that you don't run into such a large issue
2) Use the second recursive parameter of FindFirstChild
local boxModel = game.Workspace:FindFirstChild("Box Model") if boxModel then local box = boxModel:FindFirstChild("box", true) if box then --do code end end
I don't recommend this because you could either have multiple instances with the same name or have a massive model which could make this time-consuming.
As for WaitForChild
, up until recently, I would've only recommended that it be used on the server because the scripts load before ReplicatedStorage does. In a more recent update (i think this is what occurred), the player now loads before any scripts do. This changes a few things that I don't know a whole lot about yet, so take a look at the article here
Hope this answer explained some of what you were looking for!
I, myself am somewhat of a newbie when it comes to built in functions of Roblox Lua, but I think one of the purposes, or at least one of the ways I use :FindFirstChild() is when there is a bit a latency, or if I am waiting a set about of time after an event to do something, say damage a person with a sword after an animation has played, or checking if the player has a creator tag in them when they die: Ex1:
game.Players.PlayerAdded:Connect(function(plr) plr.CharacterAdded:Connect(function(char) local creator = plr:FindFirstChild("creator") if creator then if creator.Value and then local leaderstats = creator.Value:FindFirstChild("leaderstats") if leaderstats and leaderstats:FindFirstChild("points") then local points = leaderstats:FindFirstChild("points") points.Value = Points.Value + 1 end end end end) end)--the creator tag is an object value and the value of it is a plr object
Ex2:
--one script wait(2) local thing = Instance.new("Part") thing.Parent = workspace thing.Name = "brick" --another script local thing repeat thing = workspace:FindFirstChild("brick") until thing ~= nil--not needed but to prove a point
This brings me to the second usage of FindFirstChild, it allows you find the child of some object without throwing an error if it isn't there, say I have a typo on a bit of code like this :
local a = Instance.new("Part") a.Parent = workspace a.Name = "thing" if workspace.thkng then--throws an error end
alternatively, if I have a typo on a bit of code like this
local a = Instance.new("Part") a.Parent = workspace a.Name = "thing" if workspace:FindFirstChild("thkng") then--doesn't throw an error print("yay") else print("uh oh") end
In this aspect, it is superior to WaitForChild and the .as it doesn't infinitely wait for "thkng" and allows the rest of your script to go on undisturbed.
--if WaitForChild() is used without a timout argument local a = Instance.new("Part") a.Parent = workspace a.Name = "thing" if workspace:WaitForChild("thkng") then--waits forever and doesnt let the rest of the script run print("yay") else print("uh oh") end
However, In some areas, WaitForChild() is better, such as trying to get the humanoid of a player character in a local script;
local humanoid = game.Players.LocalPlayer.Character:WaitForChild("Humanoid")
or in the script i mentioned earlier on
--one script wait(2) local thing = Instance.new("Part") thing.Parent = workspace thing.Name = "brick" --another script local thing = workspace:WaitForChild("brick")
Locked by User#19524
This question has been locked to preserve its current state and prevent spam and unwanted comments and answers.
Why was this question closed?