PIXELFALLS
  • Docs
  • Hardware
  • News
  • Roadmap
  • Pricing
  • Schools
SchoolsHardwareTerms of ServicePrivacy Policy

© 2026 PIXELFALLS

Documentation

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 itLives for…Use when…
score = 0 in mainWhole gameSimple globals owned by main
title = "…" in a utility file (no local)Whole gameHelpers and shared values in non-node files
speed = 1 in a node (no local)That node typeOne value shared by every instance
local counter = 10That file or functionPrivate helpers; still one copy for the file
self.health = 100One node instanceHealth, speed, per-enemy timers
state.score = 0Whole gameScore, 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 local in 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 = 1 or a top-level local)
  • 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 → local inside the function
  • Cross-file shared updates → state. or NodeName.sharedField (not a bare global write from a node)