Complete guide to using Lua scripts to manage game object components through the engine.
- Introduction
- TransformComponent
- PhysicsComponent
- CameraComponent
- PerceptionComponent
- PerceptionSystem
- Usage Examples
The Lua scripting system allows developers to manage game object components in real-time. Each component is accessible through a corresponding Lua getter function that returns a reference to the game object's component.
-- Get a component
local transform = getTransform(gameObject)
-- Access component fields
local position = transform.m_position
-- Call component methods
perception:setSightRadius(100.0)The transform component manages the position, rotation, and scale of a game object in world and local space.
local transform = getTransform(gameObject)All fields are represented as Vector3 structures and can be read and modified directly.
| Field | Type | Description |
|---|---|---|
m_position |
Vector3 | Object position in world space |
m_rotation |
Vector3 | Object rotation in world space (in degrees or radians) |
m_scaleFactor |
Vector3 | Object scale in world space |
-- Get current position
local pos = transform.m_position
-- Change position
transform.m_position = {x = 10.0, y = 5.0, z = 20.0}
-- Modify only X coordinate
local newPos = transform.m_position
newPos.x = 15.0
transform.m_position = newPos
-- Work with local position (relative to parent)
transform.m_localPosition = {x = 1.0, y = 0.0, z = 0.0}
-- Scale the object
transform.m_scaleFactor = {x = 2.0, y = 2.0, z = 2.0}
-- Different scales per axis
transform.m_scaleFactor = {x = 1.0, y = 2.0, z = 1.5}The physics component provides access to the Jolt Physics engine. It allows you to apply forces, impulses, torques, and query velocities and positions of physics bodies.
local physics = GetPhysics(gameObject)Note: PhysicsComponent must be previously added to the game object in the editor or through code.
Applies a continuous force to the physics body.
physics:addForce({x = 100.0, y = 0.0, z = 0.0})Parameters:
force(Vector3): Force vector to apply
Applies an instantaneous impulse to the physics body.
physics:addImpulse({x = 500.0, y = 1000.0, z = 0.0})Parameters:
impulse(Vector3): Impulse vector to apply
Applies a continuous rotational torque to the physics body.
physics:addTorque({x = 0.0, y = 50.0, z = 0.0})Parameters:
torque(Vector3): Torque vector to apply
Applies an instantaneous angular impulse to the physics body.
physics:addAngularImpulse({x = 10.0, y = 20.0, z = 0.0})Parameters:
angularImpulse(Vector3): Angular impulse vector to apply
Gets the accumulated force on the physics body.
local force = physics:getAccumulatedForce()
print("Accumulated force:", force.x, force.y, force.z)Returns: Vector3
Gets the accumulated torque on the physics body.
local torque = physics:getAccumulatedTorque()Returns: Vector3
Gets the current linear velocity of the physics body.
local velocity = physics:getLinearVelocity()
local speed = math.sqrt(velocity.x * velocity.x + velocity.y * velocity.y + velocity.z * velocity.z)
print("Speed:", speed)Returns: Vector3
Gets the current angular velocity of the physics body.
local angularVel = physics:getAngularVelocity()Returns: Vector3
Gets the velocity at a specific point on the physics body.
local pointVel = physics:getPointVelocity({x = 0.0, y = 1.0, z = 0.0})Parameters:
point(Vector3): World space point to query
Returns: Vector3
Gets the current position of the physics body.
local pos = physics:getPosition()
print("Position:", pos.x, pos.y, pos.z)Returns: Vector3
Gets the current rotation of the physics body as a quaternion.
local rot = physics:getRotation()
print("Rotation quaternion:", rot)Returns: Quaternion
Clears all accumulated forces on the physics body.
physics:resetForce()Clears all accumulated torques on the physics body.
physics:resetTorque()Directly sets the linear velocity of the physics body.
physics:setLinearVelocity({x = 10.0, y = 0.0, z = 5.0})Parameters:
velocity(Vector3): Target velocity
Directly sets the angular velocity of the physics body.
physics:setAngularVelocity({x = 0.0, y = 90.0, z = 0.0})Parameters:
angularVelocity(Vector3): Target angular velocity
Warning Only PlayerObject has CameraComponent!
The camera component provides control over the camera's view, position, rotation, and various camera modes. It manages the player's perspective with support for first-person, orbital, and follow camera modes.
local cameraComponent = self.owner:getCameraComponent()
local camera = cameraComponent:getCamera()The Camera object handles view frustum, direction vectors, and stick-based camera control for orbiting and third-person perspectives.
local camera = cameraComponent:getCamera()| Property | Type | Description |
|---|---|---|
forward |
Vector3 | Camera forward direction vector |
up |
Vector3 | Camera up direction vector |
right |
Vector3 | Camera right direction vector |
position |
Vector3 | Camera world position |
deltaTime |
float | Delta time for current frame |
Sets the camera position in world space.
camera:setPosition({x = 0.0, y = 5.0, z = -10.0})Parameters:
position(Vector3): Target position
Gets the current camera position.
local pos = camera:getPosition()
print("Position:", pos.x, pos.y, pos.z)Returns: Vector3
Moves the camera forward relative to its forward direction.
camera:moveForward(5.0)Parameters:
moveSpeed(float): Speed of movement
Moves the camera backward relative to its forward direction.
camera:moveBackward(5.0)Parameters:
moveSpeed(float): Speed of movement
Moves the camera left relative to its right direction.
camera:moveLeft(5.0)Parameters:
moveSpeed(float): Speed of movement
Moves the camera right relative to its right direction.
camera:moveRight(5.0)Parameters:
moveSpeed(float): Speed of movement
Moves the camera up in world space.
camera:moveUp(5.0)Parameters:
moveSpeed(float): Speed of movement
Moves the camera down in world space.
camera:moveDown(5.0)Parameters:
moveSpeed(float): Speed of movement
Sets the target point the camera looks at (for orbital mode).
camera:setTarget({x = 0.0, y = 1.0, z = 0.0})Parameters:
target(Vector3): Target position to look at
Gets the current camera target.
local target = camera:getTarget()Returns: Vector3
Sets the camera's up direction vector.
camera:setUp({x = 0.0, y = 1.0, z = 0.0})Parameters:
up(Vector3): Up direction vector
Gets the current camera up direction.
local up = camera:getUp()Returns: Vector3
Rotates the camera around the up axis (horizontal rotation).
camera:rotateYaw(45.0) -- 45 degreesParameters:
angleSpeed(float): Rotation angle speed in degrees
Rotates the camera around the right axis (vertical rotation).
camera:rotatePitch(30.0) -- 30 degreesParameters:
angleSpeed(float): Rotation angle speed in degrees
Switches the camera to first-person mode.
camera:switchToFPSMode()The stick represents the distance and direction from the camera's target (used in orbital and third-person camera modes).
Gets the distance from the camera to its target.
local distance = camera:getStickLength()
print("Distance to target:", distance)Returns: float
Sets the distance from the camera to its target (zoom).
camera:setStickLength(15.0) -- 15 units from targetParameters:
length(float): Distance in world units (clamped to 0-100)
Gets the direction vector from target to camera (same as camera direction).
local direction = camera:getStickDirection()Returns: Vector3
Gets the width of the view.
local width = camera:getViewWidth()Returns: float
Gets the height of the view.
local height = camera:getViewHeight()Returns: float
Sets the near clipping plane distance.
camera:setNearZ(0.1)Parameters:
distance(float): Distance from camera to near plane
Gets the near clipping plane distance.
local nearZ = camera:getNearZ()Returns: float
Sets the far clipping plane distance.
camera:setFarZ(1000.0)Parameters:
distance(float): Distance from camera to far plane
Gets the far clipping plane distance.
local farZ = camera:getFarZ()Returns: float
Sets the reference length for camera calculations.
camera:setReferenceLen(10.0)Parameters:
length(float): Reference length value
Gets the current reference length.
local refLen = camera:getReferenceLen()Returns: float
-- Set up orbital camera
local camera = cameraComponent:getCamera()
camera:setTarget({x = 0.0, y = 1.0, z = 0.0}) -- Look at player center
camera:setStickLength(10.0) -- 10 units away
-- Orbit around target with mouse movement
camera:rotateYaw(45.0) -- Rotate horizontally
camera:rotatePitch(-20.0) -- Rotate verticallyfunction behavior:update(dt)
local camera = self.owner:getCameraComponent():getCamera()
local currentTime = os.clock()
-- Smoothly change zoom distance based on time
camera:setStickLength(10.0 + 3.0 * math.sin(currentTime))
return "success"
endThe particle emitter component manages particle systems for visual effects. It allows you to control emission rates, enable/disable emission, set particle spawn positions and directions, and manage the overall behavior of particle systems.
local emitter = self.owner:getParticleEmitter()Note: ParticleEmitterComponent must be previously added to the game object in the editor or through code.
Sets the rate at which particles are emitted.
emitter:setEmissionRate(100.0) -- Emit 100 particles per unit timeParameters:
emissionRate(float): Particles per unit time
Enables particle emission.
emitter:enableEmission()Disables particle emission. Previously emitted particles continue to live and update.
emitter:disableEmission()Checks if the emitter is currently emitting particles.
local isEmitting = emitter:isEnabled()
if isEmitting then
print("Particles are being emitted")
endReturns: boolean - true if emission is active, false otherwise
Increases the emission rate by the specified amount.
emitter:incrementEmissionRate(50.0) -- Increase rate by 50Parameters:
deltaEmissionRate(float): Amount to increase
Decreases the emission rate by the specified amount.
emitter:decrementEmissionRate(25.0) -- Decrease rate by 25Parameters:
deltaEmissionRate(float): Amount to decrease
Sets the position offset from which particles are emitted.
emitter:setEmitPosition({x = 10.0, y = 5.0, z = -5.0})Parameters:
offset(Vector3): World space emission position offset
Sets the direction vector for particle emission.
-- Emit particles upward
emitter:setEmitDir({x = 0.0, y = 1.0, z = 0.0})
-- Emit particles in a diagonal direction
emitter:setEmitDir({x = 1.0, y = 0.5, z = 1.0})Parameters:
direction(Vector3): Emission direction vector (should be normalized)
behavior = {}
function behavior:start()
local emitter = self.owner:getParticleEmitter()
if emitter then
emitter:setEmissionRate(50.0)
emitter:enableEmission()
end
end
function behavior:update(dt)
return "success"
end
function behavior:destroy()
print("Destroyed", self.id)
end
return behaviorbehavior = {}
function behavior:start()
self.lastEmitTime = 0
self.emitCooldown = 2.0 -- Emit for 2 seconds, then stop
self.isEmitting = true
end
function behavior:update(dt)
local emitter = self.owner:getParticleEmitter()
if not emitter then
return "success"
end
local currentTime = os.clock()
-- Toggle emission on a timer
if currentTime - self.lastEmitTime > self.emitCooldown then
self.lastEmitTime = currentTime
if self.isEmitting then
emitter:disableEmission()
self.isEmitting = false
else
emitter:enableEmission()
self.isEmitting = true
end
end
return "success"
end
function behavior:destroy()
print("Destroyed", self.id)
end
return behaviorbehavior = {}
function behavior:start()
self.rotationSpeed = 5.0 -- Radians per second
end
function behavior:update(dt)
local emitter = self.owner:getParticleEmitter()
if not emitter then
return "success"
end
local currentTime = os.clock()
-- Rotate emission direction over time
local newDir = Vector3.new(
math.sin(currentTime * self.rotationSpeed),
math.cos(currentTime * self.rotationSpeed),
0.0
)
emitter:setEmitDir(newDir)
return "success"
end
function behavior:destroy()
print("Destroyed", self.id)
end
return behaviorbehavior = {}
function behavior:start()
self.baseEmissionRate = 50.0
self.maxEmissionRate = 200.0
end
function behavior:update(dt)
local emitter = self.owner:getParticleEmitter()
local physics = self.owner:getPhysics()
if emitter and physics then
-- Get current velocity
local velocity = physics:getLinearVelocity()
-- Calculate speed
local speed = math.sqrt(
velocity.x * velocity.x +
velocity.y * velocity.y +
velocity.z * velocity.z
)
-- Scale emission rate with speed
local emissionRate = self.baseEmissionRate + (speed * 0.5)
emissionRate = math.min(emissionRate, self.maxEmissionRate)
emitter:setEmissionRate(emissionRate)
-- Set direction based on velocity
if speed > 0.1 then
local dir = Vector3.new(
velocity.x / speed,
velocity.y / speed,
velocity.z / speed
)
emitter:setEmitDir(dir)
end
end
return "success"
end
function behavior:destroy()
print("Destroyed", self.id)
end
return behaviorThe perception component manages the sight and hearing of a game object. It allows you to configure object detection parameters and receive callbacks when perception events occur.
-- Get the perception component of the current object
local perception = getPerceptionComponent(gameObject)Note: PerceptionComponent must be previously added to the game object in the editor or through code.
local ownerId = perception:getOwnerId()Returns the ID of the game object that owns this component.
Sets all sight parameters in a single call.
perception:setSight(
100.0, -- radius: sight range in units
50.0, -- loseRadius: target loss radius
120.0, -- fieldOfView: field of view angle in degrees
false -- throughObjects: can see through objects
)Sets the sight radius.
perception:setSightRadius(150.0)Parameters:
radius(float): Sight radius in world units
Sets the radius at which an object is considered lost from view.
perception:setLoseRadius(75.0)Parameters:
radius(float): Target loss radius in world units
Sets the field of view angle.
perception:setFieldOfView(90.0) -- 90 degreesParameters:
fov(float): Field of view angle in degrees (0-360)
Sets whether the object can see through other objects.
perception:setCanSeeThroughObjects(true)Parameters:
canSee(bool):trueif can see through objects,falseotherwise
Gets the current sight radius.
local radius = perception:getSightRadius()Returns: float
Gets the current target loss radius.
local loseRadius = perception:getLoseRadius()Returns: float
Gets the current field of view angle.
local fov = perception:getFieldOfView()Returns: float
Checks if the object can see through objects.
local canSee = perception:getCanSeeThroughObjects()Returns: bool
Sets all hearing parameters in a single call.
perception:setHearing(
200.0, -- radius: hearing range
0.5, -- threshold: noise threshold value
1.0 -- sensitivity: sensitivity multiplier
)Sets the hearing radius.
perception:setHearingRadius(250.0)Parameters:
radius(float): Hearing radius in world units
Sets the noise threshold for detection.
perception:setThreshold(0.3)Parameters:
threshold(float): Minimum noise level for detection (0-1)
Sets the hearing sensitivity.
perception:setSensitivity(1.5)Parameters:
sensitivity(float): Sensitivity multiplier (1.0 = standard)
Gets the current hearing radius.
local radius = perception:getHearingRadius()Returns: float
Gets the current threshold value.
local threshold = perception:getThreshold()Returns: float
Gets the current sensitivity.
local sensitivity = perception:getSensitivity()Returns: float
Callbacks are invoked when an object sees or loses sight of another object.
Adds a callback for visual detection.
local callbackId = perception:addSightCallback(function(targetId, isDetected)
if isDetected then
print("Object " .. targetId .. " detected!")
else
print("Object " .. targetId .. " lost from sight!")
end
end)Parameters:
function: Lua function with signaturefunction(targetId, isDetected)targetId(uint64): ID of the detected objectisDetected(bool):trueif detected,falseif lost
Returns: uint64 (callback ID for later removal)
Removes a specific sight callback.
perception:removeSightCallback(callbackId)Parameters:
callbackId(uint64): Callback ID obtained when adding
Removes all sight callbacks.
perception:clearSightCallbacks()Callbacks are invoked when an object hears a sound.
Adds a callback for sound detection.
local callbackId = perception:addHearingCallback(function(sourceId, loudness)
print("Heard sound from object " .. sourceId .. " with loudness " .. loudness)
end)Parameters:
function: Lua function with signaturefunction(sourceId, loudness)sourceId(uint64): ID of the sound sourceloudness(float): Sound loudness level
Returns: uint64 (callback ID)
Removes a specific hearing callback.
perception:removeHearingCallback(callbackId)Parameters:
callbackId(uint64): Callback ID
Removes all hearing callbacks.
perception:clearHearingCallbacks()Callbacks are invoked when an object takes damage.
Adds a callback for damage reception.
local callbackId = perception:addDamageCallback(function(instigatorId, damage)
print("Took damage " .. damage .. " from object " .. instigatorId)
end)Parameters:
function: Lua function with signaturefunction(instigatorId, damage)instigatorId(uint64): ID of the object dealing damagedamage(float): Damage amount
Returns: uint64 (callback ID)
Removes a specific damage callback.
perception:removeDamageCallback(callbackId)Parameters:
callbackId(uint64): Callback ID
Removes all damage callbacks.
perception:clearDamageCallbacks()Produces a sound that other objects can hear.
perception:makeNoise(0.8)Parameters:
loudness(float): Sound loudness (0-1)
Returns: Sound event ID
Deals damage to this object from a specified source.
perception:dealDamage(instigatorPerception, 25.0)Parameters:
instigator(PerceptionComponent): Perception component of the damage-dealing objectdamage(float): Damage amount
The global perception system manages team logic and interactions between objects of different teams.
local perceptionSystem = PerceptionSystem()Registers a new team in the system.
perceptionSystem:registerTeam(1)
perceptionSystem:registerTeam(2)Parameters:
teamId(uint32): Unique team ID
Removes a team from the system.
perceptionSystem:unregisterTeam(1)Parameters:
teamId(uint32): Team ID to remove
Adds a team as a sight target for visual detection.
-- Team 1 can see members of team 2
perceptionSystem:addSightTargetTeamIDsInTeam(1, 2)Parameters:
teamId(uint32): ID of the team that seestargetTeamId(uint32): ID of the team to see
Removes a team from sight targets.
perceptionSystem:removeSightTargetTeamIDsInTeam(1, 2)Parameters:
teamId(uint32): Team IDtargetTeamId(uint32): Target team ID
Clears all sight target teams.
perceptionSystem:clearSightTargetTeamIDsInTeam(1)Parameters:
teamId(uint32): Team ID
Adds a team as a hearing source for sound detection.
-- Team 1 can hear members of team 2
perceptionSystem:addHearingSourceTeamIDsInTeam(1, 2)Parameters:
teamId(uint32): ID of the team that hearssourceTeamId(uint32): ID of the team whose sounds should be heard
Removes a team from hearing sources.
perceptionSystem:removeHearingSourceTeamIDsInTeam(1, 2)Parameters:
teamId(uint32): Team IDsourceTeamId(uint32): Source team ID
Clears all hearing source teams.
perceptionSystem:clearHearingSourceTeamIDsInTeam(1)Parameters:
teamId(uint32): Team ID
Adds a game object to a team.
perceptionSystem:addToTeam(1, objectId)Parameters:
teamId(uint32): Team IDobjectId(uint64): Game object ID
Removes an object from a team.
perceptionSystem:removeFromTeam(1, objectId)Parameters:
teamId(uint32): Team IDobjectId(uint64): Game object ID
Removes all members from a team.
perceptionSystem:clearTeam(1)Parameters:
teamId(uint32): Team ID
-- Get components
local transform = getTransform(enemyObject)
local perception = getPerceptionComponent(enemyObject)
-- Set enemy position
transform.m_position = {x = 0.0, y = 0.0, z = 0.0}
-- Configure sight: sees 100 units with 120 degree field of view
perception:setSight(100.0, 50.0, 120.0, false)
-- Configure hearing: hears 200 units away
perception:setHearing(200.0, 0.5, 1.0)
-- Add callback for player detection
perception:addSightCallback(function(targetId, isDetected)
if isDetected then
print("Enemy sees player!")
-- Start attacking
else
print("Enemy lost player from sight")
-- Return to patrol mode
end
end)local perceptionSystem = PerceptionSystem()
-- Create two teams: players and enemies
perceptionSystem:registerTeam(1) -- Team 1: Players
perceptionSystem:registerTeam(2) -- Team 2: Enemies
-- Enemies see players
perceptionSystem:addSightTargetTeamIDsInTeam(2, 1)
-- Enemies hear players and each other
perceptionSystem:addHearingSourceTeamIDsInTeam(2, 1)
perceptionSystem:addHearingSourceTeamIDsInTeam(2, 2)
-- Add enemy to enemy team
perceptionSystem:addToTeam(2, enemyObjectId)local perception = getPerceptionComponent(enemyObject)
-- Add callback for sound
perception:addHearingCallback(function(sourceId, loudness)
print("Enemy heard something with loudness " .. loudness)
if loudness > 0.7 then
print("Loud sound! Start active search!")
-- Begin active search
else
print("Quiet sound, investigating carefully...")
-- Move quietly toward sound source
end
end)
-- Make a sound (e.g., footsteps)
perception:makeNoise(0.6)local perception = getPerceptionComponent(scoutObject)
-- Normal patrol mode
perception:setSightRadius(80.0)
perception:setFieldOfView(90.0)
-- Later - combat mode
if isUnderAttack then
perception:setSightRadius(150.0)
perception:setFieldOfView(120.0)
perception:setSensitivity(1.5)
end
-- Or blinded/darkened mode
if isBlinded then
perception:setSightRadius(20.0)
perception:setFieldOfView(30.0)
endlocal perceptionSystem = PerceptionSystem()
local perception1 = getPerceptionComponent(enemy1)
local perception2 = getPerceptionComponent(enemy2)
-- Add callback to first enemy
perception1:addSightCallback(function(targetId, isDetected)
if isDetected then
-- Tell second enemy target is found
perception2:addSightCallback(function()
-- Help with the attack
end)
end
end)- Reuse component references instead of repeatedly calling
getTransform()andgetPerceptionComponent() - Remove unused callbacks to save memory and improve performance
- Group operations - set multiple parameters at once
- Use
print()in callbacks to track perception events - Check radius and field of view values when experiencing unexpected behavior
- Ensure PerceptionComponent was previously added to the object
- Register teams properly at level start
- Make sure target relationships between teams are set before adding objects
- Use different team IDs for different factions or enemy types
Used to represent position, rotation, and scale.
local vec = {
x = 10.0,
y = 20.0,
z = 30.0
}Documentation is current for engine version with Lua bindings via sol2
The engine exposes a small set of helpers for working with game objects and their UUIDs from Lua.
- Returns:
UUID(anSE::UUIDhilowrapper with numeric fieldshiandlo) - Use
id:toString()to get a human-readable UUID string. - The
UUIDis a 32-bit split representation (hi/lo) to avoid precision loss in Lua numbers.
Example:
local id = gameObject:getUUID()
print("UUID hi=", id.hi, "lo=", id.lo)
print("UUID string:", id:toString())removeGameObjectByUUID(uuid)— remove a game object (and its children) from the active scene. Accepts aUUID(hi/lo) value.getGameObjectByUUID(uuid)— returns theGameObjectinstance for the givenUUID, ornilif not found.
Examples:
-- Remove an object by UUID
local id = gameObject:getUUID()
removeGameObjectByUUID(id)
-- Find an object by UUID and access its transform
local other = getGameObjectByUUID(id)
if other then
local t = other:getTransform()
print("Found object position:", t.m_position.x, t.m_position.y, t.m_position.z)
end