minetest_modding_book/_it/basics/lua.md

10 KiB

title layout root idx description redirect_from
Scriptare in Lua default ../.. 1.2 Un'introduzione a Lua, con inclusa una guida alla portata globale/locale. /it/chapters/lua.html

Introduzione

In questo capitolo parleremo dello scripting in Lua, degli strumenti necessari, e tratteremo alcune tecniche che troverai probabilmente utili.

Editor di codice

Un editor di codice con evidenziamento delle parole chiave è sufficiente per scrivere script in Lua. L'evidenziamento assegna colori diversi a parole e caratteri diversi a seconda del loro significato. Questo ti permette di individuare più facilmente eventuali errori.

function ctf.post(team,msg)
    if not ctf.team(team) then
        return false
    end
    if not ctf.team(team).log then
        ctf.team(team).log = {}
    end

    table.insert(ctf.team(team).log,1,msg)
    ctf.save()

    return true
end

Per esempio, parole chiave come if, then, end e return sono evidenziate nel passaggio qui sopra. table.insert è invece una funzione base che deriva direttamente da Lua.

Segue una lista di editor noti che si prestano bene per programmare in Lua. Non sono, ovviamente, gli unici esisteneti.

Programmare in Lua

Flusso del programma

I programmi sono una serie di comandi che vengono eseguiti uno dopo l'altro. Chiamiamo questi comandi "istruzioni". Il flusso del programma è il come queste istruzioni vengono eseguite. Differenti tipi di flusso ti permettono di saltare o meno serie di comandi. Ci sono tre tipi di flusso:

  • Sequenziale: esegue un'istruzione dopo l'altra, senza salti.
  • Selettivo: salta alcune sequenze a seconda delle condizioni.
  • Iterante: ripete ciclicamente. Continua a eseguire le stesse istruzioni finché una condizione non è soddisfatta.

Quindi, come vengono rappresentate le istruzioni in Lua?

local a = 2     -- Imposta 'a' a 2
local b = 2     -- Imposta 'b' a 2
local risultato = a + b -- Imposta 'risultato' ad a + b, cioè 4
a = a + 10
print("La somma è ".. risultato)

Whoa, cos'è appena successo?

a, b, e risultato sono variabili. Le variabili locali si dichiarano tramite l'uso della parola chiave local, e assegnando loro un valore iniziale. Local sarà discussa in un attimo, in quanto parte di un concetto molto importante chiamato portata.

Il simbolo = significa assegnazione, quindi risultato = a + b significa impostare "risultato" ad a + b. I nomi delle variabili possono essere più lunghi di un carattere, al contrario che in matematica, come visto nella variabile "risultato". Vale anche la pena notare che Lua è case-sensitive (differenzia maiscuole da minuscole); A è una variabile diversa da a.

Tipi di variabili

Una variabile può equivalere solo a uno dei seguenti tipi e può cambiare tipo dopo l'assegnazione. È buona pratica assicurarsi che una variabile sia sempre solo o nil o diversa da nil.

Tipo Descrizione Esempio
Nil Non inizializzata. La variabile è vuota, non ha valore local A, D = nil
Numero Un numero intero o decimale local A = 4
Stringa Una porzione di testo local D = "one two three"
Booleano Vero o falso (true, false) local is_true = false, local E = (1 == 1)
Tabella Liste Spiegate sotto
Funzione Può essere eseguita. Può richiedere input e ritornare un valore local result = func(1, 2, 3)

Operatori matematici

Lista non esaustiva, ce ne sono altri

Simbolo Scopo Esempio
A + B Addizione 2 + 2 = 4
A - B Sottrazione 2 - 10 = -8
A * B Moltiplicazione 2 * 2 = 4
A / B Divisione 100 / 50 = 2
A ^ B Potenze 2 ^ 2 = 22 = 4
A .. B Concatena stringhe "foo" .. "bar" = "foobar"

Selezione

La selezione più basica è il costrutto if. Si presenta così:

local random_number = math.random(1, 100) -- Tra 1 e 100.
if random_number > 50 then
    print("Woohoo!")
else
    print("No!")
end

Questo esempio genera un numero casuale tra 1 e 100. Stampa poi "Woohoo!" se il numero è superiore a 50, altrimenti stampa "No!". Cos'altro puoi usare oltre a '>'?

Operatori logici

