Skip to content

Physics Scripting

Lemonate's physics simulation runs in the engine; scripts interact through SceneObject methods (forces, velocities), the Physics module (raycasts), and events (collisions). Editor setup for gravity, layers, and colliders is covered in Physics.

SceneObject physics methods

On any physics-enabled object you can read and write simulation state:

local Vector3 = require 'engine/math/vector3'

-- Impulses and forces
self.node:applyCentralImpulse(Vector3.new(0, 8, 0))
self.node:applyImpulse(Vector3.new(1, 0, 0), Vector3.new(0, 0.5, 0))
self.node:applyForce(Vector3.new(0, -10, 0), Vector3.new(0, 0, 0))
self.node:clearForces()

-- Velocity
self.node:setLinearVelocity(Vector3.new(3, 0, 0))
local v = self.node:getLinearVelocity()
self.node:setAngularVelocity(Vector3.new(0, 1, 0))

-- Sync transform with physics world explicitly when needed
self.node:setPhysicsPosition(Vector3.new(0, 5, 0))
self.node:setPhysicsRotation(quaternion)

Use impulses for instant kicks (jumps, explosions). Use forces for continuous effects (thrusters, wind). Prefer deltaTimeMs from Lifecycle Methods when integrating custom movement alongside physics.

Raycasts

The Physics module tests line segments against colliders:

local Physics = require 'engine/physics'
local Vector3 = require 'engine/math/vector3'

Physics.raycast(
    Vector3.new(0, 10, 0),
    Vector3.new(0, -10, 0),
    Physics.RaycastType.Closest,
    {"Default"}   -- optional layer name filter, or nil for all
):next(function(hit)
    if hit.hit then
        print("Hit at", hit.point.x, hit.point.y, hit.point.z)
        local obj = SceneObject.findById(hit.object)
    end
end)

Physics.RaycastType.AllHits returns every intersection along the ray as a table.

Batch raycasts — same API shape with arrays of start/end vectors:

Physics.raycastMany(starts, ends, Physics.RaycastType.Closest, nil):next(function(results)
    for i, hit in ipairs(results) do
        -- ...
    end
end)

Typical uses: ground checks, line-of-sight, weapon traces, click-to-world placement.

Collision events

Listen for physics collision pairs globally:

local Events = require 'engine/events'

function MyBehaviour:init()
    Events.on('physicsCollisions', function(e)
        for _, pair in ipairs(e.data) do
            local a = SceneObject.findById(pair.object1)
            local b = SceneObject.findById(pair.object2)
            -- respond to contact
        end
    end)
end

See Events for event registration and cleanup behaviour.

Layers

Assign layers on scene objects to filter raycasts and collisions:

self.node:setLayers({1})

Layer names used in Physics.raycast match the project's physics layer configuration in the editor.

Global gravity

Change world gravity from scripts via the Project API:

local Project = require 'engine/project'
local Vector3 = require 'engine/math/vector3'

Project.setGravity(Vector3.new(0, -9.81, 0))

Constraints and advanced features

Hinge, slider, and cone-twist constraints are available on the Physics module. See Physics for the full reference.

Vehicles

Wheel-based vehicles use SgVehicle with a dedicated setup workflow. See SgVehicle for editor steps and a driving script example.

Further reading