527 lines
19 KiB
Text
527 lines
19 KiB
Text
[#_lesson_3_making_decisions]
|
|
== Lezione 3: Prendere decisioni
|
|
|
|
image::learn/03-decisions.png[La lezione finita, 480]
|
|
|
|
Tutto quello che hai scritto finora fa la stessa cosa a ogni fotogramma. La
|
|
parola della seconda lezione si muoveva che tu lo volessi o no, e l'unico motivo
|
|
per cui tornava indietro erano quattro blocchi di codice che ti era stato detto
|
|
di prendere sulla fiducia.
|
|
|
|
Questa lezione è quei quattro blocchi, spiegati per bene. Alla fine il tuo
|
|
programma farà domande, agirà in base alle risposte e -- visto che la domanda
|
|
più interessante che un gioco possa fare è «che cosa sta facendo il
|
|
giocatore?» -- guiderai un riquadro per la finestra con i tasti freccia. Tieniti
|
|
quel riquadro. È il giocatore del gioco che costruirai nella settima lezione.
|
|
|
|
[#_start_a_new_folder_2]
|
|
=== Crea una nuova cartella
|
|
|
|
Una cartella chiamata `decisions`, dentro un file chiamato `decisions.singe`, e
|
|
`Singe -R decisions` in esecuzione in un terminale. Come l'ultima volta.
|
|
|
|
[#_what_an_if_really_says]
|
|
=== Che cosa dice davvero un `if`
|
|
|
|
Ecco il blocco della seconda lezione, da solo.
|
|
|
|
[source,lua]
|
|
----
|
|
if wordX > lastColumn then
|
|
wordX = lastColumn
|
|
end
|
|
----
|
|
|
|
Quattro parti. La parola `if`. Una domanda. La parola `then`. E un corpo di
|
|
righe che vengono eseguite solo quando la risposta alla domanda è sì, chiuso da
|
|
`end`.
|
|
|
|
La domanda è `wordX > lastColumn`, e il vero lavoro lo fa il `>`. Confronta i
|
|
due numeri ai suoi lati e produce una risposta che è o *vero* o *falso*. Quelle
|
|
due parole non sono testo e non sono numeri: sono valori a tutti gli effetti,
|
|
chiamati *booleani*, e un booleano è l'unica cosa che interessa a un `if`.
|
|
|
|
Il rientro è la stessa idea della prima lezione: le righe interne sono rientrate
|
|
così vedi a colpo d'occhio che cosa appartiene al blocco `if`, e la riga `end` è
|
|
allineata con la riga `if` che ha aperto il blocco. Lua lo eseguirebbe anche
|
|
senza spazi. Tu non
|
|
riusciresti a leggerlo.
|
|
|
|
Questi confronti sono sei, e li userai tutti.
|
|
|
|
[cols="1,4"]
|
|
|===
|
|
| `a < b` | a è minore di b
|
|
| `a > b` | a è maggiore di b
|
|
| `a <= b` | a è minore o uguale a b
|
|
| `a >= b` | a è maggiore o uguale a b
|
|
| `a == b` | a è uguale a b
|
|
| `a ~= b` | a non è uguale a b
|
|
|===
|
|
|
|
Gli ultimi due sono quelli a cui fare attenzione, per motivi diversi.
|
|
|
|
`~=` vuol dire «non è uguale a». La maggior parte dei linguaggi lo scrive `!=`,
|
|
e se hai già visto un programma, le tue dita scriveranno `!=` e Lua lo
|
|
rifiuterà. La tilde sulla tua tastiera sta accanto al tasto `1` o sotto il `#`, a
|
|
seconda di dove vivi.
|
|
|
|
`==` sono due segni di uguale, e non è un errore di battitura per uno solo. È
|
|
uno degli errori più comuni nella programmazione, e vale la pena fermarcisi un
|
|
momento.
|
|
|
|
Nella seconda lezione hai imparato che un segno di uguale vuol dire *metti il
|
|
lato destro nel nome a sinistra*. È una cosa che fai. Cambia qualcosa.
|
|
|
|
Due segni di uguale vogliono dire *queste due cose sono uguali?* È una domanda
|
|
che fai. Non cambia niente, e restituisce vero o falso.
|
|
|
|
[source,lua]
|
|
----
|
|
lives = 3
|
|
if lives == 3 then
|
|
----
|
|
|
|
La prima riga mette `lives` a tre. La seconda chiede se vale tre. Lavori
|
|
diversi, simboli diversi, a un carattere di distanza. Se li scambi Lua ti
|
|
coglie in fallo, e alla fine di questa lezione incontrerai l'errore che usa.
|
|
|
|
[#_when_the_answer_is_no]
|
|
=== Quando la risposta è no
|
|
|
|
Da solo, un `if` non fa proprio niente quando la risposta è falsa. Molto spesso
|
|
vuoi che succeda invece l'altra cosa, e quello è `else`.
|
|
|
|
[source,lua]
|
|
----
|
|
if lives > 0 then
|
|
message = "Ready"
|
|
else
|
|
message = "Game Over"
|
|
end
|
|
----
|
|
|
|
Viene eseguito esattamente uno dei due corpi, mai tutti e due, mai nessuno,
|
|
quindi alla fine `message` contiene sempre una delle due stringhe e mai niente.
|
|
|
|
Quando le possibilità sono più di due, `elseif` le mette in catena.
|
|
|
|
[source,lua]
|
|
----
|
|
if score >= 10000 then
|
|
rank = "ace"
|
|
elseif score >= 5000 then
|
|
rank = "pilot"
|
|
elseif score >= 1000 then
|
|
rank = "rookie"
|
|
else
|
|
rank = "passenger"
|
|
end
|
|
----
|
|
|
|
Lua prova le domande dall'alto e si ferma alla prima che è vera. Un punteggio di
|
|
6000 non è maggiore di 10000, quindi prova la successiva, che è vera, quindi
|
|
`rank` diventa `pilot` e le altre due domande non vengono mai fatte.
|
|
Quest'ultimo punto conta: anche il ramo `elseif` per 1000 è vero per un punteggio di
|
|
6000, e non viene mai raggiunto, ed è per questo che l'ordine va dal più grande
|
|
al più piccolo.
|
|
|
|
Tutta la catena ha bisogno di un solo `end`, per quante parti `elseif` contenga.
|
|
È una sola decisione, non quattro.
|
|
|
|
[#_true_false_and_nothing_at_all]
|
|
=== Vero, falso e niente del tutto
|
|
|
|
Non devi per forza confrontare due cose per ottenere un booleano. Puoi tenerne
|
|
uno.
|
|
|
|
[source,lua]
|
|
----
|
|
paused = false
|
|
----
|
|
|
|
È una variabile come tutte le altre, e il valore che contiene è il booleano
|
|
`false` in persona, scritto senza virgolette perché non è la parola «false», è
|
|
l'idea. Lo stesso vale per `true`. Una variabile che ne contiene uno può andare
|
|
dritta in un `if` senza nessun confronto:
|
|
|
|
[source,lua]
|
|
----
|
|
if paused then
|
|
----
|
|
|
|
Leggilo come «se in pausa». Si legge meglio di `if paused == true`, che fa la
|
|
stessa cosa facendo il giro lungo, e i programmatori esperti ti guarderanno
|
|
strano se lo scrivi.
|
|
|
|
Tre parole uniscono e capovolgono queste risposte.
|
|
|
|
[source,lua]
|
|
----
|
|
if alive and not shielded then
|
|
if coins > 0 or freePlay then
|
|
----
|
|
|
|
`and` è vero quando lo sono entrambi i lati. `or` è vero quando lo è uno dei due
|
|
lati, o tutti e due. `not` trasforma vero in falso e falso in vero. Si leggono
|
|
come l'inglese e, cosa insolita in programmazione, vogliono dire proprio quello
|
|
che dicono in inglese.
|
|
|
|
C'è un altro valore da conoscere, ed è quello che produce gli errori più
|
|
confusi del tuo primo anno.
|
|
|
|
[source,lua]
|
|
----
|
|
overlayPrint(0, 0, "lives " .. tostring(lives))
|
|
----
|
|
|
|
Se in `lives` non hai mai messo niente, quella riga stampa `lives nil`. Lua non
|
|
si lamenta di un nome che non ha mai visto: ti dà `nil`, che è la sua parola per
|
|
*qui non c'è niente*. Non è zero e non è una stringa vuota. Zero è un numero che
|
|
volevi memorizzare. `nil` è l'assenza di un valore.
|
|
|
|
Hai già incontrato `nil` due volte senza saperlo. `frames = frames + 1` senza la
|
|
riga `frames = 0` sopra fallisce perché hai chiesto a Lua di aggiungere uno a
|
|
niente. E anche una callback scritta male è `nil`, ed è per questo che una
|
|
`onOverlayUpdate` scritta male ti dà una finestra nera e nessun errore: Singe
|
|
cerca il nome, non ci trova niente e se ne va tranquillo per la sua strada.
|
|
|
|
`tostring` è in quella riga perché `..` non unisce a niente un booleano o un
|
|
`nil`. I numeri li converte per te; questi no. Era la promessa della fine della
|
|
seconda lezione, e ora sai a che cosa serve.
|
|
|
|
Infine, la regola che tiene insieme tutta la sezione, perché `if` accetta
|
|
qualsiasi cosa gli dai, non solo vero e falso:
|
|
|
|
[quote]
|
|
In Lua tutto è vero tranne `false` e `nil`.
|
|
|
|
Zero è vero. Una stringa vuota è vera. Solo quei due non lo sono, e una volta che
|
|
lo sai, `if movingLeft then` si legge benissimo sia che `movingLeft` contenga
|
|
`true`, sia che contenga `false`, sia che non sia mai stata impostata.
|
|
|
|
[#_reading_the_controls]
|
|
=== Leggere i comandi
|
|
|
|
È ora di chiedere qualcosa al giocatore. Per questo serve una nuova callback.
|
|
|
|
[source,lua]
|
|
----
|
|
function onInputPressed(what)
|
|
if what == SWITCH_RIGHT then
|
|
boxX = boxX + 10
|
|
end
|
|
end
|
|
----
|
|
|
|
`onInputPressed` è la seconda callback che scrivi, e funziona esattamente come
|
|
descritto nella prima lezione: tu la scrivi, Singe la chiama.
|
|
`onOverlayUpdate` viene chiamata a tempo. Questa viene chiamata quando succede
|
|
qualcosa -- quando il giocatore preme qualsiasi cosa il motore riconosca.
|
|
|
|
La differenza rispetto a `onOverlayUpdate` è la parola dentro le parentesi.
|
|
Singe deve dirti *quale* comando è stato premuto, quindi passa un valore alla
|
|
funzione, e `what` è il nome con cui hai scelto di riceverlo. La prima lezione
|
|
chiamava argomenti le cose che passi a una funzione; visto da dentro, il nome
|
|
che ne riceve uno è un *parametro*. Il nome è tuo: chiamalo `what`, chiamalo
|
|
`button`, chiamalo `k`. Singe lo riempie in ogni caso.
|
|
|
|
`SWITCH_RIGHT` è un nome che il motore ha già dato a un valore, come
|
|
`OVERLAY_UPDATED` nella prima lezione. Per usarlo non devi caricare niente:
|
|
Singe li definisce tutti prima che il tuo script parta. Ce n'è uno per ogni cosa
|
|
che ha un cabinato:
|
|
`SWITCH_LEFT`, `SWITCH_RIGHT`, `SWITCH_UP`, `SWITCH_DOWN`, da `SWITCH_BUTTON1`
|
|
a `SWITCH_BUTTON4`, `SWITCH_START1`, `SWITCH_COIN1` e altri ancora. La tabella
|
|
Costanti del motore del riferimento copre tutta la famiglia, che va da
|
|
`SWITCH_UP` a `SWITCH_RECORD`. Di proposito non si chiamano «il tasto freccia destra», perché
|
|
lo stesso `SWITCH_RIGHT` arriva sia che il giocatore abbia premuto un tasto
|
|
freccia, sia che abbia spinto un joystick o la levetta di un controller. Scrivi
|
|
il gioco una volta e funziona con tutti e tre.
|
|
|
|
Aggiungi quella callback, dai a `boxX` un valore iniziale fuori dalle funzioni e
|
|
disegna qualcosa in `boxX`. Premi la freccia destra. Il riquadro salta di dieci
|
|
pixel ogni volta che la premi.
|
|
|
|
[#_it_happened_and_it_is_happening]
|
|
=== È successo, e sta succedendo
|
|
|
|
Tieni premuto il tasto freccia. Non succede nient'altro.
|
|
|
|
`onInputPressed` viene chiamata una volta, mentre il tasto scende, e non di
|
|
nuovo finché non lo lasci e lo premi ancora. Non c'è ripetizione automatica. Per
|
|
certe cose è esattamente giusto -- sparare un colpo, inserire un gettone,
|
|
scegliere una voce di menu -- e per camminare è esattamente sbagliato, perché
|
|
camminare deve continuare a succedere finché il tasto resta premuto.
|
|
|
|
Sono davvero due domande diverse. *È successo* è un evento, e lo vieni a sapere
|
|
una volta. *Sta succedendo* è uno stato, e dura. Singe ti informa degli eventi,
|
|
e il modo per trasformare gli eventi in uno stato è ricordarli da te.
|
|
|
|
Due callback, con una variabile in mezzo.
|
|
|
|
[source,lua]
|
|
----
|
|
movingRight = false
|
|
|
|
|
|
function onInputPressed(what)
|
|
if what == SWITCH_RIGHT then
|
|
movingRight = true
|
|
end
|
|
end
|
|
|
|
|
|
function onInputReleased(what)
|
|
if what == SWITCH_RIGHT then
|
|
movingRight = false
|
|
end
|
|
end
|
|
----
|
|
|
|
`onInputReleased` è la terza callback, ed è lo specchio della seconda: Singe la
|
|
chiama quando il tasto risale, con lo stesso valore `SWITCH_`. Insieme fanno in
|
|
modo che `movingRight` dica sempre la verità su quello che sta facendo in questo
|
|
momento il dito del giocatore.
|
|
|
|
Non si è ancora mosso niente, ed è proprio questo il punto. Premere e muoversi
|
|
ora sono due lavori separati. Il movimento va dove va tutto il lavoro da fare a
|
|
ogni fotogramma.
|
|
|
|
[source,lua]
|
|
----
|
|
function onOverlayUpdate()
|
|
if movingRight then
|
|
boxX = boxX + BOX_SPEED
|
|
end
|
|
...
|
|
----
|
|
|
|
Ora il riquadro scivola fluido finché il tasto resta premuto, a una velocità che
|
|
decidi tu, e i calcoli sono tornati dove devono stare, nell'unica funzione che
|
|
gira sessanta volte al secondo. Questa forma -- gli eventi impostano dei flag,
|
|
il fotogramma agisce sui flag -- è il modo in cui quasi ogni gioco gestisce i
|
|
comandi, e la userai di nuovo in ogni lezione in cui c'è un giocatore.
|
|
|
|
[#_drawing_a_box]
|
|
=== Disegnare un riquadro
|
|
|
|
`overlayBox` prende due angoli: il lato sinistro e quello in alto del
|
|
rettangolo, poi il destro e quello in basso.
|
|
|
|
[source,lua]
|
|
----
|
|
colorForeground(255, 220, 0)
|
|
overlayBox(boxX, boxY, boxX + BOX_SIZE, boxY + BOX_SIZE)
|
|
----
|
|
|
|
Disegna un *contorno*, quattro linee spesse un pixel, e non un rettangolo pieno.
|
|
Tra le chiamate per disegnare sull'overlay un rettangolo pieno proprio non c'è.
|
|
Quando più avanti vorrai un blocco pieno ci sono modi per ottenerlo, e la nona
|
|
lezione ti mostra quello solito.
|
|
|
|
I suoi numeri sono pixel, non celle di carattere. Questo trae in inganno, perché
|
|
`overlayPrint` nella seconda lezione contava in celle da sei pixel per tredici e
|
|
tutto il resto di Singe conta in pixel. `overlayPrint` è l'eccezione; le altre
|
|
chiamate per disegnare -- `overlayBox`, `overlayLine`, `overlayCircle`,
|
|
`overlayEllipse` e `overlayPlot` -- lavorano tutte negli stessi pixel che
|
|
riporta `overlayGetWidth`.
|
|
|
|
`colorForeground` imposta il colore, con tre numeri da 0 a 255: quanto rosso,
|
|
quanto verde, quanto blu. Tutti e tre a 255 è bianco, tutti a 0 è nero, e
|
|
`(255, 220, 0)` è un giallo caldo. Nota che non è un argomento di `overlayBox`.
|
|
È un'impostazione: la cambi, e tutto quello che disegni dopo esce nel nuovo
|
|
colore finché non la cambi di nuovo. `overlayPrint` è ancora una volta
|
|
l'eccezione -- il font da console arriva con i suoi colori già incorporati e ti
|
|
ignora.
|
|
|
|
[#_the_whole_thing_2]
|
|
=== Tutto insieme
|
|
|
|
[source,lua]
|
|
----
|
|
BOX_SIZE = 20
|
|
BOX_SPEED = 2
|
|
|
|
width = overlayGetWidth()
|
|
height = overlayGetHeight()
|
|
maxX = width - BOX_SIZE - 1
|
|
maxY = height - BOX_SIZE - 1
|
|
|
|
boxX = width // 2
|
|
boxY = height // 2
|
|
|
|
movingLeft = false
|
|
movingRight = false
|
|
movingUp = false
|
|
movingDown = false
|
|
|
|
|
|
function onInputPressed(what)
|
|
if what == SWITCH_LEFT then
|
|
movingLeft = true
|
|
elseif what == SWITCH_RIGHT then
|
|
movingRight = true
|
|
elseif what == SWITCH_UP then
|
|
movingUp = true
|
|
elseif what == SWITCH_DOWN then
|
|
movingDown = true
|
|
end
|
|
end
|
|
|
|
|
|
function onInputReleased(what)
|
|
if what == SWITCH_LEFT then
|
|
movingLeft = false
|
|
elseif what == SWITCH_RIGHT then
|
|
movingRight = false
|
|
elseif what == SWITCH_UP then
|
|
movingUp = false
|
|
elseif what == SWITCH_DOWN then
|
|
movingDown = false
|
|
end
|
|
end
|
|
|
|
|
|
function onOverlayUpdate()
|
|
if movingLeft and not movingRight then
|
|
boxX = boxX - BOX_SPEED
|
|
elseif movingRight and not movingLeft then
|
|
boxX = boxX + BOX_SPEED
|
|
end
|
|
|
|
if movingUp and not movingDown then
|
|
boxY = boxY - BOX_SPEED
|
|
elseif movingDown and not movingUp then
|
|
boxY = boxY + BOX_SPEED
|
|
end
|
|
|
|
if boxX < 0 then
|
|
boxX = 0
|
|
elseif boxX > maxX then
|
|
boxX = maxX
|
|
end
|
|
|
|
if boxY < 0 then
|
|
boxY = 0
|
|
elseif boxY > maxY then
|
|
boxY = maxY
|
|
end
|
|
|
|
overlayClear()
|
|
|
|
if movingLeft or movingRight or movingUp or movingDown then
|
|
colorForeground(255, 220, 0)
|
|
else
|
|
colorForeground(80, 160, 255)
|
|
end
|
|
|
|
overlayBox(boxX, boxY, boxX + BOX_SIZE, boxY + BOX_SIZE)
|
|
overlayPrint(0, 0, "x " .. boxX .. " y " .. boxY)
|
|
return OVERLAY_UPDATED
|
|
end
|
|
----
|
|
|
|
Lì dentro ci sono quattro cose che meritano una seconda occhiata.
|
|
|
|
`movingLeft and not movingRight` c'è perché un giocatore può tenere premute
|
|
tutte e due le frecce insieme. Senza il `not`, le due litigherebbero e il
|
|
riquadro tremolerebbe o andrebbe alla deriva; se invece c'è, tenerle premute
|
|
tutte e due vuol dire che non vince nessuna e il riquadro sta fermo, che è
|
|
quello che un giocatore si aspetta.
|
|
|
|
`maxX` viene calcolato una volta sola in cima, usando `overlayGetWidth` come
|
|
nella seconda lezione, e il `- 1` c'è perché l'ultimo pixel della superficie è
|
|
uno in meno della sua larghezza. Togli il `- 1` e il lato destro del riquadro
|
|
cade fuori dalla superficie e sparisce, perché Singe butta via senza lamentarsi
|
|
tutto quello che disegni fuori dall'overlay.
|
|
|
|
I blocchi di contenimento usano `elseif` invece di due blocchi `if` separati. Il
|
|
riquadro non può essere oltre il bordo sinistro e oltre il bordo destro nello
|
|
stesso momento, quindi fare la seconda domanda quando la prima era vera è
|
|
lavoro sprecato.
|
|
|
|
E la decisione sul colore è un `if` che ha il solo compito di scegliere un
|
|
valore. Giallo mentre il giocatore fa qualcosa, blu quando non fa niente: un
|
|
modo gratuito per vedere che la tua gestione dei comandi funziona davvero.
|
|
|
|
[#_try_it_3]
|
|
=== Prova tu
|
|
|
|
. *Cambia la velocità.* `BOX_SPEED = 1` e `BOX_SPEED = 8`. A otto, guarda che
|
|
cosa fa il contenimento quando spingi il riquadro in un angolo.
|
|
. *Mostra i tuoi flag.* Aggiungi una riga a `onOverlayUpdate`:
|
|
`overlayPrint(0, 1, "left " .. tostring(movingLeft))`. Premi e rilascia la
|
|
freccia sinistra e guardalo cambiare. Poi togli il `tostring` e leggi l'errore
|
|
che ti dà Lua.
|
|
. *Fallo andare più veloce quando un pulsante è premuto.* Aggiungi un flag
|
|
`running` comandato da `SWITCH_BUTTON1` nelle due callback dei comandi, e usa
|
|
un `if` in `onOverlayUpdate` per muoverti del doppio di `BOX_SPEED` finché è
|
|
vero.
|
|
. *Segna il centro.* Disegna un secondo riquadro, piccolo, al centro della
|
|
finestra, che cambi colore quando il riquadro del giocatore ci si sovrappone.
|
|
Ti servirà `and` per unire quattro confronti, ed è più difficile di quanto
|
|
sembri. Sbagliarlo un po' è normale; l'undicesima lezione lo fa per bene.
|
|
. *Togli i rilasci.* Cancella tutta la funzione `onInputReleased` ed eseguilo.
|
|
Il riquadro fa un passo e poi non si ferma più. Scopri quale riga ora non
|
|
viene mai raggiunta.
|
|
|
|
[#_break_it_on_purpose_3]
|
|
=== Rompilo apposta
|
|
|
|
Trova il blocco di contenimento e cambia il `<` del suo primo confronto in un
|
|
segno di uguale singolo, così che diventi:
|
|
|
|
[source,lua]
|
|
----
|
|
if boxX = 0 then
|
|
----
|
|
|
|
Salvalo. La finestra resta lì vuota e il terminale dice:
|
|
|
|
----
|
|
Error running script: decisions/decisions.singe:57: 'then' expected near '='
|
|
----
|
|
|
|
È l'errore da cui metteva in guardia tutta la parte su `==`, e il messaggio è un
|
|
buon esempio di errore del tutto esatto e del tutto inutile se lo prendi alla
|
|
lettera. Lua non ti sta chiedendo di aggiungere la parola `then`. Lua è arrivato
|
|
fino a `if boxX`, subito dopo si aspettava un confronto o un `then`, e ha
|
|
trovato `=`, che non può essere né l'uno né l'altro.
|
|
|
|
Ogni volta che vedi `'then' expected` dopo un `if`, cerca un `=` singolo che
|
|
dovrebbe essere doppio. È quasi sempre quello.
|
|
|
|
Nota dove è comparso questo: il gioco non è mai partito, come per la
|
|
stringa non chiusa della prima lezione, perché Lua non riusciva a leggere il
|
|
file. L'errore del contatore dei fotogrammi nella seconda lezione è successo
|
|
durante l'esecuzione. Gli errori nella forma del tuo codice ti fermano prima che
|
|
il gioco cominci. Gli errori in quello che il tuo codice fa aspettano che venga
|
|
eseguito.
|
|
|
|
[#_what_you_learned_3]
|
|
=== Cosa hai imparato
|
|
|
|
* `if question then ... end` esegue un corpo solo quando la risposta è vera.
|
|
* `else` dà l'altro caso, e `elseif` ne mette in catena altri; vince la prima
|
|
domanda vera e le altre non vengono mai fatte.
|
|
* I confronti sono `<`, `>`, `<=`, `>=`, `==` e `~=`.
|
|
* `=` mette un valore in un nome. `==` chiede se due cose sono uguali.
|
|
* `true` e `false` sono valori, e puoi tenerli in delle variabili.
|
|
* `and`, `or` e `not` uniscono e capovolgono quelle risposte.
|
|
* `nil` è quello che ottieni da un nome che non hai mai impostato, e non è zero.
|
|
* Tutto è vero tranne `false` e `nil`.
|
|
* `onInputPressed` e `onInputReleased` sono callback che Singe chiama con un
|
|
valore `SWITCH_` quando il giocatore preme o lascia andare un comando.
|
|
* Una pressione è un evento e succede una volta; tieni lo stato in una variabile
|
|
e agisci in base a quello a ogni fotogramma.
|
|
* `overlayBox` disegna un contorno in pixel, e `colorForeground` è
|
|
un'impostazione, non un argomento.
|
|
|
|
[#_next_time_3]
|
|
=== La prossima volta
|
|
|
|
Un riquadro è facile. Cento stelle no, almeno non nel modo in cui hai scritto le
|
|
cose finora, perché scrivere cento righe `overlayPlot` non è l'idea di bella
|
|
serata di nessuno. La quarta lezione è il ciclo: dire al computer di fare la
|
|
stessa cosa molte volte, con qualcosa di diverso a ogni giro, ed è questo che
|
|
rende possibile uno schermo pieno di qualsiasi cosa.
|