singe/docs/it/lessons/13-game-folder.adoc

414 lines
18 KiB
Text

[#_lesson_13_a_game_folder]
== Lezione 13: La cartella del gioco
image::learn/13-game-folder.png[La lezione finita, 480]
Il tuo gioco è uno script in una cartella di cui ricordi il nome, avviato
scrivendo il suo nome in un terminale. Per te va bene, e per chiunque altro non
serve a niente. Un giocatore dovrebbe poter copiare una cartella accanto a
Singe, avviare il menu, vedere il tuo gioco nell'elenco con il suo titolo e la
sua grafica, e premere un pulsante. L'immagine qui sopra è quel menu, con
dentro il tuo gioco.
Serve un file nuovo, lungo più o meno sei righe, e due immagini che puoi fare
con un tasto. Il tuo script non cambia per niente.
[#_give_the_game_a_name]
=== Dai un nome al gioco
Un gioco ha due nomi, uno per il computer e uno per le persone.
Quello per il computer è la cartella, e l'hai scelto nella nona lezione:
`rocks`, con dentro `rocks.singe`. La cartella e lo script hanno lo stesso
nome, come in ogni lezione dalla prima in poi, ed è per questo che
`Singe rocks` trova lo script partendo solo dalla cartella. Tieni quel nome
semplice. Niente spazi, che un terminale legge come lo stacco tra due nomi. E
le stesse maiuscole dovunque lo scrivi: sulla maggior parte dei computer che
non sono Windows, `rocks` e `Rocks` sono due cartelle diverse, e un gioco che
funziona solo sulla tua macchina non è un gioco che possa avere qualcun altro.
Il nome per le persone può essere quello che vuoi, maiuscole, spazi e tutto il
resto, e non sta nel nome della cartella. Sta nel file di cui parla questa
lezione, così cambiare il nome del gioco nel menu non vuol mai dire rinominare
una cartella.
[#_what_goes_in_the_folder]
=== Che cosa va nella cartella
Tutto ciò che serve al tuo gioco, e nient'altro. Alla fine di questa lezione ha
questo aspetto:
----
rocks/
games.dat Quello che legge il menu
rocks.singe Il gioco
art/ Il kit di grafica della nona lezione
spaceship.png
asteroid.png
bullet.png
star.png
shoot.wav
boom.wav
...
cabinet.png Un'immagine che il menu mostra accanto all'elenco
marquee.png Un'immagine che il menu mostra sopra l'elenco
----
Qualunque altra cosa ci sia finita dentro mentre imparavi -- `walk.singe` della
nona lezione, la piccola prova del suono della decima -- non fa parte del
gioco. Spostale in una cartella tutta loro accanto a `rocks`. Anche il kit di
grafica ha qualche file che questo gioco non carica mai, e per adesso non fanno
danni. È nella trentesima lezione che passi in rassegna la cartella di un gioco
e togli tutto ciò che non è il gioco.
La regola dietro questa struttura è che un gioco non va mai a prendere niente
fuori dalla propria cartella. Né la grafica, né un suono, né una libreria che
usi anche in un altro gioco -- se condividi del codice tra due giochi, ognuno
tiene la propria copia. C'è esattamente un posto fuori dalla cartella da cui un
gioco può caricare, e ci stai già caricando: la cartella `Singe` del motore
stesso, dove sta `Singe/Framework.singe` e, dalla decima lezione, il clic e la
musica.
La cartella del gioco sta nella tua cartella di lavoro, accanto al motore:
----
singe/ La tua cartella di lavoro
Singe-v3.00-... Il motore, comunque si chiami il tuo
Menu.sh Avvia il menu. Menu.bat su Windows
Singe/ File di supporto. Non sono tuoi; lasciali stare
data/ Tutto ciò che viene scritto, tra cui il tuo salvataggio
rocks/ Il tuo gioco
----
È la stessa forma che ha anche la macchina di un giocatore. Il motore ha
scritto `Singe`, `data` e `Menu.sh` (`Menu.bat` su Windows) la prima volta che
hai eseguito qualcosa, nella prima lezione. Le prime due cose le nominava la
prima lezione. La terza è nuova per te, e questa lezione la mette al lavoro.
[#_paths_count_from_where_singe_started]
=== I percorsi partono da dove è stato avviato Singe
Lo fai dalla nona lezione, quindi questo è un promemoria, non un cambiamento.
Ogni nome che il tuo gioco carica -- `art/spaceship.png`, `art/boom.wav` --
viene cercato a partire dalla cartella in cui Singe è stato *avviato*, non da
quella in cui sta il tuo script. Tu avvii Singe nella tua cartella di lavoro,
quindi un `art/spaceship.png` da solo verrebbe cercato in `singe/art`, che non
esiste. `DIR` è la cartella del tuo script con la barra già in fondo, quindi un
nome attaccato in coda punta al tuo file da dovunque sia stato avviato Singe:
[source,lua]
----
local shipSprite = spriteLoad(DIR .. "art/spaceship.png")
----
Il menu avvia Singe nella cartella in cui sta `Menu.sh`, che è di nuovo la tua
cartella di lavoro, quindi lì `DIR` fa esattamente quello che fa per te. E
continua a farlo quando il gioco viene impacchettato in un unico file nella
trentesima lezione, quando la cartella di lavoro di qualcun altro si chiama in
tutt'altro modo, e su una macchina che non vedrai mai. Un nome che comincia con
`Singe/` è la cartella del motore e non ha mai bisogno di `DIR`; ogni nome che
è tuo sì.
[#_games_dat]
=== games.dat
`games.dat` è il modo in cui un gioco si presenta. Il menu legge il `games.dat`
di ogni cartella di gioco che ha accanto ed elenca quello che trova. Niente
`games.dat`, niente posto nell'elenco: la tua cartella è invisibile, per quanto
sia bello il gioco che contiene.
Crea un nuovo file chiamato `games.dat` nella tua cartella `rocks`. Questo è il
più piccolo che funziona:
[source,lua]
----
GAMES = {
{
TITLE = "Rocks",
SCRIPT = "rocks/rocks.singe"
}
}
----
È Lua, ed è una tabella del tipo che hai incontrato nella sesta lezione:
`GAMES` è un elenco, e ogni cosa nell'elenco è un record che descrive un gioco.
Una cartella può contenere più giochi -- ecco perché è un elenco -- ma la tua
ne contiene uno.
`SCRIPT` è il campo che serve al motore per avviare il gioco, e `TITLE` quello
che serve al menu per elencarlo. Il percorso dello script parte dalla cartella
*sopra* il `games.dat`, non dalla cartella in cui sta il
`games.dat`. Quindi un `games.dat` dentro `rocks` indica il proprio script come
`rocks/rocks.singe`. Sembra che dica `rocks` due volte, ed è giusto così. Ogni
altro percorso nel file funziona allo stesso modo. Sbaglialo e, quando scrivi
il nome, nessuno si lamenta: semplicemente la voce non corrisponde mai allo
script che hai avviato.
`TITLE` è il nome per le persone di cui parlava l'inizio di questa lezione. È
quello che mostra il menu, e i giochi sono elencati in ordine di titolo, quindi
il titolo decide anche dove si trova il tuo gioco nell'elenco.
[#_telling_the_menu_more]
=== Dire di più al menu
Il menu ha un intero pannello da riempire accanto all'elenco, e lo riempie con
il resto della voce:
[source,lua]
----
GAMES = {
{
TITLE = "Rocks",
SCRIPT = "rocks/rocks.singe",
CANVAS_X = 720,
CANVAS_Y = 480,
YEAR = 2026,
GENRE = "Shooter",
DEVELOPER = "Your Name Here",
PUBLISHER = "Your Name Here",
DESCRIPTION = "Shoot the rocks before they reach your ship.",
CABINET = "rocks/cabinet.png",
MARQUEE = "rocks/marquee.png"
}
}
----
`CABINET` e `MARQUEE` sono normali file di immagine nella cartella del tuo
gioco, in qualunque formato Singe sappia leggere. La grafica del cabinato è
l'immagine grande accanto all'elenco e il marquee è la striscia sopra. Falli
grandi quanto vuoi; il menu li adatta ai loro pannelli.
Per farli non ti serve un programma di disegno, perché il tuo gioco sa
fotografarsi da solo. Eseguilo, e quando lo schermo ha l'aspetto con cui vuoi
che lo veda il mondo, premi F12 (o F11, perché alcuni desktop tengono F12 per
sé). Singe salva un'immagine della finestra nella cartella dei dati del tuo
gioco, `data/rocks`, con il nome `singe000.png`, poi `singe001.png`, e così
via. Fanne una della schermata del titolo e una nel mezzo di una battaglia.
Copiale nella tua cartella `rocks` e rinominale: la battaglia è `cabinet.png`,
il titolo è `marquee.png`.
Un vero marquee è una striscia larga con il nome del gioco a lettere grandi, e
uno schermo intero schiacciato lì dentro sembra un francobollo. Andrà bene
finché non avrai qualcosa di meglio. Lascia fuori `MARQUEE` e il menu ci mette
al suo posto l'immagine mancante del motore stesso, una scacchiera rosa con
scritto MISSING, che è peggio.
`YEAR`, `GENRE`, `DEVELOPER`, `PUBLISHER` e `DESCRIPTION` sono il testo sotto,
e il motore non li guarda mai. Sono per la persona che legge il menu, ed è
proprio questo lo scopo.
`CANVAS_X` e `CANVAS_Y` sono la dimensione del mondo del tuo gioco, e 720 per
480 è il valore predefinito -- lo stesso mondo in cui disegni dalla prima
lezione. Impostali solo se il tuo gioco vuole una forma diversa. Un gioco senza
il campo `VIDEO` è un gioco senza video, ed è il caso del tuo; è nella
quattordicesima lezione che quel campo comincia a contare.
La sezione `games.dat` del Riferimento elenca tutti i campi che esistono,
compresi diversi per hardware che non hai ancora. Di alcuni altri vale la pena
conoscere il nome già adesso.
`REQUIRES` dice di che cosa ha bisogno un gioco dalla macchina oltre al
semplice 2D: `"GUI"` per i menu e le pagine della ventesima lezione, `"SCENE"`
per il 3D che comincia nella ventiduesima, e qualche altro. Il menu lo legge
per poter dire a un giocatore «questa macchina quello non lo può eseguire»
invece di lasciare che il gioco si pianti a metà strada. Rocks è semplice 2D,
e lasciare fuori `REQUIRES` vuol dire esattamente questo, quindi lascialo
fuori. Raramente dovrai ricavare l'elenco da solo, perché Singe si accorge di
quello che un gioco usa mentre gira e lo dice quando la voce non lo elenca.
Dalla ventesima lezione in poi vedrai righe come questa, che il gioco abbia o
no un `games.dat`:
----
Warning: this game uses GUI, which its games.dat does not list in REQUIRES.
----
È un consiglio, non un errore; il gioco gira lo stesso. La cura è una riga
nella voce, `REQUIRES = { "GUI" },`, e impacchettare un gioco, nella
trentesima lezione, ti scrive l'elenco se la voce non ne ha uno. Il suo
compagno `TIER`, un numero da 0 a 3, dice quanta macchina vuole un gioco, e
può aspettare finché non scrivi un gioco abbastanza pesante da preoccupartene.
`GAME_ID` è un'identità unica per il tuo gioco, che serve alle classifiche
online della ventottesima lezione e a nient'altro. E `RESOLUTION_X` e
`RESOLUTION_Y` chiedono una dimensione particolare della finestra. Ignora il
resto finché qualcosa non ti manda a cercarlo.
[#_running_it_from_the_menu]
=== Avviarlo dal menu
Esegui `Menu.sh` -- `Menu.bat` su Windows -- dalla tua cartella di lavoro.
Trova il Singe più recente che ha accanto e avvia il menu.
Il tuo gioco è nell'elenco, con la sua grafica accanto e la sua descrizione
sotto. È l'unica cosa nell'elenco, perché `rocks` è l'unica cartella a cui hai
dato un `games.dat`; per quanto ne sa il menu, `hello`, `dodge` e gli altri non
sono giochi. Su e giù si spostano di un gioco, sinistra e destra di una pagina,
e start o un pulsante di fuoco avviano quello selezionato. Esci dal gioco con
Esc e sei di nuovo nel menu, sullo stesso gioco, pronto a ripartire. Il menu si
ricorda su quale gioco eri anche da un avvio all'altro.
Ecco tutto quello che serve per distribuire un gioco, per quanto riguarda il
motore. Un giocatore copia la tua cartella accanto a Singe e il gioco compare.
Scrivere il nome funziona ancora, e funziona allo stesso modo:
----
Singe rocks
----
Quando avvii a mano uno script in questo modo, Singe cerca un `games.dat` lì
accanto -- e fino a tre cartelle più su -- e se una voce nomina lo script che
hai avviato, le impostazioni di quella voce valgono per lui. Così un gioco si
comporta da un terminale come dal menu, il che vuol dire che puoi continuare a
lavorare come hai fatto finora, con `-R` e un editor di testo, e fidarti
comunque di quello che otterrà un giocatore. E scrive anche nello stesso posto:
comunque lo avvii, il salvataggio del tuo gioco è quello in `data/rocks`.
[#_later_one_file]
=== Più avanti: un solo file
In una cartella è facile lavorare, ed è un po' scomodo regalarla: una dozzina di
file, una cartella dentro una cartella, e un giocatore che la estrae nel posto
sbagliato. Un gioco Singe finito può essere impacchettato in un unico file
`.game` che il motore esegue direttamente, grafica, suoni e tutto il resto, e
che un giocatore copia accanto a Singe, e ha finito.
Per questo nel tuo gioco non deve cambiare niente. È la trentesima lezione, e
vale la pena aspettarla: impacchetta un gioco non finito e domani lo
impacchetterai di nuovo.
[#_what_just_happened_9]
=== Cos'è appena successo
[source,lua]
----
GAMES = {
{
----
Due graffe, perché è un elenco di record. Quella esterna è l'elenco. Quella
interna è la prima cosa nell'elenco, cioè il record di un gioco. Sbagliarne una
è l'errore tipico, e Lua ti dirà la riga.
[source,lua]
----
SCRIPT = "rocks/rocks.singe",
----
Parte dalla cartella sopra il `games.dat`, che è la tua cartella di lavoro. È
lo stesso nome che scriveresti dopo `Singe` per avviare lo script a mano, ed è
il modo più facile per ricordartelo.
La virgola in fondo alla riga separa un campo dal successivo, esattamente come
nella sesta lezione. L'ultimo campo di un record non ha la virgola dopo -- a
Lua non importa se ce l'ha, ma lasciala fuori e il tuo file somiglierà a quelli
di tutti gli altri. Una virgola che manca in mezzo è un'altra faccenda, ed è
l'errore di questa lezione.
[source,lua]
----
CABINET = "rocks/cabinet.png",
----
Un'immagine che carica il menu, non il tuo gioco, quindi si indica come
`SCRIPT`, dalla cartella sopra, e non con `DIR`. `DIR` appartiene al tuo
script mentre gira, e il menu e il motore leggono `games.dat` prima che il tuo
script sia partito.
[#_try_it_13]
=== Prova tu
. *Fai una grafica migliore.* Se hai un programma di disegno, fai un
`marquee.png` come si deve: una striscia larga con ROCKS scritto a lettere
grandi. Mettilo al posto dello screenshot e guarda di nuovo il menu.
. *Dai un games.dat a Dodge.* Scrivi un `games.dat` nella tua cartella `dodge`
della settima lezione e avvia il menu. Adesso i giochi sono due, in ordine di
titolo. Poi cambia il `TITLE` di Rocks in `Asteroid Field` e guardalo salire
sopra Dodge: l'elenco è ordinato per titolo, non per cartella.
. *Rompi games.dat per il menu.* Cancella una delle graffe di chiusura nel
`games.dat` di `rocks` e avvia il menu. Il tuo gioco è sparito dall'elenco, e
il terminale dice perché. Rimettila a posto.
. *Sbaglia SCRIPT.* Metti `CANVAS_X` a `1280` e `CANVAS_Y` a `720`, ed esegui
`Singe rocks`. Il campo di gioco è più largo. Ora cambia `SCRIPT` in
`rocks.singe` ed eseguilo di nuovo. Il gioco è tornato alla sua vecchia
dimensione, e niente te l'ha detto: la voce non nomina più lo script che hai
avviato, quindi non vale. Rimetti tutti e due com'erano.
. *Trova il tuo salvataggio.* Avvia il gioco dal menu, fai un punteggio record,
esci tornando al menu ed esci dal menu. Esegui `Singe rocks` e guarda il
titolo. Poi cerca in `data/rocks` il file che se l'è ricordato.
[#_break_it_on_purpose_12]
=== Rompilo apposta
Togli la virgola in fondo alla riga di `TITLE`, così l'inizio del file
diventa:
[source,lua]
----
GAMES = {
{
TITLE = "Rocks"
SCRIPT = "rocks/rocks.singe",
----
Esegui `Singe rocks`. Il gioco parte, e il terminale dice questo:
----
Note: rocks/games.dat ignored: [string "rocks/games.dat"]:4: '}' expected (to close '{' at line 2) near 'SCRIPT'
----
Il tuo gioco gira lo stesso, perché a un gioco avviato per nome la sua voce non
serve. Semplicemente gira senza. Avvia il menu, però, e il tuo gioco è sparito.
Se era l'unico, l'elenco dice `No games yet`, e il terminale dice la stessa
cosa in un altro modo:
----
rocks/games.dat: rocks/games.dat:4: '}' expected (to close '{' at line 2) near 'SCRIPT' Skipped.
----
Leggilo come qualunque altro errore di Lua. Il file è `rocks/games.dat` e la
riga è la 4. Ma la riga 4 è quella di `SCRIPT`, e non ha niente che non va.
L'errore è alla fine della riga 3. Dopo `TITLE = "Rocks"`, Lua si aspettava o
una virgola e un altro campo, o la `}` che chiude il record cominciato alla
riga 2. Ha trovato invece `SCRIPT`, quindi è alla riga 4 che se n'è accorto.
Il suo suggerimento per la correzione -- una `}` -- è sbagliato; la sua riga è
sbagliata di uno. Quando un errore indica l'inizio di una riga, guarda la fine
della riga prima.
Rimetti la virgola e avvia di nuovo il menu.
[#_what_you_learned_13]
=== Cosa hai imparato
* Un gioco è una cartella: lo script, la sua grafica e un `games.dat`, e
niente da fuori tranne la cartella `Singe` del motore stesso.
* Il nome della cartella è per il computer, quindi tienilo semplice. Il nome
per le persone è `TITLE`.
* I nomi che il tuo script carica partono da dove è stato avviato Singe, ed è
per questo che ognuno di loro è costruito a partire da `DIR`.
* `games.dat` è un file Lua che contiene un elenco `GAMES`, e ogni voce è un
gioco.
* A una voce servono `TITLE` e `SCRIPT` e nient'altro; i percorsi al suo
interno partono dalla cartella sopra il `games.dat`.
* `CABINET`, `MARQUEE`, `YEAR`, `GENRE`, `DEVELOPER`, `PUBLISHER` e
`DESCRIPTION` sono quello che il menu mostra al giocatore, e F12 fa
un'immagine che puoi usare per i primi due.
* `REQUIRES` dice al menu di che cosa ha bisogno un gioco oltre al 2D, e Singe
ti avverte quando un gioco usa qualcosa che la sua voce non elenca.
* `Menu.sh` o `Menu.bat` avvia il menu incluso, che elenca ogni cartella di
gioco che ha accanto, in ordine di titolo.
* Anche un gioco avviato per nome riceve la sua voce di `games.dat`, quindi si
comporta allo stesso modo in tutti e due i casi, e un `games.dat` che non si
carica viene segnalato e ignorato.
* Un gioco finito si può impacchettare in un unico file più avanti, nella
trentesima lezione.
[#_next_time_13]
=== La prossima volta
Con questo la seconda parte è finita: hai un gioco, con grafica, suono,
collisioni, punteggio e un modo perché qualcun altro lo possa avviare. La terza
parte parla della cosa che quasi nessun altro motore fa -- riprodurre un
filmato come mondo in cui si svolge il gioco -- e la quattordicesima lezione
comincia con il disco, il fotogramma e l'attesa.