[#_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.