Simbolo Scopo Esempio
A == B Uguale a 1 == 1 (true), 1 == 2 (false)
A ~= B Non uguale a (diverso da) 1 ~= 1 (false), 1 ~= 2 (true)
A > B Maggiore di 5 > 2 (true), 1 > 2 (false), 1 > 1 (false)
A < B Minore di 1 < 3 (true), 3 < 1 (false), 1 < 1 (false)
A >= B Maggiore o uguale a 5 >= 5 (true), 5 >= 3 (true), 5 >= 6 (false)
A <= B Minore o uguale a 3 <= 6 (true), 3 <= 3 (true)
A and B E (entrambi devono essere veri) (2 > 1) and (1 == 1) (true), (2 > 3) and (1 == 1) (false)
A or B O (almeno uno dei due vero) (2 > 1) or (1 == 2) (true), (2 > 4) or (1 == 3) (false)
not A non vero not (1 == 2) (true), not (1 == 1) (false)

La lista non è esaustiva, e puoi inoltre combinare gli operatori in questo modo:

if not A and B then
    print("Yay!")
end

Che stampa "Yay!" se A è falso e B vero.

Gli operatori logici e matematici funzionano esattamente allo stesso modo; entrambi accettano input e ritornano un valore che può essere immagazzinato.

local A = 5
local is_equal = (A == 5)
if is_equal then
    print("È equivalente!")
end

Programmare

Programmare è l'azione di prendere un problema, come ordinare una lista di oggetti, e tramutarlo in dei passaggi che il computer può comprendere.

Insegnarti i processi logici della programmazione non rientra nell'ambito di questo libro; tuttavia, i seguenti siti sono alquanto utili per approfondire l'argomento:

  • Codecademy è una delle migliori risorse per imparare a 'programmare'; offre un'esperienza guidata interattiva.
  • Scratch è una buona risorsa quando si comincia dalle basi assolute, imparando le tecniche di problem solving necessarie per programmare.\ Scratch è ideato per insegnare ai bambini e non è un linguaggio serio di programmazione.

Portata locale e globale

L'essere locale o globale di una variabile determina da dove è possibile accederci. Una variabile locale è accessibile soltanto da dove viene definita. Ecco alcuni esempi:

-- Accessibile dall'interno dello script
local one = 1

function myfunc()
    -- Accessibile dall'interno della funzione
    local two = one + one

    if two == one then
        -- Accessible dall'interno del costrutto if
        local three = one + two
    end
end

Mentre le variabili globali sono accessibili da qualsiasi script di qualsiasi mod.

my_global_variable = "ciao"

function one()
    my_global_variable = "hey"
end

print(my_global_variable) -- Output: "ciao"
one()
print(my_global_variable) -- Output: "hey"

Local dovrebbe essere usato il più possibile

Lua è globale di default (a differenza di molti altri linguaggi di programmazione). Le variabili locali devono essere identificate come tali.

function one()
    foo = "bar"
end

function two()
    print(dump(foo))  -- Output: "bar"
end

one()
two()

dump() è una funzione che può trasformare qualsiasi variabile in una stringa, cosicché il programmatore possa vedere cosa rappresenta. La variabile foo sarà stampata come "bar", virgolette incluse (che dimostrano che è una stringa).

L'esempio precedente non è buona programmazione e Minetest, infatti, avviserà di ciò:

Assignment to undeclared global 'foo' inside function at init.lua:2

Per ovviare, usa "local":

function one()
    local foo = "bar"
end

function two()
    print(dump(foo))  -- Output: nil
end

one()
two()

Ricorda che nil significa non inizializzato. Ovvero la variabile non è stata ancora assegnata a un valore, non esiste o è stata deinizializzata (cioè impostata a nil)

La stessa cosa vale per le funzioni. Le funzioni sono variabili di tipo speciale, e dovrebbero essere dichiarate locali, in quanto altre mod potrebbero sennò avere funzioni con lo stesso nome.

local function foo(bar)
    return bar * 2
end

Le tabelle API dovrebbero essere usate per permettere ad altre mod di chiamare le funzioni, come in:

mymod = {}

function mymod.foo(bar)
    return "foo" .. bar
end

-- In un'altra mod o script:
mymod.foo("foobar")

Inclusione di altri script Lua

Il metodo consigliato per includere in una mod altri script Lua è usare dofile.

dofile(minetest.get_modpath("modname") .. "/script.lua")

Uno script può ritornare un valore, che è utile per condividere variabili locali private:

-- script.lua
return "Hello world!"

-- init.lua
local ret = dofile(minetest.get_modpath("modname") .. "/script.lua")
print(ret) -- Hello world!

Nei capitoli seguenti si parlerà nel dettaglio di come suddividere il codice di una mod. Tuttavia, per ora l'approccio semplicistico è di avere file differenti per diversi tipi di cose — nodi.lua, craft.lua, oggetti.lua ecc.