565 lines
23 KiB
Text
565 lines
23 KiB
Text
[#_lesson_21_subtitles]
|
|
== Lezione 21: Sottotitoli
|
|
|
|
image::learn/21-subtitles.png[La lezione finita, 480]
|
|
|
|
Qualcuno che non sente giocherà al tuo gioco.
|
|
|
|
Se il tuo gioco ha del parlato e niente sottotitoli, non potrà farlo. Non nel
|
|
senso di «fa più fatica» -- arriverà alla prima scena in cui un personaggio dice
|
|
la cosa che spiega al giocatore che cosa fare, e si fermerà lì. Tutto qui, ed è
|
|
il motivo per cui questa lezione esiste invece di essere un paragrafo della
|
|
diciannovesima.
|
|
|
|
L'altro motivo è pratico. Aggiungere i sottotitoli a un gioco finito è una
|
|
tortura. Devi trovare ogni frase parlata, capire in quale fotogramma si trova,
|
|
e scoprire che metà delle tue tempistiche sono sbagliate perché il video è stato
|
|
ricodificato a metà del progetto. Fatto mentre scrivi il gioco, è un
|
|
pomeriggio. Singe ti dà un sistema che fa la parte difficile, e questa lezione
|
|
spiega come usarlo.
|
|
|
|
[#_it_is_not_ordinary_text_drawing]
|
|
=== Non è il solito testo disegnato
|
|
|
|
Potresti fare i sottotitoli da solo. Tieni un elenco di frasi con il tempo di
|
|
inizio e di fine, controlla l'orologio in `onOverlayUpdate`, e disegna quella
|
|
corrente con `fontToSprite`. C'è chi l'ha fatto. Ecco perché tu non dovresti.
|
|
|
|
I sottotitoli sono sincronizzati con *il disco*, non con un orologio. Quando
|
|
`srtLoad` legge il tuo file converte ogni marca temporale in un numero di
|
|
fotogramma del disco, lì per lì, usando la frequenza dei fotogrammi del disco
|
|
caricato. Da quel momento il motore non guarda più nessun orologio; a ogni
|
|
fotogramma disegnato chiede quale battuta copre il fotogramma su cui si trova
|
|
il disco.
|
|
|
|
Quella sola decisione ti dà la cosa che un sistema fatto in casa non azzecca
|
|
mai: *un sottotitolo sopravvive a un salto*. Manda il disco dove vuoi --
|
|
`discSearch`, `discSkipForward`, un passo, una diramazione verso un altro
|
|
segmento -- e la frase giusta compare al fotogramma disegnato successivo, in
|
|
avanti o all'indietro, senza ricaricare niente e senza azzerare nessun
|
|
orologio. In un gioco a diramazioni come quello della sedicesima lezione, dove
|
|
le scelte del giocatore fanno saltare il disco di continuo, è la differenza tra
|
|
funzionare e quasi funzionare.
|
|
|
|
Si disegna anche nel posto giusto. Il documento dei sottotitoli sta sopra
|
|
l'immagine, sopra il tuo overlay, sotto qualsiasi GUI nello spazio dello
|
|
schermo, e segue l'immagine ovunque la mettano le impostazioni del giocatore --
|
|
un'immagine rimpicciolita, una spostata, un cabinato ruotato, un'apertura in un
|
|
bezel. Non riceve input dal mouse, quindi un colpo di pistola ottica gli passa
|
|
dritto attraverso. Sistemare tutto questo da solo è una settimana che non avevi
|
|
messo in conto.
|
|
|
|
[#_write_the_file]
|
|
=== Scrivi il file
|
|
|
|
I sottotitoli vanno in un file SubRip, che finisce in `.srt` ed è testo semplice
|
|
che puoi scrivere con qualsiasi editor. È uno dei formati più semplici che
|
|
esistano. Crea un file chiamato `subtitles.srt` accanto al tuo script:
|
|
|
|
----
|
|
1
|
|
00:00:01,000 --> 00:00:04,000
|
|
They told us the cave was empty.
|
|
|
|
2
|
|
00:00:04,200 --> 00:00:08,000
|
|
They were wrong about
|
|
a great many things.
|
|
|
|
3
|
|
00:00:08,500 --> 00:00:13,000
|
|
Keep your light on the floor.
|
|
----
|
|
|
|
Una battuta è fatta di quattro cose. Un numero su una riga tutta sua. Una riga
|
|
con due marche temporali e, tra le due, una freccia fatta di due trattini e un
|
|
segno di maggiore. Una o più righe di testo. Una riga vuota per finire.
|
|
|
|
Una marca temporale è `HH:MM:SS,mmm` -- ore, minuti e secondi separati da due
|
|
punti, poi una virgola, poi i millisecondi. La virgola non è un errore di
|
|
battitura, e un punto non va bene. `00:00:04,200` vuol dire quattro secondi e
|
|
un quinto dall'inizio.
|
|
|
|
I numeri delle battute vengono letti e buttati via, quindi non devono essere in
|
|
ordine e nemmeno giusti. Numerale comunque; prima o poi ti ritroverai a cercare
|
|
la battuta quarantuno.
|
|
|
|
La battuta due mostra com'è fatta una battuta su due righe. Le righe vengono
|
|
mostrate come le hai scritte, quindi sei *tu* a decidere dove va a capo una
|
|
riga lunga, il che conta più di quanto penseresti ed è spiegato più avanti.
|
|
|
|
Il caricamento è volutamente tollerante con le cose che vanno storte in un file
|
|
scritto a mano. I fine riga di Windows si caricano senza problemi, e gli spazi
|
|
all'inizio e alla fine di ogni riga vengono tolti. Una battuta le cui marche
|
|
temporali non si riescono a leggere viene saltata e il resto del file continua
|
|
a caricarsi, il che è gentile fino al momento in cui ti chiedi dov'è finita la
|
|
riga dodici. Alcune cose non sono supportate: i tag `<i>` e `<b>` che certi
|
|
strumenti scrivono vengono mostrati come testo invece di essere applicati, e le
|
|
coordinate di posizione che certi strumenti aggiungono alla riga dei tempi
|
|
vengono ignorate. La sezione sui sottotitoli del Riferimento ha l'elenco completo.
|
|
|
|
[#_load_it_and_switch_it_on]
|
|
=== Caricalo e accendilo
|
|
|
|
Tre chiamate, e l'ordine conta.
|
|
|
|
[source,lua]
|
|
----
|
|
if srtLoad(DIR .. "subtitles.srt") then
|
|
srtPosition(80)
|
|
srtEnable(true)
|
|
end
|
|
----
|
|
|
|
`srtLoad` legge il file e risponde `true` o `false`. Risponde `false`, senza
|
|
aver caricato niente, in tre casi: il file non si può leggere, non c'è niente al
|
|
suo interno che si riesca a leggere, oppure *non c'è un disco*. In tutti e tre i
|
|
casi scrive nella console un avviso con il nome del file. È una buona scelta di
|
|
progetto e dovresti sfruttarla: un file di sottotitoli mancante non vale la
|
|
morte di un gioco, ma distribuire senza accorgertene un gioco senza sottotitoli
|
|
è una cosa che vale la pena notare.
|
|
|
|
Il caso «nessun disco» è quello in cui cadrai. Le marche temporali devono
|
|
diventare numeri di fotogramma alla frequenza dei fotogrammi del disco, e
|
|
finché non c'è un disco aperto non c'è nessuna frequenza da usare. Quindi
|
|
carica i sottotitoli *dopo* il disco, il che in uno script normale vuol dire dal
|
|
corpo dello script, dove gira tutto il resto che hai scritto al livello più
|
|
esterno. Ne segue che un `.srt` preparato per un video a una certa frequenza dei
|
|
fotogrammi finisce nel posto sbagliato su un video a un'altra. Sincronizza il
|
|
tuo file con il video che distribuirai davvero.
|
|
|
|
`srtEnable(true)` accende le battute caricate. Uno script parte con i
|
|
sottotitoli spenti, sempre, quindi un gioco che li carica deve accenderli.
|
|
Spegnerli di nuovo toglie quello che si vede, e riaccenderli mostra quello che
|
|
copre il fotogramma su cui si trova il disco in quel momento -- niente ricerche,
|
|
nessuno stato da tenere.
|
|
|
|
Tenere i sottotitoli accesi è un'impostazione, non una decisione che prendi al
|
|
posto del giocatore. Mettila nella tua pagina delle opzioni della ventesima
|
|
lezione, salvala con il `saveSet` della dodicesima, e passa a `srtEnable`
|
|
quello che il giocatore ha scelto l'ultima volta.
|
|
|
|
[#_where_they_sit]
|
|
=== Dove stanno
|
|
|
|
[source,lua]
|
|
----
|
|
srtPosition(70)
|
|
----
|
|
|
|
`srtPosition` è una percentuale dell'altezza dell'immagine, contata dall'alto,
|
|
da `1` a `95`, e il valore predefinito è `80`. Ha effetto sulla battuta che si
|
|
vede in quel momento e su tutte quelle successive. Un numero fuori
|
|
dall'intervallo viene ignorato invece di essere riportato nei limiti, il che
|
|
vuol dire che un errore di battitura lascia la posizione esattamente dov'era e
|
|
non dice niente, quindi controlla i tuoi numeri.
|
|
|
|
L'ottanta per cento è in basso, ed è in basso apposta: la parte bassa
|
|
dell'immagine di solito è la meno interessante dell'inquadratura. Spostali più
|
|
su quando la parte bassa *non* è noiosa -- quando il tuo gioco disegna un
|
|
tabellone segnapunti lungo il bordo inferiore, o quando il mirino della pistola
|
|
ottica del giocatore sta laggiù.
|
|
|
|
[#_taking_one_down]
|
|
=== Toglierne uno
|
|
|
|
[source,lua]
|
|
----
|
|
srtClear()
|
|
----
|
|
|
|
`srtClear` toglie subito dallo schermo quello che c'è, e lascia stare le
|
|
battute caricate e lo stato di accensione. La frase che si vedeva resta spenta
|
|
finché il disco non raggiunge la battuta successiva. Usalo quando una scena
|
|
finisce prima del previsto e non vuoi che l'ultima frase del dialogo resti
|
|
appesa sopra l'inquadratura successiva.
|
|
|
|
C'è un'altra chiamata che condivide il meccanismo dei sottotitoli, e forse l'hai
|
|
già usata:
|
|
|
|
[source,lua]
|
|
----
|
|
overlayBanner("Extra life!", 20)
|
|
----
|
|
|
|
`overlayBanner` mostra un breve messaggio sopra l'immagine per circa trenta
|
|
fotogrammi disegnati e poi lo toglie. Viene disegnato dallo stesso documento dei
|
|
sottotitoli, quindi un banner sembra un sottotitolo, e mentre è visibile prende
|
|
il posto di qualsiasi sottotitolo, che torna quando il banner scade. Il suo
|
|
argomento per l'altezza è separato da `srtPosition` e se non lo dai vale `47`,
|
|
il centro dell'immagine. I messaggi più lunghi di sessanta caratteri vengono
|
|
ignorati del tutto, quindi uno lungo sembra proprio non funzionare.
|
|
|
|
[#_subtitles_already_inside_the_video]
|
|
=== Sottotitoli già dentro il video
|
|
|
|
Alcuni file video portano con sé le proprie tracce di sottotitoli. Se il tuo lo
|
|
fa, non ti serve affatto un `.srt`:
|
|
|
|
[source,lua]
|
|
----
|
|
if discGetSubtitleTracks() > 0 then
|
|
srtLoadTrack(0)
|
|
else
|
|
srtLoad(DIR .. "subtitles.srt")
|
|
end
|
|
srtEnable(true)
|
|
----
|
|
|
|
`srtLoadTrack` prende un numero di traccia da `0` a
|
|
`discGetSubtitleTracks() - 1`, e dopo il caricamento tutto è identico.
|
|
`discGetSubtitleLanguage(track)` ti dice con quale lingua è etichettata una
|
|
traccia, come codice di tre lettere tipo `eng` o `fra`, così un gioco può
|
|
offrire al giocatore tutto quello che il suo video si trova ad avere.
|
|
|
|
Due avvertenze. Leggere una traccia percorre tutto il file video una volta,
|
|
senza decodificare immagini, quindi un disco lungo quanto un film richiede un
|
|
momento: fallo mentre sullo schermo c'è qualcos'altro, non tra due fotogrammi di
|
|
gioco. E le tracce di sottotitoli che contengono *immagini* delle parole invece
|
|
delle parole -- il tipo che usano i DVD e i Blu-ray -- non si possono leggere.
|
|
Vengono contate, così la numerazione corrisponde a quella che mostrano gli altri
|
|
lettori multimediali, ma per loro `srtLoadTrack` risponde `false`.
|
|
|
|
[#_the_whole_script_3]
|
|
=== Lo script completo
|
|
|
|
Questo script ha bisogno di un video. Ce l'hai: `Singe/menuBackground.mkv`, che
|
|
il motore ha estratto nella tua cartella di lavoro la prima volta che hai
|
|
eseguito qualcosa. Di' a Singe di usarlo come disco con `--framefile`, che
|
|
accende anche il disco:
|
|
|
|
----
|
|
Singe --framefile=Singe/menuBackground.mkv subtitles
|
|
----
|
|
|
|
[source,lua]
|
|
----
|
|
dofile("Singe/Framework.singe")
|
|
|
|
overlaySetResolution(discGetWidth(), discGetHeight())
|
|
|
|
local HUD_X = 16
|
|
local STEP = 5
|
|
local TOP_LIMIT = 10
|
|
local LOW_LIMIT = 95
|
|
|
|
local hudFont = fontLoad("Singe/FreeSansBold.ttf", 18)
|
|
local loaded = false
|
|
local showing = false
|
|
local height = 80
|
|
|
|
|
|
if discGetSubtitleTracks() > 0 then
|
|
loaded = srtLoadTrack(0)
|
|
end
|
|
if not loaded then
|
|
loaded = srtLoad(DIR .. "subtitles.srt")
|
|
end
|
|
|
|
if loaded then
|
|
srtPosition(height)
|
|
showing = true
|
|
srtEnable(true)
|
|
end
|
|
|
|
discPlay()
|
|
|
|
|
|
function onInputPressed(what)
|
|
if not loaded then
|
|
return
|
|
end
|
|
if what == SWITCH_BUTTON1 then
|
|
showing = not showing
|
|
srtEnable(showing)
|
|
if showing then
|
|
overlayBanner("Subtitles on", 20)
|
|
else
|
|
overlayBanner("Subtitles off", 20)
|
|
end
|
|
elseif what == SWITCH_UP then
|
|
height = math.max(TOP_LIMIT, height - STEP)
|
|
srtPosition(height)
|
|
elseif what == SWITCH_DOWN then
|
|
height = math.min(LOW_LIMIT, height + STEP)
|
|
srtPosition(height)
|
|
elseif what == SWITCH_LEFT then
|
|
srtClear()
|
|
discSearch(0)
|
|
discPlay()
|
|
end
|
|
end
|
|
|
|
|
|
function onOverlayUpdate()
|
|
overlayClear()
|
|
fontSelect(hudFont)
|
|
colorForeground(255, 255, 255)
|
|
if loaded then
|
|
if showing then
|
|
fontPrint(HUD_X, 16, "Frame " .. discGetFrame() .. " subtitles ON at " .. height .. "%")
|
|
else
|
|
fontPrint(HUD_X, 16, "Frame " .. discGetFrame() .. " subtitles OFF")
|
|
end
|
|
fontPrint(HUD_X, 40, "Fire toggles them, up and down move them, left rewinds")
|
|
else
|
|
fontPrint(HUD_X, 16, "No subtitles loaded.")
|
|
fontPrint(HUD_X, 40, "Run with --framefile and check subtitles.srt is beside the script.")
|
|
end
|
|
return OVERLAY_UPDATED
|
|
end
|
|
|
|
|
|
function onShutdown()
|
|
fontUnload(hudFont)
|
|
end
|
|
----
|
|
|
|
Premi fuoco per accenderli e spegnerli, su e giù per spostare le righe, e
|
|
sinistra per riavvolgere fino all'inizio. Il riavvolgimento è quello da tenere
|
|
d'occhio: il disco salta indietro al fotogramma zero e la battuta giusta compare
|
|
proprio al fotogramma successivo, senza che tu faccia niente.
|
|
|
|
[#_what_just_happened_17]
|
|
=== Cos'è appena successo
|
|
|
|
[source,lua]
|
|
----
|
|
if discGetSubtitleTracks() > 0 then
|
|
loaded = srtLoadTrack(0)
|
|
end
|
|
if not loaded then
|
|
loaded = srtLoad(DIR .. "subtitles.srt")
|
|
end
|
|
----
|
|
|
|
Prendi i sottotitoli del video quando ce li ha, ripiega sul file accanto allo
|
|
script quando non li ha, e alla fine sai quale dei due -- se uno dei due -- ha
|
|
funzionato. Entrambe le chiamate rispondono con un booleano, quindi il ripiego
|
|
sono due istruzioni `if` e nessun caso speciale. `menuBackground.mkv` non ha
|
|
nessuna traccia di sottotitoli, quindi quello che otterrai davvero è il file che
|
|
hai scritto.
|
|
|
|
[source,lua]
|
|
----
|
|
function onInputPressed(what)
|
|
if not loaded then
|
|
return
|
|
end
|
|
----
|
|
|
|
`return` senza niente dopo esce subito dalla funzione. Senza sottotitoli
|
|
caricati nessuno di questi tasti ha qualcosa da fare, e uscire subito è più
|
|
chiaro che avvolgere tutto il corpo in un `if`. Chiamare `srtEnable` senza
|
|
niente di caricato non fa danni, ma scrivere codice che ha senso solo quando non
|
|
fa niente è un'abitudine che conviene non prendere.
|
|
|
|
[source,lua]
|
|
----
|
|
elseif what == SWITCH_LEFT then
|
|
srtClear()
|
|
discSearch(0)
|
|
discPlay()
|
|
----
|
|
|
|
La chiamata a `srtClear` non è necessaria. Il motore mostrerà comunque la
|
|
battuta giusta per il fotogramma zero al fotogramma disegnato successivo. È lì
|
|
perché tu possa cancellarla e guardare che cosa succede: la vecchia frase resta
|
|
su per una frazione di secondo mentre il disco arriva dove deve andare. Con un
|
|
salto lento quel lampo della frase sbagliata si vede, e pulire prima è il modo
|
|
per evitarlo.
|
|
|
|
[#_making_text_readable_over_a_moving_picture]
|
|
=== Rendere leggibile il testo sopra un'immagine in movimento
|
|
|
|
Il sistema mette le parole sullo schermo. Se qualcuno riesce a leggerle è un
|
|
problema tuo, e vale per ogni riga di testo che disegni sopra un video -- una
|
|
richiesta della diciottesima lezione, un punteggio, una scelta di diramazione --
|
|
non solo per i sottotitoli.
|
|
|
|
*Stai lontano dai bordi.* I televisori tagliano i bordi delle immagini da
|
|
settant'anni, e i monitor da sala giochi sono peggio, non meglio. Parti dal
|
|
presupposto che il cinque per cento più esterno dell'immagine, su ogni lato,
|
|
sullo schermo di qualcuno potrebbe proprio non esserci. Tieni lì dentro tutto
|
|
quello che il giocatore deve leggere. È per questo che `srtPosition` si ferma a
|
|
`95` e non a `100`.
|
|
|
|
*Il contrasto non è una scelta di colore, è una garanzia.* Un testo bianco
|
|
sopra un'immagine è un testo bianco sopra qualunque cosa l'immagine stia
|
|
facendo, e fra due secondi potrebbe essere un campo di neve. Lo stile dei
|
|
sottotitoli fornito con il motore lo risolve come fanno i sottotitoli dei film:
|
|
un pannello scuro che avvolge il testo, più un'ombra di un pixel. Se disegni tu
|
|
del testo sopra un video, fai l'una o l'altra cosa -- un `overlayBox` dietro, o
|
|
una copia scura del testo spostata di un pixel. Non contare sull'immagine.
|
|
|
|
*Vai a capo tu.* Due righe corte si leggono più in fretta di una lunga, e una
|
|
riga che va a capo dove non l'hai deciso tu di solito si spezza nel punto
|
|
sbagliato. Punta a una quarantina di caratteri per riga e non più di due righe
|
|
alla volta. Vai a capo in una pausa naturale:
|
|
`They were wrong about / a great many things` si legge; `They
|
|
were wrong / about a great many things` inciampa.
|
|
|
|
*Lasciali su abbastanza a lungo.* Una velocità di lettura comoda è intorno ai
|
|
quindici caratteri al secondo, quindi una riga di quaranta caratteri vuole più
|
|
o meno tre secondi. Guarda la battuta uno nel file qui sopra: trentadue
|
|
caratteri, tre secondi. Se una frase del dialogo è breve e rapida, tenere la
|
|
battuta su un attimo dopo la fine del parlato è più gentile che farla sparire di
|
|
colpo.
|
|
|
|
*Mettili dove non c'è l'azione.* Se la cosa importante dell'inquadratura è in
|
|
basso nel fotogramma, sposta i sottotitoli più su per quella scena con
|
|
`srtPosition`. Puoi chiamarla tutte le volte che vuoi, e il giocatore non si
|
|
accorgerà mai che l'hai fatto.
|
|
|
|
[#_styling_them]
|
|
=== Lo stile dei sottotitoli
|
|
|
|
Le righe vengono disegnate da un documento, dello stesso tipo che hai incontrato
|
|
nella ventesima lezione, e due file nella tua cartella `Singe` decidono che
|
|
aspetto hanno:
|
|
|
|
* `Singe/subtitle.rml` -- il documento. Contiene un solo elemento, `#slot`, in
|
|
cui il motore scrive la battuta o il banner del momento.
|
|
* `Singe/subtitle.rcss` -- lo stile. `.cue` è il blocco che porta l'altezza
|
|
chiesta da `srtPosition`, e `.cue .text` è la barra di testo al suo interno:
|
|
bianca, in grassetto, su un pannello scuro con gli angoli arrotondati che
|
|
avvolge il testo, con un'ombra.
|
|
|
|
Apri `subtitle.rcss` e leggilo -- sono una quarantina di righe. Poi lascialo
|
|
stare, perché una modifica lì non dura. Ogni volta che Singe parte, rimette la
|
|
propria copia di qualsiasi cosa nella cartella `Singe` sia stata cambiata, e lo
|
|
dice:
|
|
|
|
----
|
|
>>> Updated File: Singe/subtitle.rcss
|
|
----
|
|
|
|
Quella cartella è del motore. Il tuo gioco porta invece una copia sua. Copia
|
|
entrambi i file fuori da `Singe` e dentro la tua cartella `subtitles`, accanto
|
|
allo script. Poi apri la tua copia di `subtitle.rml` e cambia l'unica riga del
|
|
suo `<head>` che collega lo stile, in modo che diventi:
|
|
|
|
[source,html]
|
|
----
|
|
<link type="text/rcss" href="subtitle.rcss"/>
|
|
----
|
|
|
|
Un nome dentro un documento parte dalla cartella del documento stesso, tranne
|
|
un nome che comincia con `Singe/`, che vuol dire sempre la cartella del motore.
|
|
Il collegamento così come l'hai copiato, `Singe/subtitle.rcss`, prende ancora lo
|
|
stile del motore. Quello nuovo prende il tuo.
|
|
|
|
Quando Singe trova un `subtitle.rml` accanto al tuo script, disegna i
|
|
sottotitoli con quello invece che con il proprio. Aggiungi `-p` al comando e
|
|
Singe descrive quello che sta facendo man mano, una riga alla volta:
|
|
|
|
----
|
|
Singe -p --framefile=Singe/menuBackground.mkv subtitles
|
|
----
|
|
|
|
Quando compare la prima battuta, una di quelle righe è questa:
|
|
|
|
----
|
|
Using the game's own subtitles/subtitle.rml
|
|
----
|
|
|
|
Ora cambia `font-size`, `color`, `background-color`, `border-radius` o
|
|
`font-effect` nel tuo `subtitle.rcss`, salva ed esegui di nuovo. Il motore
|
|
imposta sempre e solo il contenuto di `#slot` e l'altezza di `.cue`, quindi
|
|
tutto il resto dei tuoi due file è tuo, e niente di quello che Singe fa
|
|
all'avvio li toccherà. Se `-p` dice che sta usando i tuoi e l'aspetto non è
|
|
cambiato, rileggi il collegamento: una copia che dice ancora `Singe/` sta usando
|
|
in silenzio lo stile del motore.
|
|
|
|
Siccome `overlayBanner` usa lo stesso documento, cambiare lo stile dei
|
|
sottotitoli cambia anche quello dei tuoi banner, il che di solito è quello che
|
|
vuoi, ed è meglio saperlo prima di chiederti perché.
|
|
|
|
Un limite: il documento dei sottotitoli è un documento, e i documenti hanno
|
|
bisogno di una GPU. Su una macchina che non ce l'ha, `srtLoad` legge comunque il
|
|
tuo file e risponde comunque il vero, e non viene disegnato niente. Un avviso lo
|
|
dice una volta.
|
|
|
|
[#_try_it_21]
|
|
=== Prova tu
|
|
|
|
. *Aggiungi una quarta battuta* a `subtitles.srt`, tra gli undici e i tredici
|
|
secondi. Salva ed esegui. Poi mettila fuori ordine, come battuta `99`, per
|
|
prima nel file, e verifica che funzioni ancora.
|
|
. *Dai a una battuta una marca temporale sbagliata* -- scrivi `00:00:05.500` con
|
|
un punto al posto della virgola -- ed esegui. Guarda quale riga sparisce, e
|
|
nota che nessuno ti dice niente. Un file che si carica non è un file giusto.
|
|
. *Cambia il loro stile.* Nel tuo `subtitle.rcss` -- la copia accanto al tuo
|
|
script, non quella in `Singe` -- cambia `.cue .text` in testo giallo su uno
|
|
sfondo del tutto trasparente, poi aggiungi un'ombra più marcata. Poi guardalo sopra il video e decidi onestamente se si legge ancora.
|
|
. *Rompi apposta la tempistica.* Cambia ogni marca temporale del file in modo
|
|
che sia in ritardo di due secondi, e guarda un sistema che funziona a dovere
|
|
consegnare sottotitoli inutili. È questo che ti fa un video ricodificato.
|
|
. *Metti il comando in un menu.* Prendi la pagina di pausa della ventesima
|
|
lezione, aggiungi una casella di controllo, e collegala a `srtEnable`. Poi
|
|
salva la scelta con `saveSet`, così la volta dopo è ancora attiva. Questa è la
|
|
versione che i tuoi giocatori vogliono davvero.
|
|
|
|
[#_break_it_on_purpose_20]
|
|
=== Rompilo apposta
|
|
|
|
Esegui lo script senza l'opzione `--framefile`:
|
|
|
|
----
|
|
Singe subtitles
|
|
----
|
|
|
|
La finestra si apre, nera, con sopra il tuo messaggio di ripiego, e la console
|
|
dice:
|
|
|
|
----
|
|
Warning: No subtitles were loaded from subtitles/subtitles.srt.
|
|
----
|
|
|
|
Nessun crash e nessuna finestra di errore, perché `srtLoad` ha risposto `false`
|
|
e il tuo script ne ha tenuto conto.
|
|
|
|
È il fallimento più prezioso di questa lezione, perché è quello che succede
|
|
senza che nessuno se ne accorga. Non c'è un disco, quindi non c'è una frequenza
|
|
dei fotogrammi, quindi non c'è niente in cui trasformare le marche temporali,
|
|
quindi non si carica niente. Se avessi scritto `srtLoad(...)` da solo e avessi
|
|
buttato via la risposta, il tuo gioco sarebbe andato alla perfezione senza
|
|
mostrare nessun sottotitolo, e l'avresti scoperto quando qualcuno te l'avesse
|
|
detto.
|
|
|
|
Usa la risposta. Ogni volta.
|
|
|
|
[#_what_you_learned_21]
|
|
=== Cosa hai imparato
|
|
|
|
* Un gioco con del parlato e senza sottotitoli è un gioco a cui alcune persone
|
|
non possono proprio giocare.
|
|
* Inserire i sottotitoli strada facendo è un pomeriggio; aggiungerli dopo no.
|
|
* I sottotitoli sono un file `.srt`: un numero, due marche temporali con `-->`
|
|
in mezzo, il testo e una riga vuota.
|
|
* `srtLoad` trasforma le marche temporali in numeri di fotogramma del disco al
|
|
momento del caricamento, ed è per questo che una battuta sopravvive a
|
|
qualsiasi salto.
|
|
* I sottotitoli vanno caricati dopo il disco, e il caricamento risponde
|
|
`false` quando non riesce, anche quando non c'è un disco. Controlla la
|
|
risposta.
|
|
* `srtEnable` li accende, e uno script parte sempre con i sottotitoli spenti.
|
|
* `srtPosition` li colloca a una percentuale dell'altezza dell'immagine,
|
|
contata dall'alto, da `1` a `95`.
|
|
* `srtClear` toglie quello che si vede, e `overlayBanner` condivide lo stesso
|
|
documento.
|
|
* `srtLoadTrack` legge i sottotitoli dal file video stesso, quando li contiene.
|
|
* Singe riscrive la sua cartella `Singe` a ogni avvio, quindi per cambiare lo
|
|
stile dei sottotitoli copi `subtitle.rml` e `subtitle.rcss` accanto al tuo
|
|
script, fai puntare il collegamento della copia al tuo foglio, e cambi quello.
|
|
* Il testo sopra un'immagine in movimento ha bisogno di un margine di
|
|
sicurezza, di un contrasto suo, di righe che hai spezzato tu e del tempo per
|
|
essere letto.
|
|
|
|
[#_next_time_21]
|
|
=== La prossima volta
|
|
|
|
Con questo il testo è finito. La quarta parte prosegue senza che tu debba
|
|
leggerla in ordine, e la prossima lezione apre una porta rimasta chiusa per
|
|
venti lezioni: `overlayGetWidth` e `overlayGetHeight` sono due numeri, e una
|
|
scena ne ha tre. La ventiduesima lezione parla del terzo.
|