¿Conoces esa sensación cuando descubres un nuevo lenguaje de programación y durante los primeros 20 minutos piensas: «Vaya, es fácil»? Y luego empieza. Los paréntesis no son los correctos, se te ha olvidado el punto y coma, el compilador te grita como un vecino de arriba a las 3 de la madrugada.
Con Lua todo es diferente. En serio. Este lenguaje es tan conciso que puedes aprender sus conceptos básicos mientras te tomas un café. Y en una noche, puedes armar un miniproyecto completamente funcional. ¿No lo crees? Bueno, vamos a comprobarlo.

¿Qué es Lua y por qué lo necesito?
Lua (se pronuncia «Lu-a», no «Lua», pero, sinceramente, cada uno lo dice como quiere) es un lenguaje de programación ligero que nació en Brasil en 1993. Sí, es más antiguo que la mayoría de los frameworks de JavaScript. Y, a diferencia de ellos, todavía no está deprecated.
Dónde se utiliza Lua:
Juegos - Roblox, World of Warcraft, Garry's Mod, Love2D. Si alguna vez has escrito un complemento para WoW, ya eres un desarrollador de Lua, ¡enhorabuena!
Nginx y OpenResty — los servidores web de alta carga ejecutan scripts Lua para procesar las solicitudes.
Neovim — si eres de los que pasan más tiempo configurando su editor que escribiendo código, Lua es tu nuevo mejor amigo.
Sistemas integrados e IoT — Lua es tan ligero que funciona incluso donde Python se ahoga.
En resumen, Lua es como una navaja suiza, solo que sin sacacorchos. Compacto, útil y sorprendentemente potente.
Paso 0: Instalación (más rápido que npm install)
Linux/macOS:
# Ubuntu / Debian
sudo apt install lua5.4
# macOS
brew install luaWindows:
Descargar LuaBinaries desde sitio web oficial o ponlo a través de scoop:
scoop install luaComprobamos:
lua -v
# Lua 5.4.x Copyright (C) ...Listo. Ni Docker, ni entorno virtual, ni package.json de 300 líneas. Simplemente funciona.
Paso 1: Hello World y los primeros conceptos básicos
Crea el archivo hello.lua:
print("Hello, World!")
print("Lua is easier than you thought")Iniciar:
lua hello.luaEso es todo. Sin public static void main, sin import sys, sin use strict. Simplemente escribe y ejecuta.
Variables: sin tipos, sin problemas
local name = "Alexey"
local age = 25
local is_developer = true
print(name .. " — developer: " .. tostring(is_developer))Ten en cuenta: .. es una concatenación de cadenas. No +, no son cadenas de plantilla. Dos puntos modestos. Lua es minimalista.
Condiciones: los clásicos de siempre
local level = 42
if level >= 100 then
print("You're a legend!")
elseif level >= 50 then
print("Almost there!")
else
print("Keep swinging")
endNota: then y end en lugar de llaves. Al principio es inusual, pero después de una hora ya no lo notas.
Ciclos: tres tipos para todas las ocasiones
-- Цикл for (классический)
for i = 1, 5 do
print("Iteration: " .. i)
end
-- Цикл while
local count = 0
while count < 3 do
count = count + 1
print("Counter: " .. count)
end
-- Перебор таблицы (о таблицах — ниже)
local fruits = {"apple", "banana", "mango"}
for index, fruit in ipairs(fruits) do
print(index .. ". " .. fruit)
endPaso 2: Las tablas son la única estructura de datos (y eso es suficiente)
En Lua no hay matrices, diccionarios, objetos, conjuntos, tuplas, decks... Hay tablas. Y lo reemplazan todo. Es como si un objeto JavaScript y una matriz se fusionaran en una sola entidad:
-- Как массив
local colors = {"Red", "Green", "Blue"}
print(colors[1]) -- "Red" (индексация с 1, да-да)
-- Как словарь
local player = {
name = "Hero",
hp = 100,
level = 1
}
print(player.name) -- "Hero"
print(player["hp"]) -- 100 (тоже работает)
-- Комбинированный вариант
local config = {
title = "My Game",
resolution = {1920, 1080},
fullscreen = true
}Indexación desde 1 — Sí, es un shock después de todos los idiomas con indexación cero. Pero te acostumbrarás. Probablemente. Algún día.
Paso 3: Funciones: ciudadanos de primera clase
-- Обычная функция
local function greet(name)
return "Hi, " .. name .. "!"
end
print(greet("world"))
-- Функция как переменная (анонимная)
local square = function(x)
return x * x
end
print(square(7)) -- 49
-- Множественный возврат (это Lua-суперсила!)
local function get_player_stats()
return "Hero", 100, 15
end
local name, hp, attack = get_player_stats()
print(name .. " | HP: " .. hp .. " | ATK: " .. attack)El retorno múltiple de valores es una de esas cosas en Lua que te hace suspirar: "¿Por qué no es así en todas partes?"
Paso 4: ¡Montamos un miniproyecto: una búsqueda de texto!
La teoría está bien, pero no estamos dando una conferencia aquí. Escribamos un verdadero miniproyecto: una misión RPG de texto. Tienes que explorar una mazmorra, luchar contra monstruos y (tal vez) sobrevivir.
Crea el archivo dungeon.lua:
-- === ТЕКСТОВЫЙ КВЕСТ: ПОДЗЕМЕЛЬЕ ===
math.randomseed(os.time())
-- Состояние игрока
local player = {
name = "",
hp = 100,
attack = 15,
potions = 3
}
-- Список монстров
local monsters = {
{name = "Goblin", hp = 30, attack = 8, xp = 10},
{name = "Skeleton", hp = 50, attack = 12, xp = 20},
{name = "Dark Mage", hp = 40, attack = 18, xp = 25},
{name = "Ogr", hp = 80, attack = 10, xp = 30},
}
-- Вспомогательные функции
local function separator()
print(string.rep("-", 40))
end
local function show_status()
separator()
print("HP: " .. player.hp .. " | Potions: " .. player.potions)
separator()
end
local function ask(question, options)
print("\n" .. question)
for i, opt in ipairs(options) do
print(" " .. i .. ") " .. opt)
end
io.write("Your choice: ")
local choice = tonumber(io.read())
if not choice or choice < 1 or choice > #options then
print("Incomprehensible choice, try again.")
return ask(question, options)
end
return choice
end
-- Система боя
local function battle(monster)
print("\n⚔️ Appears in front of you " .. monster.name .. "! (HP: " .. monster.hp .. ")")
local enemy_hp = monster.hp
while enemy_hp > 0 and player.hp > 0 do
show_status()
local action = ask("What are you doing?", {"Attack", "Drink the potion", "Try to escape"})
if action == 1 then
local damage = math.random(player.attack - 5, player.attack + 5)
enemy_hp = enemy_hp - damage
print("You inflict " .. damage .. " damage!")
if enemy_hp > 0 then
local enemy_damage = math.random(monster.attack - 3, monster.attack + 3)
player.hp = player.hp - enemy_damage
print(monster.name .. " beats you on " .. enemy_damage .. " damage!")
end
elseif action == 2 then
if player.potions > 0 then
local heal = math.random(20, 35)
player.hp = player.hp + heal
player.potions = player.potions - 1
print("You are restoring " .. heal .. " HP!")
else
print("You don't have any potions! You lose a turn...")
end
local enemy_damage = math.random(monster.attack - 3, monster.attack + 3)
player.hp = player.hp - enemy_damage
print(monster.name .. " beats you on " .. enemy_damage .. " damage!")
elseif action == 3 then
if math.random(1, 100) <= 40 then
print("You managed to escape!")
return false
else
print("Couldn't escape!")
local enemy_damage = math.random(monster.attack - 3, monster.attack + 5)
player.hp = player.hp - enemy_damage
print(monster.name .. " beats you on " .. enemy_damage .. " damage!")
end
end
end
if enemy_hp <= 0 then
print("\n🎉 " .. monster.name .. " defeated!")
if math.random(1, 100) <= 30 then
player.potions = player.potions + 1
print("You find a potion!")
end
return true
end
return false
end
-- Комнаты подземелья
local function explore_room(room_number)
separator()
print("\n🚪 Room " .. room_number)
local events = {"monster", "monster", "treasure", "trap", "empty"}
local event = events[math.random(1, #events)]
if event == "monster" then
local monster = monsters[math.random(1, #monsters)]
return battle(monster)
elseif event == "treasure" then
print("You find a treasure chest!")
local bonus = ask("What are you taking?", {"Health Potion (+1)", "Grinding stone (+3 to attack)"})
if bonus == 1 then
player.potions = player.potions + 1
print("Potions: " .. player.potions)
else
player.attack = player.attack + 3
print("Attack now: " .. player.attack)
end
return true
elseif event == "trap" then
print("Trap! Thorns shoot out of the wall!")
local trap_damage = math.random(5, 15)
player.hp = player.hp - trap_damage
print("You get " .. trap_damage .. " damage.")
return true
else
print("An empty room. Silence and dust.")
if math.random(1, 100) <= 20 then
print("You find a potion in the corner!")
player.potions = player.potions + 1
end
return true
end
end
-- === НАЧАЛО ИГРЫ ===
print("╔══════════════════════════════════════╗")
print("║ DUNGEON: TEXT QUEST ║")
print("║ Written in Lua ║")
print("╚══════════════════════════════════════╝")
io.write("What's your name, adventurer? ")
player.name = io.read()
print("\nWelcome, " .. player.name .. "!")
print("You are facing the entrance to a dungeon with 5 rooms.")
print("Go through them all and become a legend.\n")
local rooms_cleared = 0
for room = 1, 5 do
if player.hp <= 0 then
break
end
explore_room(room)
if player.hp <= 0 then
break
end
rooms_cleared = rooms_cleared + 1
if room < 5 then
show_status()
local choice = ask("Going further?", {"Go ahead!", "Enough for today"})
if choice == 2 then
print("\nYou decide to return. Sometimes retreating is also wise.")
break
end
end
end
separator()
separator()
if player.hp <= 0 then
print("\n💀 " .. player.name .. " fell into the dungeon...")
print("Rooms passed: " .. rooms_cleared .. " of 5")
print("Try again — the dungeon is waiting!")
else
if rooms_cleared == 5 then
print("\n🏆 " .. player.name .. " completed the entire dungeon!")
print("HP: " .. player.hp .. " | Remaining potions: " .. player.potions)
print("You are a true legend!")
else
print("\n🏠 " .. player.name .. " returned from the dungeon.")
print("Rooms passed: " .. rooms_cleared .. " of 5")
end
end
print("\nThank you for playing! 🎮")Iniciar:
lua dungeon.luaY ahora ya has escrito un proyecto completo en Lua. Con un sistema de combate, aleatoriedad, inventario y ramificación de la trama. No es una calculadora, sino un juego real.
¿Qué sigue? ¿Dónde crecer?
Lua es un excelente punto de entrada, y aquí es donde puedes moverte:
Love2D — marco para juegos 2D en Lua. Si te ha gustado la búsqueda de texto, imagina lo que pasará con los gráficos.
Complementos de Neovim — tu propio plugin para el editor, escrito en Lua, es un placer aparte.
OpenResty — integra scripts Lua directamente en nginx y procesa millones de solicitudes.
Roblox — en serio, en Roblox se gana dinero real, y toda la lógica está escrita en Lua.
¿Quieres seguir estudiando?
¡Entra en Kodik!
Si te gusta este formato, de la teoría a la práctica de una sola vez, seguro que te gustará Kodik. Esta aplicación para aprender programación, donde cada lección no es solo una pared de texto, sino tareas que resuelves con tus manos. Python, JavaScript, HTML, CSS y otras tecnologías, todo con práctica real, sin palabrería ni aburrimiento.
Y también tenemos Canal de Telegram, donde se publican regularmente publicaciones útiles: análisis de conceptos, hojas de trucos, minitareas y memes para desarrolladores. Es una forma excelente de repasar la programación en un formato cómodo: de camino al trabajo, durante la pausa del almuerzo o cuando te quedan «cinco minutitos más» antes de acostarte. Suscríbete y deja que la programación forme parte de tu día a día.
Lua es un lenguaje que demuestra que para ser poderoso no es necesario ser complejo. En una noche, pasaste de print("Hello") a una misión de RPG de texto con un sistema de combate. Y al mismo tiempo, no instalaste una sola dependencia, no escribiste una sola configuración y no rompiste un solo package-lock.json.
Ahora tienes un proyecto de trabajo, una comprensión de los conceptos básicos y una dirección para el crecimiento. Y esto ya es más que el 90% de las personas que «iban a empezar a aprender programación la próxima semana».
¡Atrévete! 🚀
