Skip to content

Scripts in the editor

Gameplay is written in scripts, in Luau or AngelScript. Both see the same engine API; they differ in syntax. The examples in these pages show both: pick a language once and the tabs follow it.

Write a game’s scripts in one language. A game run uses one script language: the first script to load decides it, and scripts in the other language stay off (the Console says so).

  • Behavior: belongs to an entity, through its Script component. Most gameplay lives here: a coin that spins, a door that opens, a player that moves.
  • Level: one per scene, for what concerns the whole scene: spawning, win conditions, timing. Its class is always named Level.
  • Game: one per game, running from start to quit, across scene changes: menus, lives, scores, which level comes next. Its class is always named Game.

In the Assets panel, right-click and choose New, then Scripts, then the language and the kind: Luau Behavior, AngelScript Level and so on. The File menu has the same list, and opens the new script.

The new script is named NewBehavior (or NewLevel, NewGame): rename it in the Assets panel. A behavior’s class takes its name from the asset’s name when it is created. The script’s file is in the project’s Sources/ folder (.luau or .as); importing a .luau or .as file adds one too.

A new behavior moves its entity slowly along X, to show that it runs (the starter’s comments are left out here):

NewBehavior = {}
NewBehavior.__index = NewBehavior
function NewBehavior.new(entity)
local self = setmetatable({}, NewBehavior)
self.entity = entity
self.speed = 1.0
return self
end
function NewBehavior:onStart()
Log.info("NewBehavior started on " .. self.entity:name())
end
function NewBehavior:onUpdate(dt)
local p = self.entity:position()
self.entity:setPosition(p.x + self.speed * dt, p.y, p.z)
end
function NewBehavior:onDestroy()
end

Double-click a script to open it in the editor’s script page: a code editor with highlighting and completion from the engine’s API. The API button in the page’s toolbar opens a browser beside the code with everything scripts can call in that language, as a tree of types and their members. Search it with Find a type or a member, and double-click an entry to insert it at the cursor.

A behavior’s script page: the code, the problems list under it reporting that the class compiles, and the API browser open on the right.

The page checks the script a moment after you stop typing, and lists any problems under the code, each with its line and column and the message, and marks the lines. Choose a problem to move the cursor to it. Save (Ctrl+S) saves the script and cooks it. A script saved with errors does not replace the running one: the game keeps the last version that built until the errors are fixed.

You can also edit the file in Sources/ with another editor: the editor notices the change within about two seconds and cooks it. An open script page does not reload the file, so close it first; saving from the page would write over your changes.

  1. Select the entity, click + (Add a component) at the top of the inspector, and choose Script, under Scripting.
  2. In the Script component, click Add on its Behaviors list. In the new behavior’s Script field, pick the script, or drag the script from the Assets panel onto the field.

An entity can have several behaviors, and they run in the order listed. To reorder them, drag a behavior by its grip, or right-click it and choose Move up or Move down. Each behavior has:

  • Script, the script it runs.
  • Enabled, to turn it off without removing it.
  • Update Interval: seconds between onUpdate calls. 0, the default, is every frame; with a longer interval, dt is the time since the last call.
  • Its properties (below).
  • A scene’s Level script is set on the scene page. Select the scene’s own row at the top of the hierarchy, and the inspector shows the scene’s settings; set Level Script in the Scene Script section.
  • The Game script is set in Project > Project Settings…, in the Startup section, as Startup script.

When the game starts, the Game script’s launch() runs first, and then the default scene loads. A project with no default scene leaves it to the Game script to load the first one.

A behavior’s properties appear in the inspector, under the behavior, so each entity can set its own values while sharing the script.

Every field the constructor sets to a number, a boolean, a string or a Float3 is a property:

function Coin.new(entity)
local self = setmetatable({}, Coin)
self.entity = entity
self.spinSpeed = 3.0 -- a property
self.label = "Gold" -- a property
self.bob = Float3.new(0, 0.2, 0) -- a property
return self
end

When the script is cooked, the constructor runs without an entity (entity is nil) to find the properties, so keep it to setting fields. Every such field is listed, including ones you only use inside the script.

In a networked game, a list of field names in the class’s replicated field (Coin.replicated = { "label" }) keeps those properties the same on every machine (see Networking).

An error while a behavior runs turns that behavior off and logs it in the Console under Script: the script, the line and the message, then the entity, the behavior and the method that failed. The entity and its other behaviors carry on. In the Game tab, each error also shows as a notice. Saving a fixed version of the script starts the behavior again.

Behaviors run while the game plays in the Game tab, or while a scene page simulates. Save a behavior while it runs and it restarts with the new code: its fields start over, and its property values stay as set. For a Level or Game script, stop and play again.

To step through a script line by line, see Debugging scripts.