-
Notifications
You must be signed in to change notification settings - Fork 398
Lua scripting
Calls from Lua to engine are not checked, they might crash if called incorrectly.
Lua script plugin provides an option to script using Lua using Luau library. It provides a new type of component, which points to a lua script file. This file is executed when a game starts. Each component has lua sandboxed - it means that all variables and function are not accessible from other components unless they are put in the global table _G
or accessed using entity.lua_script[idx]
- Download and install [Luau language server(https://marketplace.visualstudio.com/items?itemName=JohnnyMorganz.luau-lsp) for VS Code
- open
data
folder in VS Code - create VS Code workspace settings (
data/.vscode/settings.json
) - put following json there
{
"luau-lsp.types.definitionFiles": ["scripts/lumix.d.lua", "pipelines/lumix.d.lua"],
"luau-lsp.types.roblox": false
}
- create
.luaurc
indata\scripts\
and put following json there
{
"languageMode": "nonstrict",
"lint": { "*": true, "FunctionUnused": false },
"lintErrors": true,
"globals": ["expect"]
}
- typechecking should now work, you can test with following script:
function onInputEvent(event : InputEvent)
return event.some_prop
end
See Lua console plugin for example how to do plugins for editor in Lua.
Each script can contain function update(dt)
and this function is called each frame.
See API definition.
function LumixAPI.logError(msg)
function LumixAPI.instantiatePrefab(universe, position, prefab)
Example:
ext_prefab = -1
Editor.setPropertyType(this, "ext_prefab", Editor.RESOURCE_PROPERTY, "prefab")
-- alternative
-- local ext_prefab = LumixAPI.loadResource(LumixAPI.engine, "models/cube.fab", "prefab")
function start()
local s = 20
for i = 1, s do
for j = 1, s do
for k = 1, s do
local position = { i * 3, j * 3, k* 3 }
LumixAPI.instantiatePrefab(Lumix.main_universe, position, ext_prefab)
end
end
end
end
Components are directly exposed as properties of entity
See player.lua for real-world example.
-- e is entity
e.gui_rect.top_points = 50
-- is the same as
e.getComponent("gui_rect").top_points = 50
A new lua object is created every time component is accessed this way, so cache the component to avoid the performance hit
local rect = e.gui_rect
rect.top_points = 50
rect.top_relative = 0.5
You can access environments of other script like this:
local env = e.lua_script[script_index]
Every Vec3, color, decimal, integer and boolean property (you can see properties in the property grid in the editor) can be accessed from Lua. However name of a property is transformed in following way:
- convert to lowercase
- replace all nonalphanumeric characters with
_
,
For example:
-- property Fog color
-- "this" is current Entity accessible from lua
local e = this.universe:createEntity()
local c = e:createComponent("environment")
c.fog_color = {1, 0, 1}
Other than standard lua types there following types:
- Vec3 - a table with 3 numbers
- Quat - a table with 4 numbers
onInputEvent
function is called on every input event.
function onInputEvent(event)
if event.type == "button" then
if event.device.type == "keyboard" then
if event.key_id == LumixAPI.INPUT_KEYCODE_UP then
LumixAPI.logInfo("keyboard button event")
end
end
elseif event.type == "axis" then
if event.device.type == "mouse" then
yaw = yaw + event.x * -0.005;
pitch = pitch + event.y * -0.005;
end
end
end
If two entities with a physical component collide, onContact function is called in script on both of them:
function onContact(entity)
end
If a physical entity enters a trigger, onTrigger function is called in script on both of them:
function onTrigger(other_entity, touch_lost)
end
function onPathFinished() ...
Lua function onPathFinished is called on an entity which finished its path.
x = 0
checked = true
function onGUI()
-- button
if ImGui.Button("Test") then
LumixAPI.logError("Test clicked.")
end
-- drag float
local changed = false
changed, x = ImGui.DragFloat("Drag float", x)
if changed then
LumixAPI.logError("X changed, new value = " .. tostring(x))
end
-- checkbox
changed, checked = ImGui.Checkbox("Checkbox", checked)
if changed then
if checked then
LumixAPI.logError("Checkbox is checked")
else
LumixAPI.logError("Checkbox is unchecked")
end
end
end
Editor.createEntityEx
is a nice helper function to create entity, attach components and set properties in one call. It also create a record in editor's undo stack, so it can be undone/redone.
Editor.createEntityEx {
position = { 3 * i, 0, 0 },
model_instance = { Source = "models/shapes/cube.fbx" }
}
World.createEntityEx
has the same syntax and meaning as Editor.createEntityEx
, but but it does not create any record in editor's undo stack. It means World.createEntityEx
should only be called ingame, calling it in editor scripts might result in undefined behaviour. On the other hand Editor.createEntityEx
should not be called ingame, since Editor
might be nil if not run from Studio.
-- create grid of 7x120x7 cubes with box physics
for i = 1, 7 do
for j = 1, 120 do
for k = 1, 7 do
Lumix.main_world:createEntityEx {
position = { i * 3, j * 3, k * 3 },
model_instance = { source = "models/shapes/cube.fbx" },
rigid_actor = { dynamic = 1, box_geometry = { {} } }
}
end
end
end