โ๏ธ Component Lifecycle
function init(self)
-- runs once when component loads
self.hp = 100
msg.post("#sprite", "play_animation",
{id = "idle"})
end
function update(self, dt)
-- runs every frame (dt = delta)
end
function on_message(self, message_id, message)
-- handle messages from other components
end
function final(self)
-- cleanup when component is removed
end
function on_input(self, action_id, action)
-- handle input actions
end
๐ฎ Game Objects & Position
| go.get_position() | Get current GO position |
| go.set_position(v3) | Set GO position |
| go.get_world_position() | World-space position |
| go.set_world_position(v3) | Set world position directly |
| go.get_rotation() | Get quaternion rotation |
| go.set_rotation(quat) | Set rotation |
| go.get_scale() | Get scale vector |
| go.set_scale(v3) | Set scale |
| go.delete() | Delete this game object |
| go.delete(id) | Delete another GO by URL |
๐ฌ Messages
-- send a message to another component
msg.post("/enemy_factory", "spawn", {
position = go.get_position(),
type = "slime"
})
-- broadcast to all components in this GO
msg.post("#", "take_damage", {amount = 10})
-- common message targets
"#" = this game object
"#sprite" = the sprite component
"#script" = the script component
"#camera" = the camera component
-- receive in on_message:
function on_message(self, id, msg)
if id == hash("take_damage") then
self.hp -= msg.amount
end
end
๐ง Rendering & Sprite
| sprite.play_flipbook(id, anim) | Play a flipbook animation |
| render.set_constant(name, val) | Set a material constant |
| render.get_constant(name) | Read a material constant |
| go.set("#sprite", "tint", v4) | Set sprite tint colour |
| go.set("#sprite", "scale.x", n) | Set sprite scale axis |
| go.set("#sprite", "opacity", n) | Set sprite opacity (0-1) |
| go.get("#sprite", "size") | Get sprite dimensions |
โก Physics
-- raycast
function update(self, dt)
local from = go.get_world_position()
local to = from + vmath.vector3(0, -100, 0)
local result = physics.raycast(from, to, {hash("ground")})
if result then
-- hit something
print("Hit:", result.id)
end
end
-- enable physics on a GO
msg.post("#", "enable")
physics.set_listener(callback)
๐งฎ Math (vmath)
| vmath.vector3(x,y,z) | Create a 3D vector |
| vmath.vector4(x,y,z,w) | Create a 4D vector |
| vmath.quat(x,y,z,w) | Create a quaternion |
| vmath.vmath.lerp(a,b,t) | Linear interpolation |
| vmath.length(v) | Vector length |
| vmath.normalize(v) | Normalised unit vector |
| vmath.dot(a,b) | Dot product |
| vmath.cross(a,b) | Cross product |
| math.random(min,max) | Random integer in range |
๐ญ Collections & Factories
-- spawn from a factory component
function spawn_enemy(self, pos)
local props = {hp = 30, speed = 5}
collectionfactory.create(
"/enemy_factory#factory",
pos,
vmath.quat(),
props,
nil,
function(self, id)
msg.post(id, "init_enemy",
{hp = props.hp})
end
)
end
๐จ GUI Nodes
| gui.get_node("name") | Get a GUI node by name |
| gui.set_enabled(node, bool) | Show / hide a node |
| gui.set_position(node, v3) | Set node position |
| gui.animate(node, prop, to, easing, duration) | Animate a property |
| gui.set_color(node, v4) | Set node colour |
| gui.get_text(node) | Get text content |
| gui.set_text(node, str) | Set text content |
| gui.pick_node(node, x, y) | Hit-test a screen point |
๐ ๏ธ Common Patterns
โโ PLAYER MOVEMENT (TOP-DOWN) โโ
function update(self, dt)
local move = vmath.vector3(0)
if action.pressed then
if action_id == hash("up") then move.y = 1 end
if action_id == hash("down") then move.y = -1 end
if action_id == hash("left") then move.x = -1 end
if action_id == hash("right") then move.x = 1 end
end
if vmath.length(move) > 0 then
move = vmath.normalize(move)
go.set_position(go.get_position() + move * self.speed * dt)
end
end
โโ HEALTH SYSTEM โโ
function on_message(self, id, msg)
if id == hash("take_damage") then
self.hp = math.max(0, self.hp - msg.amount)
if self.hp <= 0 then
msg.post("@system:", "shutdown")
end
end
end
โโ ENEMY SPAWN TIMER โโ
function update(self, dt)
self.timer = self.timer - dt
if self.timer <= 0 then
spawn_enemy(self, go.get_position())
self.timer = 3 -- every 3 seconds
end
end
โโ SCENE TRANSITION โโ
msg.post("level_controller#script", "load_level",
{level = "level02"})