5. Objects and scripts
You now know everything needed to read a game script. This page puts it together: how a table becomes an object with functions of its own, and what each line of a script file is for.
Functions in tables
A table can hold functions, since functions are values:
This works for one door. For two doors the function is stuck, because it names door directly.
self
Give the function the table it should work on, as its first argument. By convention that argument is called self:
One function, any number of doors. Each call says which door it means.
The colon
Writing front.toggle(front) names the table twice. Lua has a shorthand for exactly this:
A colon does two things:
- In a call,
front:toggle()meansfront.toggle(front). The table before the colon is passed as the first argument. - In a definition,
function front:toggle()meansfunction front.toggle(self). An argument namedselfis added for you.
So the rule is short: a dot gets a value out of a table, a colon calls a function on it.
Mixing them up is the most common error in game scripts. entity.Destroy() calls the function without telling it which entity, and fails with a message about a bad argument or a nil value.
Reading a script file
Here is a complete script. Every line should now make sense.
local Spinner = {}makes an empty table. The script is this table.Spinner.Fields = { ... }adds a record to it, listing the values the inspector should show.function Spinner:OnStart()adds a function to the table. The colon gives it aself.return Spinnerhands the table to the engine. A script file must end this way.
The engine then does the rest. For each entity that has this script, it makes a fresh table, the instance, that can use every function in Spinner. It calls OnStart once and OnUpdate every frame, passing the instance as self.
So inside these functions:
selfis this entity's own instance. Ten entities with the script have ten separateselftables.self.Entityis the entity the script is on. The engine puts it there.self.Speedis the field's value for this entity: 90, or whatever was typed in the inspector.self.Turnsis a value the script made up for itself inOnStart. Anything you store onselfis still there next frame.
A local variable inside OnUpdate is gone when the function returns. A value on self lasts as long as the entity does. That is how a script remembers things.
Your own functions
Add functions of your own the same way, and call them with self::
Another script can call these on any entity that has the script:
GetScript gives that entity's instance, or nil when it has no such script, which is why the if is there.
Sharing code between scripts
A file can return a table of helper functions, and other scripts load it with require:
These helpers use a dot, not a colon. Roll does not act on a particular thing, so it needs no self.
What local at the top of a file means
A local outside every function belongs to the file. All the entities using the script share it:
Use self for what belongs to one entity, and a file-level local for what all of them share.
Try it
- Write a
Countertable with acountand two functions written with a colon,AddandReport. Call each a few times. - Take the
Spinnerscript above and add aReversefunction that flips the sign ofself.Speed. - Read
Player.luafrom the tutorial. Say for each line whether it uses a dot or a colon, and why.
Next: mistakes everyone makes.