Lua Basics
Published March 2, 2020
GuideBlogLuaCoding
Basic Syntax and Data Types
Basic Syntax and Data Types
Lua is a lightweight and easy to learn programming language. In this section, we will cover the basic structure of a Lua script, as well as the different data types available and how to manipulate them.
Script Structure
A Lua script is a plain text file with the .lua file extension. The script is executed from top to bottom, and it can contain a combination of statements, comments, and functions.
Statements
Statements are commands that perform a specific action, such as assigning a value to a variable or calling a function.
-- This is a statement that assigns the value "hello" to the variable "greeting"
greeting = "hello"
Comments
Comments are used to add notes or explanations to the code and are ignored by the interpreter. In Lua, comments are created using double dashes (--).
-- This is a comment and will be ignored by the interpreter
greeting = "hello"
Tip: It's a great practice to leave comments around your code to explain what it does, for not only yourself but others.
-- Function to check pal's health
function checkPalHealth()
-- Get pal using getPal function
local pal = getPal("anubis")
-- Return pal's health
return pal.health
end
Variables and Functions
Variables and Functions
In Lua, variables are used to store and manipulate data, and functions are used to organize and reuse code.
Variables
In Lua, variables are declared using the `local` keyword or without it. It's recommended to use the local keyword when declaring a variable, as it limits the scope of the variable to the current function or file, and prevents accidental global variable assignments.
-- Declaring a variable
local x = 5
-- Declaring a variable without the `local` keyword
y = 10
Lua supports several data types, including numbers, strings, booleans, and tables.
-- Declaring a number variable
local age = 25
-- Declaring a string variable
local name = "John"
-- Declaring a boolean variable
local isValid = true
-- Declaring a table variable
local myTable = {1, 2, 3}
Functions
In Lua, functions are declared using the function keyword and can be called using the function name followed by parentheses.
-- Declaring a function
function sayHello()
print("Hello!")
end
-- Calling a function
sayHello()
Functions can also take parameters and return values.
-- Declaring a function with parameters
function add(x, y)
return x + y
end
-- Calling a function with arguments
result = add(5, 10)
Functions can be stored in variables and passed as arguments to other functions.
-- Storing a function in a variable
local myFunction = function()
print("Hello!")
end
-- Passing a function as an argument
otherFunction(myFunction)
Flow Control
Flow Control
In Lua, flow control statements are used to control the flow of execution of a script. These include `if`, `else`, `elseif`, `for`, `while`, and `repeat` statements.
If-Else Condition
The `if` statement is used to check if a certain condition is true and execute a block of code if it is. The `else` statement is used as an alternative if the condition is not true.
-- If-else statement
local x = 5
if x > 10 then
print("x is greater than 10")
else
print("x is less than or equal to 10")
end
Elseif Condition
The `elseif` statement is used to check multiple conditions. If the first condition is not true, the script will check the next one, and so on, until a true condition is found or the end of the script is reached.
-- Elseif statement
local x = 5
if x > 10 then
print("x is greater than 10")
elseif x < 0 then
print("x is less than 0")
else
print("x is between 0 and 10")
end
For Loop
The `for` loop is used to iterate over a range of numbers or elements in an array or table. The loop variable is declared and initialized before the loop, and the loop will continue until the end condition is met.
-- For loop
for i = 1, 10 do
print(i)
end
While Loop
The `while` loop is used to execute a block of code repeatedly as long as a certain condition is true.
-- While loop
local x = 5
while x > 0 do
print(x)
x = x - 1
end
Repeat Until
The `repeat` statement is used to execute a block of code repeatedly until a certain condition is met. The code block is executed at least once before the condition is checked.
-- Repeat until
local x = 5
repeat
x = x - 1
print(x)
until x == 0
Tables and Metatables
Tables and Metatables
In Lua, tables are a fundamental data structure used to store and organize data. A table is a collection of key-value pairs, where each key is unique within the table. Tables can be used as arrays, dictionaries, objects, or a combination of these.
Creating a Table
To create a table, you can use curly braces `` and separate the key-value pairs with commas. Keys can be either numbers or strings, and values can be any Lua data type, including other tables.
-- Creating a table
local myTable = {
["name"] = "John",
["age"] = 25,
[3] = "hello",
-- Tables can be used as values of other tables
["nestedTable"] = {
["key"] = "value"
}
}
Accessing Table Elements
You can access the elements of a table using the table name followed by the key in square brackets `[]`.
-- Accessing table elements
print(myTable["name"]) -- Output: John
print(myTable.name) -- Output: John
print(myTable[3]) -- Output: hello
print(myTable.nestedTable.key) -- Output: value
Metatables
Metatables are used to define the behavior of a table when certain operations are performed on it. A metatable is a table that can be set as the metatable of another table. The metatable contains metamethods, which are functions that define the behavior of the table when certain operations are performed on it.
-- Creating a metatable
local myMetatable = {
__add = function(table1, table2)
local newTable = {}
for k, v in pairs(table1) do
newTable[k] = v
end
for k, v in pairs(table2) do
newTable[k] = v
end
return newTable
end
}
-- Setting the metatable
setmetatable(myTable, myMetatable)
-- Using the metamethod
local myOtherTable = {
["city"] = "New York",
["country"] = "USA"
}
local myCombinedTable = myTable + myOtherTable
print(myCombinedTable.name) -- Output: John
print(myCombinedTable.city) -- Output: New York
Object-Oriented Programming
Object-Oriented Programming in Lua
While Lua doesn't have built-in class support, we can implement OOP patterns using tables and metatables. This creates a powerful and flexible object system.
Creating Classes
-- Define a class
local Player = {}
Player.__index = Player
function Player.new(name, health)
local self = setmetatable({}, Player)
self.name = name
self.health = health
return self
end
function Player:takeDamage(amount)
self.health = self.health - amount
end
-- Creating an instance
local player = Player.new("Hero", 100)
player:takeDamage(10)
print(player.health) -- Output: 90
Inheritance
-- Base class
local Entity = {}
Entity.__index = Entity
function Entity.new(name)
local self = setmetatable({}, Entity)
self.name = name
return self
end
-- Derived class
local Monster = setmetatable({}, {__index = Entity})
Monster.__index = Monster
function Monster.new(name, damage)
local self = setmetatable(Entity.new(name), Monster)
self.damage = damage
return self
end
Error Handling and Debugging
Error Handling and Debugging
Lua provides robust error handling mechanisms to help you write more reliable code and track down issues effectively.
Protected Calls
-- Using pcall for safe execution
local success, result = pcall(function()
-- Potentially dangerous code
error("Something went wrong!")
end)
if not success then
print("Error caught: " .. result)
end
Custom Error Handling
-- Creating and handling custom errors
function divide(a, b)
if b == 0 then
error("Division by zero!", 2)
end
return a / b
end
local success, result = pcall(divide, 10, 0)
if not success then
print("Error in division: " .. result)
end
Debug Library
-- Using the debug library
local function trace()
local level = 2
local info = debug.getinfo(level, "Sl")
while info do
print(string.format("%s:%d", info.short_src, info.currentline))
level = level + 1
info = debug.getinfo(level, "Sl")
end
end
function someFunction()
trace() -- Print stack trace
end
Code Standards and Organization
Code Standards and Organization
Writing clean, maintainable Lua code involves following consistent patterns and conventions. Here's how to structure your code professionally.
File Organization
-- config.lua
local Config = {
VERSION = "1.0.0",
MAX_PLAYERS = 10,
DEBUG_MODE = true
}
return Config
-- player.lua
local Player = {}
local Config = require("config")
function Player.new(name)
return {
name = name,
health = 100,
maxPlayers = Config.MAX_PLAYERS
}
end
return Player
Naming Conventions
Follow these naming patterns for clear, readable code:
PascalCase for modules and classes (PlayerManager, GameState)
camelCase for functions and variables (getCurrentPlayer, playerCount)
UPPERCASE for constants (MAX_HEALTH, DEFAULT_SPEED)
Use descriptive, meaningful names (calculateDamage, isPlayerAlive)
-- Module/Class names (PascalCase)
local PlayerManager = {}
local GameState = {}
-- Variables and functions (camelCase)
local playerCount = 0
local function getCurrentPlayer()
return activePlayer
end
-- Constants (UPPERCASE)
local MAX_HEALTH = 100
local DEFAULT_SPEED = 5
-- Clear, descriptive names
local isPlayerAlive = true
local function calculateDamage(baseDamage, armor)
return baseDamage * (1 - armor)
end
Documentation Standards
--- Player class representing a game character
-- @class Player
-- @field name string The player's display name
-- @field health number Current health points
local Player = {}
--- Creates a new Player instance
-- @param name string The player's name
-- @param health number Initial health value
-- @return Player The new player instance
function Player.new(name, health)
local self = setmetatable({}, Player)
self.name = name
self.health = health
return self
end
--- Applies damage to the player
-- @param amount number The amount of damage to apply
-- @return number The remaining health
function Player:takeDamage(amount)
self.health = math.max(0, self.health - amount)
return self.health
end