Scripting basics
KHIM games are scripted in Luau, the fast, safe language Roblox made from Lua, with KHIM's own small API on top. If you have written any Lua, JavaScript or Python, you'll read it straight away.
Three kinds of script
| Kind | Runs on | Use it for |
|---|---|---|
| Script | The game server - once | The game itself: health, coins, scores, rounds, doors, anything that matters |
| ClientScript | Every player's device - once each | Input, UI, the camera, effects only one player sees |
| Module | Wherever it is required | Code and settings shared by several scripts |
Add one with Insert Object (right-click a row in the Hierarchy) or the top bar's Insert menu. Double-click it to open it.
Where a script sits decides whether it runs:
- A Script runs anywhere except StorageService and UI. Put game logic in ServerService, where players never see it, or inside the part it controls.
- A ClientScript runs on every player unless it sits in ServerService or StorageService. Put it in ClientService, or inside the UI it drives.
- A Module runs the first time something
requires it. Shared ones go in ReplicationService (sharedin scripts).
KHIM Engine dims a script that won't run where it is, and its tooltip says why.
Your first script
Insert a Part, then right-click it in the Hierarchy > Insert Object > Script. Open the script and type:
local part = script.parent -- the part this script is in
part.touched:connect(function(hit)
local player = players.fromPart(hit)
if player then
print(player.name .. " touched me!")
part.color = rgb(255, 80, 80)
end
end)Press F5, walk into the part: it turns red and the Console says who touched it.
Three rules cover the whole API
- Members are camelCase:
part.position,player.walkSpeed,button.clicked. - Modules use a dot, objects use a colon:
net.send(...),players.all()- butpart:tween(...),folder:find("Coin"). - A choice between a few options is a string:
part.shape = "Ball",label.textAlign = "Center",input.onKey("E", fn).
Finding things
Everything in the world is an object with a name, a parent and children:
local door = world.Door -- a child by name
local lamp = world.House.Kitchen.Lamp -- deeper
local tree = world:find("Big Tree") -- names with spaces
local shop = world:waitFor("Shop") -- waits until it exists
local config = require(shared.Config) -- a Module in ReplicationServiceworld | The World container: every part players see |
shared | ReplicationService |
game.ServerService, game.StorageService, game.ClientService | The other containers |
script | This script; script.parent is what it is in |
players.me | In a ClientScript: the player whose device it is |
find(name) returns nil when there is nothing by that name; waitFor(name) waits for it (and warns after 5 seconds). Use waitFor in ClientScripts, where the world arrives a piece at a time.
Events
Things that happen are events. Connect a function to one and it runs every time:
local connection = part.touched:connect(function(hit) print("touched by", hit.name) end)
connection:disconnect() -- stop listening
part.touched:once(function(hit) print("only the first time") end)
local hit = part.touched:wait() -- wait for the next time, then go onCommon ones: players.joined, players.left, part.touched, button.clicked, prompt.triggered, player.died, game.frame (every frame, with the time since the last).
Waiting and time
task.wait(2) -- wait 2 seconds (without freezing the game)
task.spawn(function() print("alongside") end) -- run something alongside
task.delay(5, function() print("later") end) -- run something in 5 seconds
print(time()) -- seconds since the game startedLoops need a wait
A script that runs for more than one second without waiting is stopped. Every while true do loop needs a task.wait() inside it.
Values
local spot = vec3(0, 10, 0) -- a position or direction
local red = rgb(255, 0, 0) -- a colour, 0-255 (or rgb("#ff0000"))
local sky = hsv(0.6, 0.5, 1) -- a colour from hue, saturation, value (0-1)
local where = transform.lookAt(vec3(0, 5, 10), vec3(0, 0, 0)) -- a position and a facing
local size = dim(0.5, 0, 0, 40) -- UI: half the width, 40 points highSee Value types.
Making objects
local ball = new("Part")
ball.shape = "Ball"
ball.size = vec3(2, 2, 2)
ball.position = vec3(0, 20, 0)
ball.anchored = false
ball.parent = world -- nothing appears until it has a parent
local copy = world.Tree:clone()
copy.parent = world
ball:destroy() -- gone, with everything inside it
ball:destroyAfter(5) -- gone in 5 secondsnew(className, parent) takes the parent as a second argument too.
Moving things smoothly
local door = world.Door
door:tween({position = door.position + vec3(0, 8, 0)}, 1) -- up 8 units over 1 second
door:tween({color = rgb(0, 255, 0), transparency = 0.5}, {time = 2, style = "Bounce"})Parts, UI objects, Lighting and the camera all tween. Options: time, style ("Linear", "Sine", "Quad", "Cubic", "Quart", "Back", "Bounce", "Elastic"), direction ("In", "Out", "InOut"), repeats (-1 forever), reverses, delay. A tween returns an object with completed and cancel().
Modules
A Module returns a value - usually a table - and every require of it gets the same one:
-- Module "Config" in ReplicationService
return {
startingCoins = 50,
swordDamage = 20,
}-- any Script or ClientScript
local Config = require(shared.Config)
print(Config.startingCoins)A Module runs once per server and once per player's device.
The editor helps
- Suggestions as you type: after
.and:it lists what fits there -players.listsjoined,left,all...; insideplayers.joined:connect(function(player),player.lists a player's members. Ctrl Space asks anywhere. - Snippets: type
touched,savedataorwhileloopat the start of a line - see Snippets. - Hover a name to see its type and what it does.
- Mistakes are underlined as you type, with a "did you mean":
'pirnt' is not defined; did you mean print?. A misspelt member at run time says it too:postion is not a valid member of Part; did you mean position?. - F12 on
world.Door.Hingeselects that Hinge in the Hierarchy.
Roblox names work too
If you know Roblox, its names still run: game:GetService("Players"), Instance.new("Part"), Vector3.new, part.Position, :Connect, FindFirstChild, RemoteEvent and so on. The docs use KHIM's names; Coming from Roblox has the table.
Next
- Server and client - the one thing to get right.
- Players and characters and Parts and objects.