Lua Language Samples
Essential Lua programming examples for game development and embedded scripting
Key Facts
- Category
- Programming Languages
- Items
- 3
- Format Families
- sample
Sample Overview
Essential Lua programming examples for game development and embedded scripting This sample set belongs to Programming Languages and can be used to test related workflows inside Elysia Tools.
💻 Lua Hello World lua
🟢 simple
⭐
Basic Lua Hello World program and fundamental syntax examples
⏱️ 15 min
🏷️ lua, programming, beginner, game development, scripting
Prerequisites:
Basic programming concepts
-- Lua Hello World Examples
-- 1. Basic Hello World
print("Hello, World!")
-- 2. Hello World with variable
local message = "Hello, World!"
print(message)
-- 3. Hello World with function
function sayHello()
return "Hello, World!"
end
print(sayHello())
-- 4. Hello World with function parameters
function greet(name)
return "Hello, " .. name .. "!"
end
print(greet("World"))
print(greet("Lua"))
-- 5. Hello World with table
local greeter = {
message = "Hello, World!"
}
function greeter:sayHello()
return self.message
end
print(greeter:sayHello())
-- 6. Hello World with class-like structure
local Greeter = {}
Greeter.__index = Greeter
function Greeter.new(message)
local self = setmetatable({}, Greeter)
self.message = message or "Hello, World!"
return self
end
function Greeter:greet()
return self.message
end
local greeter1 = Greeter.new()
local greeter2 = Greeter.new("Hello from custom class!")
print(greeter1:greet())
print(greeter2:greet())
-- 7. Hello World multiple times
for i = 1, 5 do
print("Hello, World! " .. i)
end
-- 8. Hello World with table
local greetingList = {"Hello", "Bonjour", "Hola", "Ciao", "こんにちは"}
for _, greeting in ipairs(greetingList) do
print(greeting .. ", World!")
end
-- 9. Hello World with map-like table
local greetings = {
en = "Hello",
es = "Hola",
fr = "Bonjour",
de = "Hallo",
ja = "こんにちは"
}
for lang, greeting in pairs(greetings) do
print(greeting .. ", World! (" .. lang .. ")")
end
-- 10. Hello World with user input simulation
-- Note: In a real environment, you might use io.read()
function simulateUserInput()
local userName = "Lua User" -- Simulated input
return "Hello, " .. userName .. "!"
end
print(simulateUserInput())
-- Basic data types examples
-- Numbers (Lua has only one number type: double)
local integer = 42
local float = 3.14
local scientific = 1.23e-4
-- Strings
local singleQuote = 'Hello'
local doubleQuote = "World"
local multiline = [[
This is a multiline string
that can span multiple lines
without escaping.
]]
-- Booleans
local isTrue = true
local isFalse = false
-- Nil (represents absence of value)
local nilValue = nil
-- Tables (main data structure)
local emptyTable = {}
local list = {1, 2, 3, 4, 5}
local map = {name = "Lua", version = "5.4", awesome = true}
print("Data types:")
print("Integer:", integer, "Type:", type(integer))
print("Float:", float, "Type:", type(float))
print("String:", singleQuote, "Type:", type(singleQuote))
print("Boolean:", isTrue, "Type:", type(isTrue))
print("Nil:", nilValue, "Type:", type(nilValue))
print("Table:", list, "Type:", type(list))
-- Control flow examples
local age = 18
-- If-else statement
if age >= 18 then
print("You are an adult")
else
print("You are a minor")
end
-- If-elseif-else
local score = 85
local grade
if score >= 90 then
grade = "A"
elseif score >= 80 then
grade = "B"
elseif score >= 70 then
grade = "C"
else
grade = "F"
end
print("Score:", score, "Grade:", grade)
-- Loop examples
-- Numeric for loop
print("For loop:")
for i = 1, 3 do
print("Iteration:", i)
end
-- While loop
print("While loop:")
local count = 0
while count < 3 do
print("Count:", count)
count = count + 1
end
-- Repeat-until loop
print("Repeat-until loop:")
local repeatCount = 0
repeat
print("Repeat count:", repeatCount)
repeatCount = repeatCount + 1
until repeatCount >= 3
-- Functions as first-class citizens
-- Anonymous function
local multiply = function(a, b)
return a * b
end
print("5 * 3 =", multiply(5, 3))
-- Function that returns multiple values
function getMinMax(numbers)
local min = numbers[1]
local max = numbers[1]
for _, num in ipairs(numbers) do
if num < min then min = num end
if num > max then max = num end
end
return min, max
end
local numbers = {5, 2, 8, 1, 9, 3}
local minVal, maxVal = getMinMax(numbers)
print("Min:", minVal, "Max:", maxVal)
-- String manipulation
local text = "Hello, Lua World!"
print("Original:", text)
print("Upper:", string.upper(text))
print("Lower:", string.lower(text))
print("Length:", #text)
print("Substring:", string.sub(text, 1, 5))
print("Find Lua:", string.find(text, "Lua"))
-- String concatenation and formatting
local name = "Lua"
local version = "5.4"
local formatted = string.format("Language: %s, Version: %s", name, version)
print(formatted)
-- Table operations
-- Lists (arrays)
local fruits = {"apple", "banana", "cherry", "date"}
print("Fruits list:")
for i, fruit in ipairs(fruits) do
print(i, fruit)
end
-- Add to end
table.insert(fruits, "elderberry")
print("After insert:", table.concat(fruits, ", "))
-- Remove from end
local removed = table.remove(fruits)
print("Removed:", removed)
print("Remaining:", table.concat(fruits, ", "))
-- Map-like tables
local person = {
name = "John Doe",
age = 30,
city = "New York",
skills = {"programming", "gaming", "music"}
}
print("Person information:")
print("Name:", person.name)
print("Age:", person.age)
print("City:", person.city)
print("Skills:", table.concat(person.skills, ", "))
-- Dynamic table access
local key = "age"
print("Dynamic access:", person[key])
-- Table iteration
print("Person details:")
for key, value in pairs(person) do
if type(value) ~= "table" then
print(key .. ":", value)
end
end
-- Error handling with pcall
function riskyOperation(shouldFail)
if shouldFail then
error("Something went wrong!")
end
return "Success!"
end
-- Safe execution
local success, result = pcall(riskyOperation, false)
if success then
print("Operation result:", result)
else
print("Operation failed:", result)
end
local success, result = pcall(riskyOperation, true)
if success then
print("Operation result:", result)
else
print("Operation failed:", result)
end
-- Variable scope examples
local globalVar = "I am global" -- Available everywhere
function testScope()
local localVar = "I am local" -- Available only in this function
print("Inside function - Global:", globalVar)
print("Inside function - Local:", localVar)
end
testScope()
print("Outside function - Global:", globalVar)
-- print(localVar) -- This would cause an error: localVar is not defined
-- Metatables demonstration
local vector = {x = 3, y = 4}
-- Metatable for vector operations
local vectorMeta = {
__add = function(a, b)
return {x = a.x + b.x, y = a.y + b.y}
end,
__tostring = function(v)
return "(" .. v.x .. ", " .. v.y .. ")"
end
}
setmetatable(vector, vectorMeta)
local vector2 = {x = 1, y = 2}
setmetatable(vector2, vectorMeta)
local result = vector + vector2
print("Vector addition:", tostring(result))
💻 Lua Tables and Metatables lua
🟡 intermediate
⭐⭐⭐⭐
Advanced table operations, metatables, and object-oriented programming in Lua
⏱️ 30 min
🏷️ lua, tables, metatables, oop, data structures
Prerequisites:
Lua basics, Understanding of metatables, Object-oriented concepts
-- Lua Tables and Metatables Examples
-- 1. Advanced Table Operations
-- Table as array/list
local numbers = {10, 20, 30, 40, 50}
-- Array operations
function arrayCopy(arr)
local copy = {}
for i, v in ipairs(arr) do
copy[i] = v
end
return copy
end
function arrayFilter(arr, predicate)
local result = {}
for i, v in ipairs(arr) do
if predicate(v) then
table.insert(result, v)
end
end
return result
end
function arrayMap(arr, transform)
local result = {}
for i, v in ipairs(arr) do
result[i] = transform(v)
end
return result
end
function arrayReduce(arr, accumulator, initial)
local result = initial
for _, v in ipairs(arr) do
result = accumulator(result, v)
end
return result
end
-- Test array operations
local doubled = arrayMap(numbers, function(x) return x * 2 end)
local evens = arrayFilter(numbers, function(x) return x % 2 == 0 end)
local sum = arrayReduce(numbers, function(acc, x) return acc + x end, 0)
print("Original:", table.concat(numbers, ", "))
print("Doubled:", table.concat(doubled, ", "))
print("Even numbers:", table.concat(evens, ", "))
print("Sum:", sum)
-- 2. Table as dictionary/map
local person = {
name = "Alice",
age = 30,
city = "New York",
email = "[email protected]",
hobbies = {"reading", "hiking", "coding"}
}
-- Dictionary operations
function tableCopy(t)
local copy = {}
for k, v in pairs(t) do
if type(v) == "table" then
copy[k] = tableCopy(v)
else
copy[k] = v
end
end
return copy
end
function tableKeys(t)
local keys = {}
for k, _ in pairs(t) do
table.insert(keys, k)
end
return keys
end
function tableValues(t)
local values = {}
for _, v in pairs(t) do
table.insert(values, v)
end
return values
end
function tableMerge(t1, t2)
local result = tableCopy(t1)
for k, v in pairs(t2) do
result[k] = v
end
return result
end
-- Test dictionary operations
local keys = tableKeys(person)
local values = tableValues(person)
local extended = tableMerge(person, {country = "USA", phone = "555-1234"})
print("Person keys:", table.concat(keys, ", "))
print("Extended person:")
for k, v in pairs(extended) do
print(" " .. k .. ":", type(v) == "table" and table.concat(v, ", ") or v)
end
-- 3. Stack and Queue implementations
-- Stack implementation using table
local Stack = {}
Stack.__index = Stack
function Stack.new()
return setmetatable({}, Stack)
end
function Stack:push(item)
table.insert(self, item)
end
function Stack:pop()
if #self == 0 then
return nil
end
return table.remove(self)
end
function Stack:peek()
if #self == 0 then
return nil
end
return self[#self]
end
function Stack:isEmpty()
return #self == 0
end
function Stack:size()
return #self
end
-- Test Stack
local stack = Stack.new()
stack:push("first")
stack:push("second")
stack:push("third")
print("Stack size:", stack:size())
print("Peek:", stack:peek())
print("Pop:", stack:pop())
print("Pop:", stack:pop())
print("Is empty:", stack:isEmpty())
-- Queue implementation using table
local Queue = {}
Queue.__index = Queue
function Queue.new()
return setmetatable({head = 0, tail = -1}, Queue)
end
function Queue:enqueue(item)
self.tail = self.tail + 1
self[self.tail] = item
end
function Queue:dequeue()
if self.head > self.tail then
return nil
end
local value = self[self.head]
self[self.head] = nil -- Free memory
self.head = self.head + 1
return value
end
function Queue:isEmpty()
return self.head > self.tail
end
function Queue:size()
if self:isEmpty() then
return 0
end
return self.tail - self.head + 1
end
-- Test Queue
local queue = Queue.new()
queue:enqueue("Alice")
queue:enqueue("Bob")
queue:enqueue("Charlie")
print("Queue size:", queue:size())
print("Dequeue:", queue:dequeue())
print("Dequeue:", queue:dequeue())
print("Queue size after dequeues:", queue:size())
-- 4. Metatables - The Magic of Lua
-- Basic metatable example
local myTable = {a = 10, b = 20}
-- Create metatable with __index method
local myMeta = {
__index = function(table, key)
print("Accessing missing key:", key)
return "default value"
end,
__newindex = function(table, key, value)
print("Setting new key:", key, "to:", value)
rawset(table, key, value)
end
}
setmetatable(myTable, myMeta)
print(myTable.c) -- Triggers __index
myTable.c = 30 -- Triggers __newindex
print(myTable.c) -- Regular access
-- 5. Operator overloading with metatables
-- Vector class
local Vector = {}
Vector.__index = Vector
function Vector.new(x, y)
local self = setmetatable({x = x or 0, y = y or 0}, Vector)
return self
end
function Vector.__add(a, b)
return Vector.new(a.x + b.x, a.y + b.y)
end
function Vector.__sub(a, b)
return Vector.new(a.x - b.x, a.y - b.y)
end
function Vector.__mul(a, scalar)
if type(a) == "table" and type(scalar) == "number" then
return Vector.new(a.x * scalar, a.y * scalar)
elseif type(a) == "number" and type(scalar) == "table" then
return Vector.new(a * scalar.x, a * scalar.y)
end
error("Invalid multiplication")
end
function Vector.__eq(a, b)
return math.abs(a.x - b.x) < 0.0001 and math.abs(a.y - b.y) < 0.0001
end
function Vector.__tostring(v)
return string.format("(%g, %g)", v.x, v.y)
end
function Vector:magnitude()
return math.sqrt(self.x * self.x + self.y * self.y)
end
function Vector:normalize()
local mag = self:magnitude()
if mag > 0 then
return Vector.new(self.x / mag, self.y / mag)
end
return Vector.new(0, 0)
end
function Vector:dot(other)
return self.x * other.x + self.y * other.y
end
-- Test Vector class
local v1 = Vector.new(3, 4)
local v2 = Vector.new(1, 2)
print("Vector1:", v1)
print("Vector2:", v2)
print("Addition:", v1 + v2)
print("Subtraction:", v1 - v2)
print("Multiplication:", v1 * 2)
print("Magnitude:", v1:magnitude())
print("Normalized:", v1:normalize())
print("Dot product:", v1:dot(v2))
-- 6. Read-only table proxy
function makeReadOnly(t)
local proxy = {}
local meta = {
__index = t,
__newindex = function(t, k, v)
error("Attempt to modify read-only table")
end,
__pairs = function()
return pairs(t)
end,
__ipairs = function()
return ipairs(t)
end
}
setmetatable(proxy, meta)
return proxy
end
local config = {
max_connections = 100,
timeout = 30,
debug = false
}
local readonlyConfig = makeReadOnly(config)
print("Max connections:", readonlyConfig.max_connections)
-- readonlyConfig.max_connections = 200 -- This would throw an error
-- 7. Table with default values
function withDefaults(defaults)
local meta = {
__index = defaults
}
return setmetatable({}, meta)
end
local gameSettings = withDefaults({
volume = 0.5,
difficulty = "normal",
fullscreen = false,
resolution = {width = 1920, height = 1080}
})
print("Volume:", gameSettings.volume)
gameSettings.volume = 0.8 -- This overwrites the default
print("New volume:", gameSettings.volume)
print("Resolution width:", gameSettings.resolution.width)
-- 8. Chainable interface (fluent interface)
local StringBuilder = {}
StringBuilder.__index = StringBuilder
function StringBuilder.new()
return setmetatable({buffer = {}}, StringBuilder)
end
function StringBuilder:add(text)
table.insert(self.buffer, text)
return self
end
function StringBuilder:addLine(text)
table.insert(self.buffer, text or "")
return self
end
function StringBuilder:clear()
self.buffer = {}
return self
end
function StringBuilder:toString()
return table.concat(self.buffer)
end
function StringBuilder:length()
return #self.buffer
end
-- Test StringBuilder
local sb = StringBuilder.new()
local result = sb
:add("Hello")
:add(" ")
:add("World")
:addLine()
:add("This is Lua")
:addLine("StringBuilder example")
:toString()
print("StringBuilder result:")
print(result)
-- 9. Weak tables for caching
local cache = setmetatable({}, {__mode = "v"}) -- Weak values
function expensiveComputation(x)
if cache[x] then
print("Cache hit for", x)
return cache[x]
end
print("Computing for", x)
local result = x * x * x -- Simulate expensive operation
cache[x] = result
return result
end
print("Result 1:", expensiveComputation(10))
print("Result 2:", expensiveComputation(10))
print("Result 3:", expensiveComputation(20))
print("Result 4:", expensiveComputation(10))
-- 10. Observable table pattern
function makeObservable(t, onChange)
local proxy = {}
local meta = {
__index = function(_, k)
return t[k]
end,
__newindex = function(_, k, v)
local oldValue = t[k]
t[k] = v
if onChange and oldValue ~= v then
onChange(k, oldValue, v)
end
end,
__pairs = function()
return pairs(t)
end,
__ipairs = function()
return ipairs(t)
end
}
return setmetatable(proxy, meta)
end
local playerData = makeObservable({
score = 0,
lives = 3,
level = 1
}, function(key, oldValue, newValue)
print(string.format("Player %s changed: %s -> %s", key, oldValue, newValue))
end)
playerData.score = 100
playerData.lives = 2
playerData.level = 2
💻 Lua Coroutines and Modules lua
🟡 intermediate
⭐⭐⭐⭐
Coroutine programming, module system, and practical game development patterns
⏱️ 35 min
🏷️ lua, coroutines, modules, game dev, entity system, async
Prerequisites:
Lua basics, Table operations, Understanding of game programming concepts
-- Lua Coroutines and Modules Examples
-- 1. Basic Coroutine Examples
-- Simple coroutine
function simpleCoroutine()
print("Coroutine started")
for i = 1, 3 do
print("Coroutine step", i)
coroutine.yield("Yielded value " .. i)
end
print("Coroutine finished")
return "Final result"
end
-- Create and run coroutine
local co = coroutine.create(simpleCoroutine)
print("Coroutine status:", coroutine.status(co))
-- Resume coroutine multiple times
while true do
local success, result = coroutine.resume(co)
print("Resume result:", success, result)
if not success or coroutine.status(co) == "dead" then
break
end
end
print("Final coroutine status:", coroutine.status(co))
-- 2. Coroutine for task scheduling
function taskScheduler()
local tasks = {}
-- Add task function
local function addTask(name, func, delay)
table.insert(tasks, {
name = name,
func = func,
delay = delay,
timeRemaining = delay,
coroutine = coroutine.create(func)
})
end
-- Update function (call this every frame)
local function update(deltaTime)
for i, task in ipairs(tasks) do
task.timeRemaining = task.timeRemaining - deltaTime
if task.timeRemaining <= 0 and coroutine.status(task.coroutine) ~= "dead" then
local success, result = coroutine.resume(task.coroutine)
if not success then
print("Task error:", task.name, result)
table.remove(tasks, i)
elseif coroutine.status(task.coroutine) == "dead" then
print("Task completed:", task.name)
table.remove(tasks, i)
end
end
end
end
return {
addTask = addTask,
update = update,
getTaskCount = function() return #tasks end
}
end
-- Test task scheduler
local scheduler = taskScheduler()
-- Define some tasks
local function countdownTask()
for i = 5, 1, -1 do
print("Countdown:", i)
coroutine.yield()
end
print("Blast off!")
end
local function printTask()
for i = 1, 3 do
print("Printing line", i)
coroutine.yield()
end
end
-- Add tasks with delays
scheduler:addTask("Countdown", countdownTask, 1.0)
scheduler:addTask("Print", printTask, 2.0)
-- Simulate game loop
for frame = 1, 10 do
print("=== Frame", frame, "===")
scheduler:update(1.0) -- 1 second per frame
if scheduler.getTaskCount() == 0 then
break
end
end
-- 3. Coroutine for animation
function animateValue(startValue, endValue, duration, updateFunc)
local startTime = os.clock()
while true do
local currentTime = os.clock()
local elapsed = currentTime - startTime
local progress = math.min(elapsed / duration, 1.0)
-- Easing function (ease in-out)
local easedProgress = progress < 0.5
and 2 * progress * progress
or 1 - math.pow(-2 * progress + 2, 2) / 2
local currentValue = startValue + (endValue - startValue) * easedProgress
updateFunc(currentValue)
if progress >= 1.0 then
break
end
coroutine.yield()
end
end
-- Create animation coroutine
local animationCo = coroutine.create(function()
animateValue(0, 100, 3.0, function(value)
print(string.format("Animation progress: %.1f%%", value))
end)
print("Animation complete!")
end)
-- Run animation
while coroutine.status(animationCo) ~= "dead" do
coroutine.resume(animationCo)
os.execute("sleep 0.1") -- Wait 100ms (in real code, use proper timing)
end
-- 4. Generator pattern with coroutines
function rangeGenerator(start, stop, step)
step = step or 1
return coroutine.create(function()
for i = start, stop, step do
coroutine.yield(i)
end
end)
end
function fibonacciGenerator(n)
return coroutine.create(function()
local a, b = 0, 1
for i = 1, n do
coroutine.yield(a)
a, b = b, a + b
end
end)
end
-- Test generators
print("Range generator:")
local rangeGen = rangeGenerator(1, 5)
while true do
local success, value = coroutine.resume(rangeGen)
if not success or coroutine.status(rangeGen) == "dead" then
break
end
print(" Value:", value)
end
print("\nFibonacci generator:")
local fibGen = fibonacciGenerator(10)
while true do
local success, value = coroutine.resume(fibGen)
if not success or coroutine.status(fibGen) == "dead" then
break
end
print(" Fibonacci:", value)
end
-- 5. Coroutine-based state machine
function createStateMachine()
local state = "idle"
local co = coroutine.create(function()
while true do
if state == "idle" then
print("State: Idle")
state = coroutine.yield("idle")
elseif state == "loading" then
print("State: Loading...")
for i = 1, 3 do
print(" Loading", i, "/ 3")
coroutine.yield("loading")
end
state = "playing"
elseif state == "playing" then
print("State: Playing")
state = coroutine.yield("playing")
elseif state == "paused" then
print("State: Paused")
state = coroutine.yield("paused")
else
print("Unknown state:", state)
state = "idle"
end
end
end)
return {
setState = function(newState) state = newState end,
update = function()
if coroutine.status(co) ~= "dead" then
local success, currentState = coroutine.resume(co)
return success and currentState or "error"
end
return "dead"
end
}
end
-- Test state machine
local stateMachine = createStateMachine()
for i = 1, 10 do
print("--- Update", i, "---")
local currentState = stateMachine.update()
-- Simulate state transitions
if i == 2 then
stateMachine.setState("loading")
elseif i == 5 then
stateMachine.setState("playing")
elseif i == 7 then
stateMachine.setState("paused")
elseif i == 8 then
stateMachine.setState("playing")
end
end
-- 6. Module system examples
-- In Lua, modules are typically created as tables
-- Here's how to structure a module:
-- mathUtils.lua (simulated here)
local mathUtils = {}
function mathUtils.clamp(value, min, max)
if value < min then return min end
if value > max then return max end
return value
end
function mathUtils.lerp(a, b, t)
return a + (b - a) * t
end
function mathUtils.randomFloat(min, max)
return min + math.random() * (max - min)
end
function mathUtils.distance(x1, y1, x2, y2)
return math.sqrt((x2 - x1)^2 + (y2 - y1)^2)
end
-- Add metatable for module
setmetatable(mathUtils, {
__tostring = function()
return "MathUtils module"
end
})
-- Test the math utilities module
print("\n=== Math Utils Module ===")
print("Clamp 15 to [0, 10]:", mathUtils.clamp(15, 0, 10))
print("Lerp 0 to 10 by 0.3:", mathUtils.lerp(0, 10, 0.3))
print("Random float [1, 5]:", string.format("%.2f", mathUtils.randomFloat(1, 5)))
print("Distance between (0,0) and (3,4):", mathUtils.distance(0, 0, 3, 4))
-- 7. Game entity system with modules
-- Entity component system
local Entity = {}
Entity.__index = Entity
function Entity.new(id)
local self = setmetatable({
id = id,
components = {},
tags = {}
}, Entity)
return self
end
function Entity:addComponent(name, component)
self.components[name] = component
return self
end
function Entity:getComponent(name)
return self.components[name]
end
function Entity:hasComponent(name)
return self.components[name] ~= nil
end
function Entity:addTag(tag)
self.tags[tag] = true
return self
end
function Entity:hasTag(tag)
return self.tags[tag] == true
end
function Entity:update(dt)
-- Update all components that have update method
for name, component in pairs(self.components) do
if component.update then
component:update(self, dt)
end
end
end
-- Component modules
local Transform = {}
Transform.__index = Transform
function Transform.new(x, y)
return setmetatable({
x = x or 0,
y = y or 0,
rotation = 0,
scaleX = 1,
scaleY = 1
}, Transform)
end
function Transform:update(entity, dt)
-- Transform component logic
end
local Health = {}
Health.__index = Health
function Health.new(maxHealth)
return setmetatable({
current = maxHealth,
maximum = maxHealth
}, Health)
end
function Health:update(entity, dt)
-- Regeneration logic could go here
end
function Health:takeDamage(amount)
self.current = math.max(0, self.current - amount)
return self.current <= 0
end
function Health:heal(amount)
self.current = math.min(self.maximum, self.current + amount)
end
local Movement = {}
Movement.__index = Movement
function Movement.new(speed)
return setmetatable({
speed = speed or 100,
direction = {x = 1, y = 0}
}, Movement)
end
function Movement:update(entity, dt)
local transform = entity:getComponent("transform")
if transform then
transform.x = transform.x + self.direction.x * self.speed * dt
transform.y = transform.y + self.direction.y * self.speed * dt
end
end
function Movement:setDirection(x, y)
local length = math.sqrt(x * x + y * y)
if length > 0 then
self.direction.x = x / length
self.direction.y = y / length
end
end
-- Test entity system
print("\n=== Entity System ===")
local player = Entity.new("player")
:addComponent("transform", Transform.new(100, 100))
:addComponent("health", Health.new(100))
:addComponent("movement", Movement.new(150))
:addTag("player")
:addTag("alive")
print("Player created with ID:", player.id)
print("Player has transform:", player:hasComponent("transform"))
print("Player has health:", player:hasComponent("health"))
print("Player is alive:", player:hasTag("alive"))
-- Update player
for i = 1, 3 do
print("\n--- Update", i, "---")
local movement = player:getComponent("movement")
local transform = player:getComponent("transform")
movement:setDirection(1, 0) -- Move right
player:update(0.1) -- 100ms update
print("Player position:", string.format("(%.1f, %.1f)", transform.x, transform.y))
end
-- Take damage
local health = player:getComponent("health")
health:takeDamage(30)
print("Player health after damage:", health.current .. "/" .. health.maximum)
-- 8. Coroutine-based AI behavior
local AIBehavior = {}
AIBehavior.__index = AIBehavior
function AIBehavior.new(entity)
local self = setmetatable({
entity = entity,
state = "patrol",
target = nil,
coroutine = nil
}, AIBehavior)
-- Start AI coroutine
self.coroutine = coroutine.create(function()
self:runAI()
end)
return self
end
function AIBehavior:runAI()
while true do
if self.state == "patrol" then
print("AI: Patrolling...")
for i = 1, 3 do
self:moveTo(math.random(-100, 100), math.random(-100, 100))
coroutine.yield()
end
self.state = "search"
elseif self.state == "search" then
print("AI: Searching for targets...")
self.target = {x = 50, y = 50} -- Simulate finding a target
self.state = "chase"
coroutine.yield()
elseif self.state == "chase" then
if self.target then
print("AI: Chasing target at", self.target.x, self.target.y)
self:moveTo(self.target.x, self.target.y)
local transform = self.entity:getComponent("transform")
local dist = mathUtils.distance(transform.x, transform.y,
self.target.x, self.target.y)
if dist < 5 then
print("AI: Reached target!")
self.target = nil
self.state = "patrol"
end
else
self.state = "patrol"
end
coroutine.yield()
end
end
end
function AIBehavior:moveTo(x, y)
local transform = self.entity:getComponent("transform")
if transform then
print("AI moving to:", x, y)
transform.x = x
transform.y = y
end
end
function AIBehavior:update(dt)
if self.coroutine and coroutine.status(self.coroutine) ~= "dead" then
local success, result = coroutine.resume(self.coroutine)
if not success then
print("AI Error:", result)
end
end
end
-- Test AI behavior
print("\n=== AI Behavior ===")
local enemy = Entity.new("enemy")
:addComponent("transform", Transform.new(0, 0))
:addComponent("movement", Movement.new(100))
local ai = AIBehavior.new(enemy)
-- Run AI for several updates
for i = 1, 10 do
print("\nAI Update", i)
ai:update(0.1)
end
print("\nAll examples completed!")