414 lines
18 KiB
Text
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.
|