Learn Roblox Scripting (Luau) from Zero
Scripting is what brings Roblox games to life. Every mechanic — from a kill brick to a complex combat system — is powered by Luau scripts. This tutorial takes you from zero coding knowledge to writing practical game scripts.
Set up your first server Script
Open a Baseplate in Studio and enable Explorer, Properties, and Output. Insert a Script into ServerScriptService for the first two examples. Leave its RunContext at the default Legacy value. Start a play test and check Output; editing code without starting a test does not run it.
For the touch examples, create an anchored Part in Workspace and insert a separate Script beneath that Part. Keep CanTouch enabled. A Script under a Part has that Part as script.Parent. Pasting the same touch code into ServerScriptService changes what Parent means and will fail.
These examples use server Scripts. LocalScripts handle client behavior in supported locations, while ModuleScripts return reusable code that another script requires. See Roblox’s script types and locations for the current placement rules.
Basics: Variables and Print
local playerName = "Alex"
local score = 100
local isAlive = true
print("Player:", playerName)
print("Score:", score)
For a deeper check of conditions, try the true/false and boolean exercises.
Functions
local function greetPlayer(name)
print("Welcome, " .. name .. "!")
end
greetPlayer("Alex") -- prints: Welcome, Alex!
Events — The Heart of Roblox Scripting
Roblox is event-driven. Things happen when players touch parts, click buttons, or join the game.
-- When a player touches a part
script.Parent.Touched:Connect(function(hit)
print(hit.Name .. " touched me!")
end)
5 Practical Scripts
Script 1: Kill Brick
script.Parent.Touched:Connect(function(hit)
local humanoid = hit.Parent:FindFirstChild("Humanoid")
if humanoid then
humanoid.Health = 0
end
end)
Script 2: Speed Boost Pad
Put this Script inside an anchored pad. One character gets one five-second boost at a time; another player can use the pad independently. It records the previous speed and only restores it if the speed still equals this boost. This is a small prototype: games with sprinting or multiple buffs need one movement system that owns the final speed.
local pad = script.Parent
local active = {}
local boostSpeed = 50
pad.Touched:Connect(function(hit)
local character = hit:FindFirstAncestorOfClass("Model")
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
if not humanoid or humanoid.Health <= 0 or active[humanoid] then
return
end
active[humanoid] = true
local previousSpeed = humanoid.WalkSpeed
humanoid.WalkSpeed = boostSpeed
task.delay(5, function()
if humanoid.Parent and humanoid.WalkSpeed == boostSpeed then
humanoid.WalkSpeed = previousSpeed
end
active[humanoid] = nil
end)
end)
Walk across the pad repeatedly during the five seconds. The first activation controls the timer; repeated body-part contacts do not schedule additional resets.
Script 3: Disappearing Platform
Use a new anchored Part with CanCollide enabled and Transparency set to zero. This platform disappears for everyone, so one shared debounce is appropriate. Roblox touch events can fire for multiple body parts; the flag prevents overlapping hide/show sequences.
local part = script.Parent
local busy = false
part.Touched:Connect(function(hit)
local character = hit:FindFirstAncestorOfClass("Model")
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
if not humanoid or humanoid.Health <= 0 or busy then
return
end
busy = true
task.wait(1)
part.Transparency = 1
part.CanCollide = false
task.wait(3)
part.Transparency = 0
part.CanCollide = true
busy = false
end)
Test with two players: both should see the same disappearing platform. For a deeper explanation, read Roblox’s debounce patterns.
Script 4: Coin Collector
First create a Script called Leaderstats in ServerScriptService. It creates a visible session-only coin count for each player. This example does not save progress between visits.
local Players = game:GetService("Players")
local function addStats(player)
if player:FindFirstChild("leaderstats") then return end
local stats = Instance.new("Folder")
stats.Name = "leaderstats"
local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Value = 0
coins.Parent = stats
stats.Parent = player
end
Players.PlayerAdded:Connect(addStats)
for _, player in Players:GetPlayers() do
addStats(player)
end
Then insert this separate Script inside an anchored coin Part. A coin is claimed once, globally; it is not a separate collectible for each player. Set the coin’s CanCollide property to false so it does not block the character.
local Players = game:GetService("Players")
local coin = script.Parent
local claimed = false
coin.Touched:Connect(function(hit)
if claimed then return end
local character = hit:FindFirstAncestorOfClass("Model")
local player = character and Players:GetPlayerFromCharacter(character)
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
if not player or not humanoid or humanoid.Health <= 0 then return end
local stats = player:FindFirstChild("leaderstats")
local coins = stats and stats:FindFirstChild("Coins")
if not coins or not coins:IsA("IntValue") then return end
claimed = true
coins.Value += 1
coin:Destroy()
end)
Confirm the score changes by exactly one when the coin disappears. Duplicate the coin to make a small collection course. Data persistence, purchases, and rewards supplied by clients require additional validation.
Script 5: A Shared Door with a Coin Requirement
Create an anchored door with CanCollide enabled and put this Script inside it. For a quick test, set the Leaderstats example’s starting Coins value to 10 before entering play mode. This gate checks a balance but does not spend coins. When a qualifying player opens it, everyone can pass during the three-second window. It is a shared-world prototype, not a secure per-player paid gate.
local Players = game:GetService("Players")
local door = script.Parent
local requiredCoins = 10
local busy = false
door.Touched:Connect(function(hit)
if busy then return end
local character = hit:FindFirstAncestorOfClass("Model")
local player = character and Players:GetPlayerFromCharacter(character)
local stats = player and player:FindFirstChild("leaderstats")
local coins = stats and stats:FindFirstChild("Coins")
if not coins or not coins:IsA("IntValue") or coins.Value < requiredCoins then
return
end
busy = true
door.Transparency = 0.5
door.CanCollide = false
task.wait(3)
door.Transparency = 0
door.CanCollide = true
busy = false
end)
Working in a larger project? Learn how to search code across all scripts before changing a mechanic.
Test before combining the examples
- No output: check Script location, RunContext, and whether a play test is running.
- Touched is missing: the Script is probably not directly under a BasePart. Check Explorer.
- A touch does nothing: check CanTouch, the character’s health, and any cooldown flag.
- Coins are missing: check the Leaderstats setup, exact capitalization, and Output errors.
- Only one player is affected: identify whether that is the intended per-character state or an accidental shared flag.
Test each mechanic alone, then run a multi-client Studio test. Check repeated contacts, two simultaneous players, respawning during a boost, and a player leaving. Save a backup before combining scripts; our Studio saving guide covers local and cloud copies.
Ready to add character motion? Follow our first Roblox animation exercise before connecting a clip to gameplay.
For a small progression project, build a session-only XP rank display and test its promotion thresholds.
A practical learning sequence
Start with variables and Output, then functions, events, object references, and tables. Change one constant in a working example, predict the result, and test it. Next, make one mechanic from a blank Script without copying. Move to client/server communication and persistence only after you can explain where your code runs and who owns each piece of state. Learning time depends on practice and project complexity.
Use Roblox’s event documentation and client/server security guide when expanding a prototype.
Skip the Coding — Use AI
If scripting isn't your thing, Obby can help draft Luau code from a description. Specify the Script location, expected behavior, and test cases; inspect the output and verify it in Studio before publishing.


