Skip to content

Lua scripting

Mikulas Florek edited this page May 14, 2016 · 150 revisions

Lua script plugin provides an option to script using Lua. 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 Engine.getEnvironment.

Update function

Each script can contain function update(dt) and this function is called each frame.

API

Engine

Global variables

  • Universe g_universe
  • Engine g_engine

All scenes are visible to script as global variables, each with prefix "g_scene_" and ends with the name of a plugin, e.g.:

  • g_scene_renderer
  • g_scene_animation
  • g_scene_audio
  • g_scene_physics
  • g_scene_lua_script

Properties

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:

  1. Remove all nonalphabetic characters,
  2. If a character is after nonalphabetic character in the source name, it is uppercase in the Lua name.

For example:

-- property Fog color
GlobalLight.setFogColor(g_scene_renderer, cmp, {1, 0, 1})
local color = GlobalLight.getFogColor(g_scene_renderer, cmp) -- color == {1, 0, 1}

Types

Other than standard lua types there is one more - Vec3. It is just table with three numbers.

Functions

  • Entity Engine.createEntity(Universe universe)

  • void Engine.logError(string text)

  • void Engine.logInfo(string text)

  • Vec3 Engine.multVecQuat(Vec3 vec, Vec3 axis, number angle)

  • void Engine.setEntityPosition(Universe univ, Entity entity, Vec3 position)

  • Vec3 Engine.getEntityPosition(Universe univ, Entity entity)

  • void Engine.setEntityRotation(Universe univ, Entity entity, Vec3 axis, number angle)

  • void Engine.setEntityLocalRotation(Universe univ, Entity entity, Vec3 axis, number angle)

  • Component Engine.createComponent(Scene scene, string type, Entity entity)

  • void Engine.destroyComponent(Scene scene, string type, Component component)

  • Component Engine.getRenderable(Scene scene, Entity entity)

  • Table Engine.getEnvironment(Scene scene, Entity entity, number script_index) #620

  • Entity Engine.createEntityEx(Engine engine, Universe universe, Table entity_description)

Usage:

Engine.createEntityEx(g_engine, g_universe, {
    renderable = { Source = "models/utils/cube/cube.msh" },
    position = {6, 5, 5}
})

Input system

Constants

  • Engine.INPUT_TYPE_DOWN
  • Engine.INPUT_TYPE_PRESSED
  • Engine.INPUT_TYPE_MOUSE_X
  • Engine.INPUT_TYPE_MOUSE_Y
  • Engine.INPUT_TYPE_LTHUMB_X
  • Engine.INPUT_TYPE_LTHUMB_Y
  • Engine.INPUT_TYPE_RTHUMB_X
  • Engine.INPUT_TYPE_RTHUMB_Y
  • Engine.INPUT_TYPE_RTRIGGER
  • Engine.INPUT_TYPE_LTRIGGER

Functions

  • number Engine.getInputActionValue(Engine engine, number action)
  • void Engine.addInputAction(Engine engine, number action, number type, number key)

Usage

local LEFT_ACTION = 0
function init()
	cmp = Engine.createComponent(g_scene_physics, "physical_controller", this)
	Engine.addInputAction(g_engine, LEFT_ACTION, Engine.INPUT_TYPE_PRESSED, string.byte("A"), -1)
end

function update(dt)
	local speed = 1
	if Engine.getInputActionValue(g_engine, LEFT_ACTION) > 0 then
		local v = Engine.multVecQuat({-speed, 0, 0}, {0, 1, 0}, yaw)
		Physics.moveController(g_scene_physics, cmp, v, dt)
	end
end

Physics

  • void Physics.moveController(Scene scene, Component cmp, Vec3 velocity, number time_delta)
  • number Physics.getActorSpeed(Scene scene, Component cmp)
  • Component Physics.getActorComponent(Scene scene, Entity entity)
  • void Physics.putToSleep(Scene scene, Component component)
  • void Physics.applyForceToActor(Scene scene, Component component, Vec3 force)
  • Entity Physics.raycast(Scene scene, Vec3 origin, Vec3 dir)

If two entities with a physical component collide, onContact function is called in script on both of them:

function onContact(entity)
  API_logError("not implemented - onContact(" .. entity .. ")")
end

