Voxel Game Maker

Docs Quick code

Waiting, timing and tasks

wait, game time, wait_until, and running several things at once with run_async, every and after.

#wait

wait(2)                       -- pause this code for 2 seconds
wait(0)                       -- pause until the next frame
self.move(0, 0, 5, 1)         -- glide 5 tiles over 1 s, and wait until it arrives
self.move(0, 0, 5, 1, false)  -- the same glide, but carry on at once
  • wait() pauses only this code; the player, other scripts and the world keep going.
  • It works anywhere — in loops, inside your own functions, deep in a chain of calls — and the code carries on exactly where it was.
  • When a Code node finishes, its script goes on to the next node.
  • One run at a time: while a script is still running on an object (paused in a wait(), a glide or a Wait node), pressing E again — or its timer coming round — doesn't start a second copy.
  • Code stops if its object is removed, and when the player leaves the level.
  • Code in a dialogue runs all at once: waits are skipped there.

#Game time

Function Gives
dt() Seconds since the last frame (about 0.016 at 60 frames a second).
time() Seconds since the level started (game time — it stops while the game is paused).
frame() How many frames since the level started.

Use dt() for movement and cooldowns that run at the same speed on every computer:

local speed = 4          -- tiles per second
local cooldown = 0
while true do
  cooldown -= dt()
  if key_down("Q") and cooldown <= 0 then
    self.move(0, 0, -1, 0.2, false)
    cooldown = 0.5       -- at most twice a second
  end
  wait(0)
end

The time of day is separate: hour(), set_hour(h), is_night(), day(); and on-screen countdowns are start_timer(name, seconds), time_left(name).

#wait_until

wait_until(function() return switch_on("bridge_down") end)
popup("The bridge is down!")

-- With a time limit: gives false if it ran out first.
if not wait_until(function() return self.distance(player) < 2 end, 10) then
  popup("You took too long")
end

It checks every frame.

#Running things at the same time

Usually code does one thing after another. A task is code that runs alongside — its own waits don't hold up the rest:

Function Does
run_async(fn, …) Starts fn now, alongside this code (extra values go to fn).
every(seconds, fn) Calls fn every few seconds (the first time after seconds).
after(seconds, fn) Calls fn once, seconds from now.
cancel(task) Stops one of these.
task_running(task) true while it hasn't finished or been cancelled.

Each gives back a task to cancel later.

-- A lamp that blinks while the code below does other things.
local blink = every(0.5, function()
  self.hidden = not self.hidden
end)

-- A bomb: tick, tick, boom.
after(3, function()
  particles("explosion", 2)
  shake(0.3)
  self.remove()
end)

-- Two things moving at once.
run_async(function() object("door_left").move(-1, 0, 0, 1) end)
object("door_right").move(1, 0, 0, 1)

wait(5)
cancel(blink)

Tasks belong to the object whose code started them: they stop when it's removed, and all of them stop when the player leaves the level.

#Asking the player

local pick = choice("Buy the sword for 10 coins?", ["Yes", "No"])
if pick == "Yes" and money_count() >= 10 then
  take("Coin", 10)
  give("Sword")
end

choice(question, options) shows the choices, waits for the pick and gives its text. (In a dialogue, where code can't wait, use a Choice node instead; there choice() gives "".)