Lua ScriptingIntermediate

Cross-object interactions

Find nearby objects, inspect their transforms, apply impulses, handle triggers, and coordinate state between scripts.

Find another object at runtime

Object scripts can look up scene objects by UUID, exact name, name prefix, or object type. Spatial queries return UUIDs for overlapping physics bodies; resolve each UUID with gameObject.getObject(id) before reading its transform or calling methods on it.

MethodResult
getObject(uuid)One object API or nil
getObjectByName(name)The first exact-name match or nil
getObjectsByNamePrefix(prefix)An array of object APIs
getObjectsByType(type)An array of object APIs
sphereQuery(radius)UUIDs of physics bodies overlapping a sphere centered on this object
boxQuery(halfExtents)UUIDs of physics bodies overlapping a box centered on this object

Filter spatial results

Spatial queries return physics-body UUIDs, not names, types, or tags. Build a set from a name-prefix lookup when only a particular group should react.

Example: knock back nearby crates

This pattern fits a Ground Pound ability. Name the breakable rigid bodies with a shared prefix such as Ground Pound Crate, keep them dynamic, and call knockBackNearbyCrates() once when the character lands. If the controller already defines init(), merge the crate lookup into that function instead of defining a second one.

local GROUND_POUND_RADIUS = 1.5
local CRATE_NAME_PREFIX = "Ground Pound Crate"

local crateIds = {}

function init()
    local crates = gameObject.getObjectsByNamePrefix(CRATE_NAME_PREFIX)
    for _, crate in ipairs(crates) do
        crateIds[crate.id] = true
    end
end

function knockBackNearbyCrates()
    local playerPosition = gameObject.getPosition()
    local nearbyIds = gameObject.sphereQuery(GROUND_POUND_RADIUS)
    local hitIds = {}

    for _, id in ipairs(nearbyIds) do
        if crateIds[id] and not hitIds[id] then
            hitIds[id] = true

            local crate = gameObject.getObject(id)
            if crate then
                local cratePosition = crate.getPosition()
                local dx = cratePosition.x - playerPosition.x
                local dz = cratePosition.z - playerPosition.z
                local distance = math.sqrt(dx * dx + dz * dz)

                if distance < 0.001 then
                    dx, dz, distance = 1, 0, 1
                end

                crate.addImpulse(
                    dx / distance * 20,
                    8,
                    dz / distance * 20
                )
            end
        end
    end
end

The impulse values are a starting point for a mass-5 crate. Increase or decrease them to match the desired launch speed. addForce and addTorque are also available on the resolved object API.

Share state between object scripts

A resolved object API exposes getVar(name) and setVar(name, value). Define the variable on the target object in the inspector first, then another script can update it:

local crate = gameObject.getObject(crateId)
if crate then
    crate.setVar("broken", true)
end

The crate's own script can read gameObject.getVar("broken") during update(deltaTime). Primitive values are numbers, strings, and booleans. An editor-configured object_ref variable is returned as another object API.

Trigger callback payloads

Call gameObject.registerForCollisions() in init(), then define onTriggerEnter(other) and onTriggerExit(other). Trigger callbacks can run on scripts attached to either side of the overlap.

function init()
    gameObject.registerForCollisions()
end

function onTriggerEnter(other)
    print("Entered trigger: " .. other.id)

    local object = gameObject.getObject(other.id)
    if object then
        object.setVar("insideHazard", true)
    end
end

function onTriggerExit(other)
    print("Left trigger: " .. other.id)
end

other is a callback snapshot, not an object API. On entry it contains id, position, rotation, normal, contactPoint, contactDepth, and isTrigger. On exit, rely on id, position, and rotation. Resolve other.id when you need current state or object methods.

Object destruction limitations

Object scripts do not expose gameObject.destroy(). In a scene script, scene.destroyObject(id) and scene.destroyObjectByRef(object) only remove objects created during simulation with scene.createObject(). They cannot remove authored scene objects.

Authored breakables stay in the scene

For an authored crate, use an impulse or have its own script react to a broken variable and move it below the world. Three-dimensional objects do not currently expose a general visibility or enabled-state method.