Roblox EP2 Your first Luau: colour pads, lava floors and floors that vanish
Write your first Luau in Roblox Studio. Script, Touched, Humanoid and debounce through three examples every real obby uses, every line explained.
- Roblox code runs on events. Touched fires when something touches a part, and the function you connected runs
- Always check that the toucher is a real character, by finding a Humanoid, before doing anything
- Touched fires dozens of times for one step, so you need a debounce to stop code repeating
In EP1 we built a scene you can walk and jump through, but nothing moves. This episode writes your first code, through three examples every obby needs, with every line explained. No programming experience needed.
Adding your first Script
- Make a new Part, tick Anchored, name it
ColorPad - In Explorer, hover over
ColorPad; a + button appears. Click it and choose Script - Studio opens the code editor with one line already there:
print("Hello world!")
- Press Play and look at the Output panel:
Hello world!appears
print writes a message to Output. You will use it constantly to see how far your code got.
A Script inside a Part runs by itself when the game starts, and knows what it sits in through script.Parent.
Example 1: change colour when stepped on
Delete that line and type this instead:
local pad = script.Parent
pad.Touched:Connect(function(otherPart)
local humanoid = otherPart.Parent:FindFirstChildWhichIsA("Humanoid")
if humanoid then
pad.BrickColor = BrickColor.random()
end
end)
Line by line:
local pad = script.Parentmakes a variable calledpadholding the Part this script is inside.localmeans the variable exists only in this filepad.Touchedis an event that fires every time something touchespad:Connect(function(otherPart) ... end)connects a function to the event. Every touch runs it, passingotherPart, the part that touchedotherPart.Parent:FindFirstChildWhichIsA("Humanoid"): the toucher is a foot or leg; the whole character is itsParent, and every character contains a Humanoid. Finding one means a real character touched, not a ball or rock rolling inif humanoid then ... endacts only when one was foundpad.BrickColor = BrickColor.random()picks a random colour
Press Play and step on it; the colour changes.
Most Roblox code has this shape: wait for an event → check it is what you care about → act.
First problem: Touched fires a lot
Add this as the first line inside the function:
print("touched by", otherPart.Name)
Press Play, walk on and stand still. Output floods with dozens of lines, because the left foot, right foot and each leg segment touch separately, and touch again with every tiny movement. The colour flickers too fast to see.
The fix is called a debounce: a variable that says “busy, don’t repeat”.
local pad = script.Parent
local cooling = false
pad.Touched:Connect(function(otherPart)
if cooling then
return
end
local humanoid = otherPart.Parent:FindFirstChildWhichIsA("Humanoid")
if not humanoid then
return
end
cooling = true
pad.Color = Color3.fromRGB(255, 90, 90) -- red
task.wait(1)
pad.Color = Color3.fromRGB(90, 200, 120) -- green
cooling = false
end)
coolingstartsfalseand becomestruewhile working. Any touch in between meetsif cooling then return endand leaves at oncereturnleaves the function right there; written this way instead of nesting severalifs, it reads more easilytask.wait(1)waits one secondColor3.fromRGB(r, g, b)sets a colour by red, green, blue, each 0 to 255- Text after
--is a comment: the program ignores it; it is there for people
Example 2: a lava floor
Every obby has floors that send you back. Make a new Part named Lava, tick Anchored, set Material to Neon and Color to orange-red in Properties, and add this Script:
local lava = script.Parent
lava.Touched:Connect(function(otherPart)
local humanoid = otherPart.Parent:FindFirstChildWhichIsA("Humanoid")
if humanoid then
humanoid.Health = 0
end
end)
humanoid.Health = 0 sets health to zero; the character falls and respawns at a spawn point. This one needs no debounce, because setting health to zero again and again has the same result.
To decide whether you need a debounce, ask: “if this ran ten times in a row, would the result differ from running once?” If yes, you need one.
Example 3: a floor that vanishes if you linger
A floor that fades away when stepped on, then comes back, makes players hurry. Make a Part named FadePad and add this Script:
local pad = script.Parent
local busy = false
pad.Touched:Connect(function(otherPart)
if busy then
return
end
if not otherPart.Parent:FindFirstChildWhichIsA("Humanoid") then
return
end
busy = true
for i = 1, 10 do
pad.Transparency = i / 10 -- fade 10% at a time
task.wait(0.1)
end
pad.CanCollide = false -- nothing to stand on now
task.wait(3)
pad.CanCollide = true
pad.Transparency = 0
busy = false
end)
for i = 1, 10 do ... endrepeats 10 times, withitaking 1, 2, 3 up to 10Transparency: 0 is solid, 1 is invisibleCanCollide = falsemakes the part non-solid; the character falls through- It fades for 1 second, stays gone for 3, then returns
Tune the numbers to taste; task.wait(0.05) fades twice as fast.
Reading errors
Change the line that finds the Humanoid in the lava script to this:
local humanoid = otherPart.Parent.Humanoid -- no FindFirstChild
When something that is not a character touches it, such as an unanchored ball rolling into it, Output shows red text along the lines of Humanoid is not a valid member of ..., because we demanded a Humanoid from something that has none.
If you see attempt to index nil with ..., you are using something that is nil (empty, not there), like trying to open a drawer in a cabinet that does not exist.
Both are fixed the same way: find it first, check it was found, then use it, which is exactly the FindFirstChildWhichIsA plus if humanoid then pattern we have used all along.
Try it in 10 minutes
- Build
ColorPadwith a debounce, and make it return to its original colour after 2 seconds - Put two or three
Lavaslabs between the steps from EP1 - Make
FadePada bridge over the lava, then press Play and try it
Common mistakes
- Not checking for a Humanoid, so a rolling ball or loose part triggers the code
- Forgetting a debounce where repeating changes the result
- Forgetting
busy = falseat the end, so it works only once per game - Putting the Script in the wrong place, so
script.Parentis not the part you meant
Next episode
We now have scripts scattered across parts, all running on the server. EP3 explains that a Roblox game has two sides, the server and each player’s device, why you must know which side your code runs on, and why that is the heart of stopping cheaters.
FAQ
Why task.wait and not wait?
The old wait still works, but Roblox now recommends task.wait, which is more precise and part of the newer task library. Many older articles and videos still use wait; swap it for task.wait when you see it.
What does red text in Output mean?
Your code hit an error. The message names the script and line number; click it and Studio jumps to that line. The beginner's most common error, attempt to index nil, is explained in this article.
Commands and settings were tested on sample systems. Try them on a test machine before production.