Audio

  • SoundHandle Audio.playSound(Scene scene, Entity entity, string clip_name, bool is_3d)
  • void Audio.setSoundVolume(Scene scene, SoundHandle sound_id, number volume)
  • void Audio.setEcho(IScene* scene, SoundHandle sound, number wet_dry_mix, number feedback, number left_delay, number right_delay)

Renderer

  • string Renderer.getCameraSlot(Camera component)
  • Camera Renderer.getCameraComponent(Entity entity)
  • Renderable Renderer.getRenderableComponent(Entity entity)
  • void Renderer.addDebugCross(Vec3 center, number size, number rgba_color, number life)
  • Material Renderer.getTerrainMaterial(Terrain component)
  • Texture Renderer.getMaterialTexture(Material material, number texture_index)
  • void Renderer.setRenderableMaterial(Scene scene, Renderable component, number material_index, string path)
  • void Renderer.setRenderablePath(Scene scene, Renderable component, string path)

Navigation

  • bool Navigation.generateNavmesh()
  • void navigate(Entity entity, Vec3 destination, number speed)
  • void debugDrawCompactHeightfield()
  • void debugDrawNavmesh()
  • void debugDrawHeightfield()
  • void debugDrawPaths()
  • void debugDrawContours()
  • number getPolygonCount()
  • void generateTile(number x, number y, bool keep_data)
  • bool save(string path)
  • bool load(string path)
  • void setGeneratorParams(number cell_size, number cell_height, number agent_radius, number agent_height, number walkable_angle, number max_climb)

Editor

ImGui

Following dear imgui functions are available in lua:

  • bool, number ImGui.DragFloat(string label, number value)

    The first returned value indicates whether value has been changed. The second returned value is the new value

  • bool ImGui.Button(string label)

    Returns true if the button has been clicked.

  • bool, bool ImGui.Checkbox(string label, bool checked)

     The first returned value indicates whether `checked` values has been changed. The second returned value is the new `checked`.
    

Usage

x = 0
checked = true
function onGUI()
    -- button
    if ImGui.Button("Test") then
        Engine.logError("Test clicked.")
    end

    -- drag float
    local changed = false
    changed, x = ImGui.DragFloat("Drag float", x)
    if changed then
        Engine.logError("X changed, new value = " .. tostring(x))
    end

    -- checkbox
    changed, checked = ImGui.Checkbox("Checkbox", checked)
    if changed then
        if checked then
            Engine.logError("Checkbox is checked")
        else
            Engine.logError("Checkbox is unchecked")
        end
    end
end

Importing asset

Editor.importAsset(Editor.import_asset_dialog, 
{
	output_dir = "D:\\Projects\\lumixengine_data\\models\\test\\yyy",
	srcs = {
		{ 
			src = "C:\\Users\\Miki\\Downloads\\Nature Pack\\Nature Pack\\Objects\\Birch_01.fbx" ,
			materials = {
				{ 
					matching = function(idx, name) return name:lower():find("branch") ~= nil end,
					import = true,
					shader = "leaves",
					alpha_cutout = true,
					textures = {
						{
							import = false,
							to_dds = true
						}
					},
				},
				{ 
					matching = function(idx, name) return name:lower():find("branch") == nil end,
					import = true,
					textures = {
						{
							import = true,
							to_dds = true,
							src = "c:\\path\\to\\texture.tga"
						}
					},
				},
			}
		}
	},
	create_billboard = false,
	scale = 0.01
})

Import all .obj from a directory (Windows only):

for filename in io.popen([[dir "C:\Users\Miki\Downloads\3D Nature pack\Models\" /b]]):lines() do 

	if string.sub(filename,-string.len(".obj"))==".obj" then

		Editor.importAsset(Editor.import_asset_dialog, 
		{
			output_dir = "C:\\projects\\lumixengine_data\\models\\test",
			lods = { 10, 100, -1, -1}, -- -1 == infinite distance
			srcs = {
				{ 
					src = [[C:\Users\Miki\Downloads\3D Nature pack\Models\]] .. filename,
					materials = {
						{ 
							matching = function(idx, name) return true end,
							import = true,
						},
					}
				}
			}
		})
		Engine.logError(filename .. " imported")
	end
end

Clone this wiki locally