00
:
00
:
00
:
00
•Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Lua nei Videogiochi

Lua e’ uno dei linguaggi di scripting piu’ utilizzati nell’industria dei videogiochi. Da World of Warcraft a Roblox, da Angry Birds a Dark Souls, Lua alimenta la logica di gioco di titoli giocati da centinaia di milioni di persone. In questo articolo esploriamo perche’ Lua e’ cosi’ popolare nel game development e vediamo esempi pratici con i framework piu’ diffusi.

Perche’ Lua nei Videogiochi

Lua possiede una combinazione unica di caratteristiche che lo rendono ideale per lo scripting nei videogiochi:

  • Leggero: L’intero interprete pesa circa 300 KB. Puo’ essere integrato in qualsiasi motore senza impattare sulle dimensioni del progetto.
  • Veloce: Lua e’ uno dei linguaggi di scripting piu’ veloci. Con LuaJIT (Just-In-Time compiler) raggiunge prestazioni vicine al C in molti scenari.
  • Facile da integrare: L’API C di Lua e’ semplice e ben documentata. Bastano poche righe per collegare Lua a un motore scritto in C o C++.
  • Sintassi accessibile: Game designer e level designer possono imparare Lua rapidamente senza essere programmatori esperti.
  • Sandboxing: E’ possibile limitare le funzionalita’ esposte agli script, garantendo sicurezza nel modding.
  • Hot reload: Gli script Lua possono essere ricaricati a runtime senza ricompilare il motore di gioco.

Motori e Framework che Usano Lua

Motore/Framework Tipo Note
Love2D Framework 2D Open source, ideale per prototipi e giochi indie
Roblox Piattaforma Usa Luau, un fork di Lua con tipi opzionali
Solar2D (ex Corona) Framework mobile Specializzato in giochi 2D per iOS e Android
Defold Motore 2D Di King (Candy Crush), gratuito e multipiattaforma
CryEngine Motore AAA Usa Lua per scripting di gameplay
Gideros Framework mobile Sviluppo rapido con Lua
World of Warcraft MMO Interfaccia utente e addon scritti in Lua

Love2D: Il Framework 2D con Lua

Love2D (o LOVE) e’ un framework open source che permette di creare giochi 2D usando esclusivamente Lua. E’ perfetto per imparare e per sviluppare giochi indie.

Struttura Base di un Progetto Love2D

Un progetto Love2D ha tre funzioni principali di callback:

-- main.lua

function love.load()
    -- Inizializzazione: carica risorse, imposta variabili
    love.window.setTitle("Il Mio Gioco")
    love.window.setMode(800, 600)
end

function love.update(dt)
    -- Aggiornamento logica di gioco (chiamata ogni frame)
    -- dt = delta time in secondi
end

function love.draw()
    -- Disegna tutto a schermo (chiamata ogni frame)
    love.graphics.print("Ciao dal mio gioco!", 350, 280)
end

Esempio Completo: Personaggio Mobile

Creiamo un gioco in cui un quadrato si muove sullo schermo con le frecce direzionali.

-- main.lua - Personaggio mobile con Love2D

local giocatore = {}

function love.load()
    love.window.setTitle("Personaggio Mobile")
    love.window.setMode(800, 600)

    -- Inizializza il giocatore
    giocatore.x = 400
    giocatore.y = 300
    giocatore.larghezza = 40
    giocatore.altezza = 40
    giocatore.velocita = 200
    giocatore.colore = {0.2, 0.6, 1.0}  -- azzurro
end

function love.update(dt)
    -- Movimento con le frecce direzionali
    if love.keyboard.isDown("up") or love.keyboard.isDown("w") then
        giocatore.y = giocatore.y - giocatore.velocita * dt
    end
    if love.keyboard.isDown("down") or love.keyboard.isDown("s") then
        giocatore.y = giocatore.y + giocatore.velocita * dt
    end
    if love.keyboard.isDown("left") or love.keyboard.isDown("a") then
        giocatore.x = giocatore.x - giocatore.velocita * dt
    end
    if love.keyboard.isDown("right") or love.keyboard.isDown("d") then
        giocatore.x = giocatore.x + giocatore.velocita * dt
    end

    -- Mantieni il giocatore dentro lo schermo
    local w, h = love.graphics.getDimensions()
    giocatore.x = math.max(0, math.min(w - giocatore.larghezza, giocatore.x))
    giocatore.y = math.max(0, math.min(h - giocatore.altezza, giocatore.y))
