-
Notifications
You must be signed in to change notification settings - Fork 5
Writing Scripts
This page explains the basic scripting model used by Tilky Engine.
It covers:
- how to write a script
- how to create public variables
- how to create shared global script state
- how to access the entity this script is attached to
- how to access fields from other components
- how to access another script’s public variables
| Object | Meaning |
|---|---|
Owner |
The entity this script is attached to |
Public |
Variables exposed to the editor and saved per script component instance |
Scripts |
Global shared runtime table visible to all scripts |
A Lua script can define two main functions:
function Start()
Debug.Print("Script started")
end
function Update()
Debug.Print("Script updated")
endStart() is called once when the script becomes active.
Update() is called every frame while the script component is enabled.
Owner is the entity this script is attached to.
function Start()
Debug.Print("Owner entity ID:", Owner.id)
endBefore using a component, check that the entity has it.
function Start()
if Owner.hasTransform then
Debug.Print("Owner has a transform")
end
endComponents are accessed through Owner.
function Start()
local transform = Owner.transform
if not transform then
return
end
Debug.Print("Entity has a transform")
endThe common pattern is:
local component = Owner.componentName
if not component then
return
endExample:
function Start()
local rb = Owner.rigidbody
if not rb then
Debug.Print("This entity has no rigidbody")
return
end
Debug.Print("This entity has a rigidbody")
endOnce you have a component, you can read or change its exposed fields.
function Start()
local transform = Owner.transform
if not transform then
return
end
Debug.Print("Position X:", transform.position.x)
endExample of changing a transform field:
function Start()
local transform = Owner.transform
if not transform then
return
end
transform.position.x = 100
endExample of changing a rigidbody field:
function Start()
local rb = Owner.rigidbody
if not rb then
return
end
rb.velocity.x = 10
endPublic variables are declared at the top of a script.
Public.Float("speed", 5.0)
Public.Int("health", 100)
Public.Bool("aggressive", true)
Public.String("displayName", "Enemy")Public variables are:
- shown in the editor
- saved per entity
- unique for each script component instance
- accessible from other scripts through a script reference
After declaring a public variable, use it through Public.name.
Public.Int("health", 100)
function Start()
Debug.Print("Health:", Public.health)
endYou can also change it during runtime:
Public.Int("health", 100)
function Start()
Public.health = Public.health - 25
Debug.Print("New health:", Public.health)
endRuntime changes affect the active play session. They do not automatically overwrite the saved level data.
If two entities use the same Lua script, each entity has its own public values.
Example script:
-- Enemy.lua
Public.Int("health", 100)
Public.String("enemyName", "Enemy")
function Start()
Debug.Print(Public.enemyName, "health:", Public.health)
endEntity A can have:
enemyName = "Guard"
health = 100
Entity B can have:
enemyName = "Boss"
health = 500
Both entities use Enemy.lua, but their Public values are independent.
Use local variables for private runtime state that only this script instance needs.
local timesUpdated = 0
function Update()
timesUpdated = timesUpdated + 1
Debug.Print("Updated:", timesUpdated)
endLocal variables are not shown in the editor and are not saved as public script data.
Use local variables for:
- temporary state
- counters
- cached values
- internal script logic
Use Public when the value should be editable from the editor.
Scripts is a shared table visible to all scripts during the current runtime session.
Use it for global runtime state.
Scripts.GameStats = Scripts.GameStats or {
enemiesSpawned = 0,
enemiesKilled = 0
}The or pattern prevents the table from being reset if another script already created it.
Example:
Scripts.GameStats = Scripts.GameStats or {
enemiesSpawned = 0,
enemiesKilled = 0
}
function Start()
Scripts.GameStats.enemiesSpawned =
Scripts.GameStats.enemiesSpawned + 1
Debug.Print("Enemies spawned:", Scripts.GameStats.enemiesSpawned)
endAll scripts see the same Scripts.GameStats.
Use Public for data owned by one script component instance.
Public.Int("health", 100)
Public.Float("speed", 5.0)Use Scripts for shared runtime state.
Scripts.GameStats = Scripts.GameStats or {
enemiesKilled = 0
}Example:
Public.Int("health", 100)
Scripts.GameStats = Scripts.GameStats or {
enemiesKilled = 0
}
function Update()
if Public.health <= 0 then
Scripts.GameStats.enemiesKilled =
Scripts.GameStats.enemiesKilled + 1
Debug.Print("Enemies killed:", Scripts.GameStats.enemiesKilled)
end
endIf 5 entities use this script:
- each entity has its own
Public.health - all entities share the same
Scripts.GameStats
Public variables can be accessed from another script through an entity reference.
local healthScript = target:GetScript("Health")This returns a reference to the Health.lua script attached to target.
Always check that the script exists before using it.
local healthScript = target:GetScript("Health")
if not healthScript:IsValid() then
return
endThen access its public variables through .Public.
healthScript.Public.health = healthScript.Public.health - 25Full example:
Public.Int("damage", 25)
function Damage(target)
local healthScript = target:GetScript("Health")
if not healthScript:IsValid() then
return
end
healthScript.Public.health =
healthScript.Public.health - Public.damage
Debug.Print("Target health:", healthScript.Public.health)
endIn this example:
-
Public.damagebelongs to the current script -
healthScript.Public.healthbelongs to the target entity’sHealth.luascript
-- Health.lua
Public.Int("health", 100)
Public.Int("maxHealth", 100)
function Start()
Debug.Print("Health:", Public.health)
end
function Update()
if Public.health <= 0 then
Debug.Print("Entity died")
Owner:Destroy()
end
endOther scripts can access this script’s health value with:
local healthScript = someEntity:GetScript("Health")
if healthScript:IsValid() then
Debug.Print(healthScript.Public.health)
end-- DamageDealer.lua
Public.Int("damage", 25)
function Damage(target)
local healthScript = target:GetScript("Health")
if not healthScript:IsValid() then
Debug.Print("Target has no Health script")
return
end
healthScript.Public.health =
healthScript.Public.health - Public.damage
Debug.Print("Damaged target. New health:", healthScript.Public.health)
endtarget must be an entity passed to this function by another script or by an engine event.
Use Owner.componentName.
function Start()
local transform = Owner.transform
if not transform then
return
end
transform.position.x = 50
endAnother example:
function Start()
local rb = Owner.rigidbody
if not rb then
return
end
rb.velocity.x = 20
endIf you have an entity reference, access its components the same way.
function PrintTargetPosition(target)
local transform = target.transform
if not transform then
Debug.Print("Target has no transform")
return
end
Debug.Print("Target X:", transform.position.x)
endThe entity reference could come from another script, an engine event, or an engine function.
local transform = Owner.transform
if not transform then
return
endlocal script = Owner:GetScript("Health")
if not script:IsValid() then
return
endPublic.Float("speed", 5.0)
Public.Int("health", 100)
Public.Bool("enabled", true)
Public.String("name", "Entity")Scripts.GameState = Scripts.GameState or {
score = 0
}Use Owner to access the entity this script is attached to.
Owner.transform
Owner.rigidbody
Owner:GetScript("Health")Use Public for values that should be editable in the editor and saved per entity.
Public.Int("health", 100)
Public.Float("speed", 5.0)Use Scripts for global runtime state shared between scripts.
Scripts.GameStats.enemiesKilledUse local variables for private script-only runtime state.
local counter = 0Access another script’s public variables through an entity reference.
local health = target:GetScript("Health")
if health:IsValid() then
health.Public.health = health.Public.health - 25
end