Lua 语言示例
Lua编程示例,用于游戏开发和嵌入式脚本
💻 Lua Hello World lua
🟢 simple
⭐
Lua Hello World程序和基本语法示例
⏱️ 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 greetings = {"Hello", "Bonjour", "Hola", "Ciao", "こんにちは"}
for _, greeting in ipairs(greetings) 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 表和元表 lua
🟡 intermediate
⭐⭐⭐⭐
高级表操作、元表和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 协程和模块 lua
🟡 intermediate
⭐⭐⭐⭐
协程编程、模块系统和实用游戏开发模式
⏱️ 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!")