end

function love.draw()
    -- Sfondo
    love.graphics.clear(0.1, 0.1, 0.15)

    -- Disegna il giocatore
    love.graphics.setColor(giocatore.colore)
    love.graphics.rectangle("fill", giocatore.x, giocatore.y,
                            giocatore.larghezza, giocatore.altezza)

    -- HUD
    love.graphics.setColor(1, 1, 1)
    love.graphics.print("Posizione: " .. math.floor(giocatore.x) ..
                        ", " .. math.floor(giocatore.y), 10, 10)
    love.graphics.print("Usa WASD o le frecce per muoverti", 10, 30)
end

function love.keypressed(tasto)
    if tasto == "escape" then
        love.event.quit()
    end
end

Love2D: Collisioni e Oggetti

-- Sistema di collisione AABB semplice
local function collisione(a, b)
    return a.x < b.x + b.larghezza and
           a.x + a.larghezza > b.x and
           a.y < b.y + b.altezza and
           a.y + a.altezza > b.y
end

local monete = {}

function love.load()
    -- Genera monete casuali
    for i = 1, 10 do
        table.insert(monete, {
            x = math.random(50, 750),
            y = math.random(50, 550),
            larghezza = 15,
            altezza = 15,
            raccolta = false
        })
    end
end

Roblox e Luau

Roblox utilizza Luau, un fork di Lua sviluppato internamente con miglioramenti significativi: tipi opzionali, prestazioni migliorate e nuove funzionalita’ del linguaggio.

-- Esempio di script Roblox (Luau)
local Players = game:GetService("Players")

local function onPlayerAdded(player: Player)
    print(player.Name .. " si e' unito alla partita!")

    player.CharacterAdded:Connect(function(character)
        local humanoid = character:WaitForChild("Humanoid")
        humanoid.WalkSpeed = 24  -- velocita' aumentata
        humanoid.JumpPower = 75  -- salto potenziato
    end)
end

Players.PlayerAdded:Connect(onPlayerAdded)
-- Sistema di punti in Roblox
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local function setupLeaderboard(player: Player)
    local leaderstats = Instance.new("Folder")
    leaderstats.Name = "leaderstats"
    leaderstats.Parent = player

    local punti = Instance.new("IntValue")
    punti.Name = "Punti"
    punti.Value = 0
    punti.Parent = leaderstats
end

Players.PlayerAdded:Connect(setupLeaderboard)

Solar2D (ex Corona SDK)

Solar2D e’ un framework Lua specializzato nello sviluppo di giochi 2D per dispositivi mobili. E’ stato usato per creare giochi scaricati milioni di volte su App Store e Google Play.

-- main.lua - Esempio Solar2D
local physics = require("physics")
physics.start()

-- Crea il pavimento
local pavimento = display.newRect(
    display.contentCenterX, display.contentHeight - 30,
    display.contentWidth, 60
)
physics.addBody(pavimento, "static")

-- Crea una palla che rimbalza
local palla = display.newCircle(
    display.contentCenterX, 50, 30
)
palla:setFillColor(1, 0.3, 0.3)
physics.addBody(palla, "dynamic", {
    bounce = 0.8,
    density = 1.0,
    friction = 0.3
})

-- Tocca per aggiungere nuove palle
local function onTouch(event)
    if event.phase == "began" then
        local nuova = display.newCircle(event.x, event.y, 20)
        nuova:setFillColor(math.random(), math.random(), math.random())
        physics.addBody(nuova, "dynamic", {bounce = 0.7})
    end
end

Runtime:addEventListener("touch", onTouch)

World of Warcraft: Addon con Lua

WoW e’ stato uno dei primi grandi giochi a offrire un sistema di addon basato su Lua. L’intera interfaccia utente e’ scritta in Lua e XML.

