Variable Scope
PIXELFALLS Lua has a few places data can live. Choose based on who should see it and how many copies you need.
At a glance
| How you write it | Lives for… | Use when… |
|---|---|---|
score = 0 in main | Whole game | Simple globals owned by main |
title = "…" in a utility file (no local) | Whole game | Helpers and shared values in non-node files |
speed = 1 in a node (no local) | That node type | One value shared by every instance |
local counter = 10 | That file or function | Private helpers; still one copy for the file |
self.health = 100 | One node instance | Health, speed, per-enemy timers |
state.score = 0 | Whole game | Score, flags, data main and nodes both update |
Globals in main
In main, an assignment without local creates a global:
-- main score = 0 function update() score = score + 1 end
Node scripts can read main globals. When both main and nodes need to change the same value, prefer state (below) so writes stay on one shared table.
Utility files (non-node)
Other code files that are not marked as nodes are helper scripts. They are not a second main: they do not get game init / update / draw.
Bare names in a utility file still become globals — the same pool as main. Anything can read them by the plain name:
-- main score = 0
-- gui.lua (not a node) title = "My Game"
-- anywhere (main, gui, or a node) drawText(title, 1, 1, 7, 1) drawText("Score: " .. score, 1, 8, 7, 1)
From your point of view, title and score look the same: both are globals. It does not matter which file defined them.
Watch outs:
- Prefer clear names so two files do not both set the same global (last write wins).
- A top-level
localin a utility file stays private to that file. - If the file were a node, bare
title = …would live on that node type (e.g.gui.title), not as a free global.
Variables in a node file
Node files run in their own module environment.
Without local — one value shared by every instance of that node type:
-- Enemy.lua (node) speed = 1 -- all Enemy instances share this function update(self) self.x = self.x + speed end
If you spawn three enemies, they all move using the same speed. Change speed once and every Enemy picks it up.
With local — private to that file (or to one function). A top-level local is still one value for the whole node type, not one per instance:
-- Enemy.lua (node) local counter = 10 -- private to this file; still shared by all Enemy instances function update(self) local step = 1 -- only this update call counter = counter + step end
Per-instance data ()
Use self for data that belongs to one spawned node:
function init(self) self.health = 100 self.timer = 60 end function update(self) self.timer = self.timer - 1 if self.timer <= 0 then destroy(self) end end
Each spawn(Enemy) gets its own health and timer. See Nodes.
Shared game state ()
The runtime provides a built-in global table state for values main and nodes both read and write:
-- main function init() state.score = 0 end function drawUI() drawText("Score: " .. state.score, 1, 1, 7, 1) end
-- Coin.lua (node) function update(self) -- when collected: state.score = state.score + 10 destroy(self) end
Initialize fields in main init() when you can. See also PIXELFALLS Lua Sugar.
Accessing from other files
Node reading a main global
Nodes can read globals defined in main:
-- main difficulty = 2
-- Enemy.lua (node) function init(self) self.speed = 1 * difficulty end
To change that value from a node, prefer state.difficulty instead of assigning difficulty = … in the node file (a bare write there stays on the node type, and does not update main’s global).
Other code reading a node’s shared variable
A top-level assignment without local lives on the node’s class table (the same global as the node name). Main or another file can read or write it:
-- Enemy.lua (node) speed = 1
-- main function update() -- bump difficulty: every Enemy moves faster if score >= 100 then Enemy.speed = 2 end end function drawUI() drawText("Enemy speed: " .. Enemy.speed, 1, 1, 7, 1) end
A top-level local in the node file is private — other files cannot see it.
Other code reading instance data (self)
self is only the current instance inside that node’s methods. Elsewhere you use a reference returned by spawn, or found via queries:
-- main player = spawn(Player, 64, 64) function drawUI() drawText("HP: " .. player.health, 1, 1, 7, 1) end
-- Bullet.lua (node) function update(self) local hits = self:getCollidedEntities() for i = 1, #hits do local other = hits[i] if other.health then other.health = other.health - 1 end end end
Quick tips
- Per enemy / bullet / pickup →
self. - Shared by all instances of one node type → top-level in the node file (
speed = 1or a top-levellocal) - Score, level, story flags →
state. - Helpers in non-node files → bare names are globals (like main); use clear names to avoid clashes
- Temps and helpers →
localinside the function - Cross-file shared updates →
state.orNodeName.sharedField(not a bare global write from a node)