-- Esempio di addon WoW semplice
local frame = CreateFrame("Frame")
frame:RegisterEvent("PLAYER_LOGIN")
frame:RegisterEvent("CHAT_MSG_SAY")

frame:SetScript("OnEvent", function(self, event, ...)
    if event == "PLAYER_LOGIN" then
        print("|cff00ff00[MioAddon]|r Benvenuto! Addon caricato.")
    elseif event == "CHAT_MSG_SAY" then
        local messaggio, mittente = ...
        print("|cff00ff00[MioAddon]|r " .. mittente .. " ha detto: " .. messaggio)
    end
end)

-- Comando slash personalizzato
SLASH_MIOADDON1 = "/mioaddon"
SlashCmdList["MIOADDON"] = function(msg)
    if msg == "stato" then
        print("|cff00ff00[MioAddon]|r Addon attivo e funzionante!")
    else
        print("|cff00ff00[MioAddon]|r Comandi: /mioaddon stato")
    end
end

Scripting di Game Logic con Lua

Un pattern comune nei motori di gioco e’ esporre le API del motore a Lua per permettere di scrivere la logica di gioco in modo flessibile.

-- Esempio generico di scripting per un motore di gioco

-- Definizione di un nemico con comportamento AI
local Nemico = {}

function Nemico.nuovo(nome, vita, danno)
    local self = {
        nome = nome,
        vita = vita,
        vita_max = vita,
        danno = danno,
        stato = "pattuglia",
        posizione = {x = 0, y = 0},
        raggio_visione = 150,
        raggio_attacco = 40,
    }

    function self.aggiorna(dt, giocatore)
        local dist_x = giocatore.x - self.posizione.x
        local dist_y = giocatore.y - self.posizione.y
        local distanza = math.sqrt(dist_x * dist_x + dist_y * dist_y)

        if distanza <= self.raggio_attacco then
            self.stato = "attacco"
        elseif distanza <= self.raggio_visione then
            self.stato = "inseguimento"
            -- Muovi verso il giocatore
            local dir_x = dist_x / distanza
            local dir_y = dist_y / distanza
            self.posizione.x = self.posizione.x + dir_x * 60 * dt
            self.posizione.y = self.posizione.y + dir_y * 60 * dt
        else
            self.stato = "pattuglia"
        end
    end

    function self.ricevi_danno(quantita)
        self.vita = math.max(0, self.vita - quantita)
        if self.vita == 0 then
            self.stato = "morto"
        end
    end

    return self
end

-- Utilizzo
local goblin = Nemico.nuovo("Goblin", 50, 10)
print(goblin.nome .. " - Vita: " .. goblin.vita .. " - Stato: " .. goblin.stato)

Defold: Game Engine Gratuito

Defold, sviluppato originariamente da King (creatori di Candy Crush), usa Lua come linguaggio principale di scripting.

-- Esempio di script Defold per un componente di gioco
function init(self)
    msg.post(".", "acquire_input_focus")
    self.velocita = 200
    self.direzione = vmath.vector3(0, 0, 0)
end

function update(self, dt)
    local pos = go.get_position()
    pos = pos + self.direzione * self.velocita * dt
    go.set_position(pos)
    self.direzione = vmath.vector3(0, 0, 0)
end

function on_input(self, action_id, action)
    if action_id == hash("su") then
        self.direzione.y = 1
    elseif action_id == hash("giu") then
        self.direzione.y = -1
    elseif action_id == hash("sinistra") then
        self.direzione.x = -1
    elseif action_id == hash("destra") then
        self.direzione.x = 1
    end
end

Conclusione

Lua si e’ affermato come lo standard de facto per lo scripting nei videogiochi grazie alla sua leggerezza, velocita’ e facilita’ di integrazione. Che si tratti di un framework indie come Love2D, di una piattaforma massiva come Roblox o di addon per giochi AAA come World of Warcraft, Lua offre la flessibilita’ necessaria per separare la logica di gioco dal motore sottostante. Per chi vuole avvicinarsi al game development, Love2D rappresenta il punto di partenza ideale: basta un file main.lua per iniziare a creare.