561 lines
23 KiB
Text
561 lines
23 KiB
Text
[#_lesson_21_subtitles]
|
|
== Lección 21: Subtítulos
|
|
|
|
image::learn/21-subtitles.png[La lección terminada, 480]
|
|
|
|
Alguien que no puede oír va a jugar a tu juego.
|
|
|
|
Si tu juego tiene voces y no tiene subtítulos, no podrá. No es que «le cueste
|
|
más» -- llegará a la primera escena en la que un personaje dice lo que le
|
|
explica al jugador qué tiene que hacer, y ahí se quedará. Eso es todo, y es la
|
|
razón de que esta lección exista en lugar de ser un párrafo de la lección
|
|
diecinueve.
|
|
|
|
La otra razón es práctica. Meterle subtítulos a un juego ya terminado es un
|
|
suplicio. Tienes que encontrar cada frase hablada, averiguar en qué fotograma
|
|
está y descubrir que la mitad de los tiempos están mal porque tu vídeo se volvió
|
|
a codificar a mitad del proyecto. Si lo haces mientras escribes el juego, es
|
|
cosa de una tarde. Singe te da un sistema que hace la parte difícil, y esta
|
|
lección explica cómo usarlo.
|
|
|
|
[#_it_is_not_ordinary_text_drawing]
|
|
=== No es dibujar texto sin más
|
|
|
|
Podrías hacer los subtítulos tú mismo. Guardas una lista de frases con sus
|
|
tiempos de inicio y de fin, miras el reloj en `onOverlayUpdate` y dibujas la
|
|
actual con `fontToSprite`. Hay quien lo ha hecho. Esta es la razón por la que
|
|
tú no deberías.
|
|
|
|
Los subtítulos se sincronizan con *el disco*, no con un reloj. Cuando `srtLoad`
|
|
lee tu archivo, convierte cada marca de tiempo en un número de fotograma del
|
|
disco, en ese mismo momento, usando la tasa de fotogramas del disco que esté
|
|
cargado. A partir de entonces el motor no mira ningún reloj; en cada fotograma
|
|
dibujado pregunta qué entrada cubre el fotograma en el que está el disco.
|
|
|
|
Esa única decisión te da lo que un sistema hecho a mano nunca consigue hacer
|
|
bien: *un subtítulo sobrevive a un salto*. Manda el disco a cualquier sitio --
|
|
`discSearch`, `discSkipForward`, un paso, una ramificación a otro segmento -- y
|
|
la frase correcta está en pantalla en el siguiente fotograma dibujado, hacia
|
|
delante o hacia atrás, sin recargar nada y sin poner a cero ningún reloj. En un
|
|
juego con ramificaciones como el de la lección dieciséis, donde las decisiones
|
|
del jugador hacen saltar el disco de un lado a otro sin parar, esa es la
|
|
diferencia entre funcionar y casi funcionar.
|
|
|
|
Además se dibuja en el sitio correcto. El documento de los subtítulos está sobre
|
|
la imagen, por encima de tu overlay y por debajo de cualquier GUI en espacio de
|
|
pantalla, y sigue a la imagen allí donde la pongan los ajustes del jugador --
|
|
una imagen encogida, una desplazada, una recreativa girada, un hueco en un
|
|
bezel. No acepta entrada del ratón, así que un disparo de pistola de luz lo
|
|
atraviesa sin más. Hacer todo eso bien por tu cuenta es una semana que no
|
|
tenías prevista.
|
|
|
|
[#_write_the_file]
|
|
=== Escribe el archivo
|
|
|
|
Los subtítulos van en un archivo SubRip, que termina en `.srt` y es texto plano
|
|
que puedes escribir en cualquier editor. Es uno de los formatos más sencillos
|
|
que existen. Crea un archivo llamado `subtitles.srt` junto a tu 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 entrada son cuatro cosas. Un número en una línea propia. Una línea con dos
|
|
marcas de tiempo y, entre ellas, una flecha hecha de dos guiones y un signo de
|
|
mayor que. Una o más líneas de texto. Una línea en blanco para terminar.
|
|
|
|
Una marca de tiempo es `HH:MM:SS,mmm` -- horas, minutos y segundos separados por
|
|
dos puntos, luego una coma y luego los milisegundos. La coma no es una errata, y
|
|
un punto no sirve. `00:00:04,200` son cuatro segundos y un quinto desde el
|
|
principio.
|
|
|
|
Los números de las entradas se leen y se tiran, así que no tienen por qué estar
|
|
en orden, ni siquiera ser correctos. Numéralas de todos modos; en algún momento
|
|
estarás buscando la entrada cuarenta y uno.
|
|
|
|
La entrada dos muestra cómo es una entrada de dos líneas. Las líneas se muestran
|
|
tal como las escribiste, así que eres *tú* quien decide dónde se parte una línea
|
|
larga, lo cual importa más de lo que parece y se explica más abajo.
|
|
|
|
El analizador es tolerante a propósito con las cosas que salen mal en un archivo
|
|
editado a mano. Los finales de línea de Windows se cargan sin cambios, y los
|
|
espacios del principio y del final se quitan de cada línea. Una entrada cuyas
|
|
marcas de tiempo no se pueden analizar se salta, y el resto del archivo se sigue
|
|
cargando, lo cual es muy amable justo hasta que te preguntas dónde ha ido a
|
|
parar la línea doce. Algunas cosas no están soportadas: las etiquetas `<i>` y
|
|
`<b>` que escriben algunas herramientas se muestran como texto en lugar de
|
|
obedecerse, y las coordenadas de posición que algunas herramientas añaden a la
|
|
línea de tiempo se ignoran. La sección de subtítulos de la referencia tiene la lista
|
|
completa.
|
|
|
|
[#_load_it_and_switch_it_on]
|
|
=== Cárgalo y actívalo
|
|
|
|
Tres llamadas, y el orden importa.
|
|
|
|
[source,lua]
|
|
----
|
|
if srtLoad(DIR .. "subtitles.srt") then
|
|
srtPosition(80)
|
|
srtEnable(true)
|
|
end
|
|
----
|
|
|
|
`srtLoad` lee el archivo y responde `true` o `false`. Responde `false`, sin
|
|
haber cargado nada, en tres casos: el archivo no se puede leer, no hay nada en
|
|
él que se pueda analizar o *no hay disco*. En los tres imprime en la consola un
|
|
aviso que nombra el archivo. Es un buen diseño y deberías aprovecharlo: un
|
|
archivo de subtítulos que falta no merece que el juego muera por él, pero
|
|
publicar un juego sin subtítulos sin enterarte sí merece que lo notes.
|
|
|
|
El caso de «no hay disco» es el que te va a pillar. Las marcas de tiempo tienen
|
|
que convertirse en números de fotograma a la tasa de fotogramas del disco, y
|
|
mientras no hay un disco abierto no hay tasa de fotogramas que usar. Así que
|
|
carga los subtítulos *después* del disco, lo que en un script normal significa
|
|
desde el cuerpo del script, donde se ejecuta todo lo demás que has escrito
|
|
fuera de las funciones. De ahí se sigue que un `.srt` preparado para un vídeo a
|
|
una tasa de fotogramas cae en el sitio equivocado en un vídeo a otra.
|
|
Sincroniza tu archivo con el vídeo que de verdad vas a publicar.
|
|
|
|
`srtEnable(true)` activa las entradas cargadas. Un script empieza con los
|
|
subtítulos desactivados, siempre, así que un juego que los carga tiene que
|
|
activarlos. Desactivarlos otra vez quita lo que se esté mostrando, y volver a
|
|
activarlos pone lo que cubra el fotograma en el que está el disco ahora
|
|
mismo -- sin buscar nada, sin estado que guardar.
|
|
|
|
Tener los subtítulos activados es un ajuste, no una decisión que tomas tú por
|
|
el jugador. Ponlo en tu página de opciones de la lección veinte, guárdalo con
|
|
`saveSet` de la lección doce y pásale a `srtEnable` lo último que haya elegido
|
|
el jugador.
|
|
|
|
[#_where_they_sit]
|
|
=== Dónde se colocan
|
|
|
|
[source,lua]
|
|
----
|
|
srtPosition(70)
|
|
----
|
|
|
|
`srtPosition` es un porcentaje hacia abajo de la imagen, de `1` a `95`, y por
|
|
defecto es `80`. Se aplica a la entrada que está en pantalla ahora mismo y a
|
|
todas las que vienen después. Un número fuera del rango se ignora en lugar de
|
|
recortarse al límite, lo que significa que una errata deja la posición
|
|
exactamente donde estaba y no dice nada, así que revisa tus números.
|
|
|
|
El ochenta por ciento queda bajo, y queda bajo a propósito: la parte de abajo de
|
|
la imagen suele ser la menos interesante del plano. Súbelos cuando la parte de
|
|
abajo *no* sea aburrida -- cuando tu juego dibuja un marcador a lo largo del
|
|
borde inferior, o cuando el punto de mira de la pistola de luz del jugador vive
|
|
ahí abajo.
|
|
|
|
[#_taking_one_down]
|
|
=== Quitar uno
|
|
|
|
[source,lua]
|
|
----
|
|
srtClear()
|
|
----
|
|
|
|
`srtClear` quita de golpe lo que haya en pantalla, y deja en paz las entradas
|
|
cargadas y el estado de activación. La línea que se estaba mostrando sigue
|
|
quitada hasta que el disco llega a la siguiente entrada. Úsalo cuando una escena
|
|
termina antes de tiempo y no quieres que la última frase del diálogo se quede
|
|
colgando sobre el plano siguiente.
|
|
|
|
Hay una llamada más que comparte la maquinaria de los subtítulos, y puede que
|
|
ya la hayas usado:
|
|
|
|
[source,lua]
|
|
----
|
|
overlayBanner("Extra life!", 20)
|
|
----
|
|
|
|
`overlayBanner` muestra un mensaje corto sobre la imagen durante unos treinta
|
|
fotogramas dibujados y luego lo quita. Lo dibuja el mismo documento que los
|
|
subtítulos, así que un rótulo parece un subtítulo, y mientras está en pantalla
|
|
ocupa el lugar de cualquier subtítulo, que vuelve cuando se le acaba el tiempo
|
|
al rótulo. Su propio argumento de altura es independiente de `srtPosition` y por
|
|
defecto vale `47`, el centro de la imagen. Los mensajes de más de sesenta
|
|
caracteres se ignoran por completo, así que uno largo parece no funcionar en
|
|
absoluto.
|
|
|
|
[#_subtitles_already_inside_the_video]
|
|
=== Subtítulos que ya están dentro del vídeo
|
|
|
|
Algunos archivos de vídeo llevan sus propias pistas de subtítulos. Si el tuyo
|
|
las lleva, no necesitas ningún `.srt`:
|
|
|
|
[source,lua]
|
|
----
|
|
if discGetSubtitleTracks() > 0 then
|
|
srtLoadTrack(0)
|
|
else
|
|
srtLoad(DIR .. "subtitles.srt")
|
|
end
|
|
srtEnable(true)
|
|
----
|
|
|
|
`srtLoadTrack` recibe un número de pista de `0` a `discGetSubtitleTracks() - 1`
|
|
y todo lo que viene después de cargar es idéntico.
|
|
`discGetSubtitleLanguage(track)` te dice con qué idioma está etiquetada una
|
|
pista, como un código de tres letras del tipo `eng` o `fra`, así que un juego
|
|
puede ofrecerle al jugador lo que su vídeo resulte llevar.
|
|
|
|
Dos advertencias. Leer una pista recorre una vez todo el archivo de vídeo, sin
|
|
decodificar ninguna imagen, así que un disco tan largo como una película tarda
|
|
un momento: hazlo mientras hay otra cosa en pantalla, no entre dos fotogramas de
|
|
juego. Y las pistas de subtítulos que guardan *imágenes* de las palabras en
|
|
lugar de las palabras -- las que usan los DVD y los Blu-ray -- no se pueden
|
|
leer. Se cuentan, para que la numeración coincida con la que muestran otros
|
|
reproductores, pero `srtLoadTrack` responde `false` para ellas.
|
|
|
|
[#_the_whole_script_3]
|
|
=== El script completo
|
|
|
|
Este necesita un vídeo. Ya tienes uno: `Singe/menuBackground.mkv`, que el motor
|
|
desempaquetó en tu carpeta de trabajo la primera vez que ejecutaste algo. Dile a
|
|
Singe que lo use como disco con `--framefile`, que además enciende el 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
|
|
----
|
|
|
|
Pulsa el disparo para activarlos y desactivarlos, arriba y abajo para mover las
|
|
líneas, e izquierda para rebobinar hasta el principio. El rebobinado es el que
|
|
hay que mirar: el disco salta atrás al fotograma cero y la entrada correcta está
|
|
en pantalla justo en el fotograma siguiente, sin que tú hagas nada al respecto.
|
|
|
|
[#_what_just_happened_17]
|
|
=== Qué acaba de pasar
|
|
|
|
[source,lua]
|
|
----
|
|
if discGetSubtitleTracks() > 0 then
|
|
loaded = srtLoadTrack(0)
|
|
end
|
|
if not loaded then
|
|
loaded = srtLoad(DIR .. "subtitles.srt")
|
|
end
|
|
----
|
|
|
|
Usa los subtítulos del propio vídeo cuando los tiene, recurre al archivo que hay
|
|
junto al script cuando no, y termina sabiendo cuál ha funcionado -- si es que ha
|
|
funcionado alguno. Las dos llamadas responden con un booleano, así que el plan
|
|
de reserva son dos sentencias `if` y ningún caso especial.
|
|
`menuBackground.mkv` no lleva ninguna pista de subtítulos, así que lo que vas a
|
|
obtener de verdad es el archivo que escribiste.
|
|
|
|
[source,lua]
|
|
----
|
|
function onInputPressed(what)
|
|
if not loaded then
|
|
return
|
|
end
|
|
----
|
|
|
|
`return` sin nada detrás sale de la función inmediatamente. Sin subtítulos
|
|
cargados, ninguna de estas teclas tiene nada que hacer, y salir pronto es más
|
|
claro que envolver todo el cuerpo en un `if`. Llamar a `srtEnable` sin nada
|
|
cargado no hace daño, pero escribir código que solo tiene sentido cuando no
|
|
hace nada es una costumbre que más vale no coger.
|
|
|
|
[source,lua]
|
|
----
|
|
elseif what == SWITCH_LEFT then
|
|
srtClear()
|
|
discSearch(0)
|
|
discPlay()
|
|
----
|
|
|
|
El `srtClear` no es necesario. El motor pondrá la entrada correcta para el
|
|
fotograma cero en el siguiente fotograma dibujado de todos modos. Está ahí para
|
|
que puedas borrarlo y mirar qué pasa: la línea vieja se queda en pantalla una
|
|
fracción de segundo mientras el disco llega a donde va. En un salto lento ese
|
|
destello de la línea equivocada se ve, y limpiar primero es como lo evitas.
|
|
|
|
[#_making_text_readable_over_a_moving_picture]
|
|
=== Texto legible sobre una imagen en movimiento
|
|
|
|
El sistema pone las palabras en pantalla. Que alguien pueda leerlas es problema
|
|
tuyo, y vale para cada línea de texto que dibujes sobre vídeo -- una indicación
|
|
de la lección dieciocho, una puntuación, una elección de rama -- no solo para
|
|
los subtítulos.
|
|
|
|
*No te acerques a los bordes.* Los televisores llevan setenta años recortando
|
|
los bordes de la imagen, y los monitores de las recreativas son peores, no
|
|
mejores. Trabaja suponiendo que el cinco por ciento exterior de la imagen, en
|
|
cada lado, puede no estar en absoluto en la pantalla de alguien. Mantén dentro
|
|
de ese margen todo lo que el jugador tenga que leer. Por eso `srtPosition` se
|
|
detiene en `95` y no en `100`.
|
|
|
|
*El contraste no es una elección de color, es una garantía.* Un texto blanco
|
|
sobre una imagen es un texto blanco sobre lo que la imagen esté haciendo en ese
|
|
momento, y dentro de dos segundos eso puede ser un campo nevado. El estilo de
|
|
subtítulos incluido lo resuelve como lo hacen los subtítulos de cine: un panel
|
|
oscuro que se ciñe al texto, más una sombra de un píxel. Si dibujas tu propio
|
|
texto sobre vídeo, haz una cosa o la otra -- un `overlayBox` detrás o una copia
|
|
oscura del texto desplazada un píxel. No te fíes de la imagen.
|
|
|
|
*Parte tú las líneas.* Dos líneas cortas se leen más rápido que una larga, y una
|
|
línea que se parte donde tú no has elegido suele partirse por el sitio
|
|
equivocado. Apunta a unos cuarenta caracteres por línea y no más de dos líneas a
|
|
la vez. Parte en una pausa natural:
|
|
`They were wrong about / a great many things` se lee bien;
|
|
`They were wrong / about a great many things` tropieza.
|
|
|
|
*Déjalas el tiempo suficiente.* Una velocidad de lectura cómoda anda por los
|
|
quince caracteres por segundo, así que una línea de cuarenta caracteres pide
|
|
unos tres segundos. Mira la entrada uno del archivo de arriba: treinta y dos
|
|
caracteres, tres segundos. Si una frase del diálogo es corta y rápida, dejar la
|
|
entrada un momento más allá del final de lo que se dice es más amable que
|
|
quitarla de golpe.
|
|
|
|
*Ponlos donde no está la acción.* Si lo importante del plano está en la parte
|
|
de abajo del encuadre, sube los subtítulos para esa escena con `srtPosition`.
|
|
Puedes llamarla tantas veces como quieras, y el jugador nunca notará que lo has
|
|
hecho.
|
|
|
|
[#_styling_them]
|
|
=== Darles estilo
|
|
|
|
Las líneas las dibuja un documento, del mismo tipo que conociste en la lección
|
|
veinte, y dos archivos de tu carpeta `Singe` deciden qué aspecto tienen:
|
|
|
|
* `Singe/subtitle.rml` -- el documento. Tiene un solo elemento, `#slot`, en el
|
|
que el motor escribe la entrada o el rótulo actual.
|
|
* `Singe/subtitle.rcss` -- el estilo. `.cue` es el bloque que lleva la altura
|
|
que pidió `srtPosition`, y `.cue .text` es la barra de texto que hay dentro:
|
|
blanca, en negrita, sobre un panel oscuro redondeado que se ciñe al texto, con
|
|
una sombra.
|
|
|
|
Abre `subtitle.rcss` y léelo -- son unas cuarenta líneas. Luego déjalo en paz,
|
|
porque lo que edites ahí no dura. Cada vez que Singe arranca, vuelve a poner su
|
|
propia copia de todo lo que haya cambiado en la carpeta `Singe`, y lo dice:
|
|
|
|
----
|
|
>>> Updated File: Singe/subtitle.rcss
|
|
----
|
|
|
|
Esa carpeta es del motor. Tu juego trae su propia copia en su lugar. Copia los
|
|
dos archivos de `Singe` a tu carpeta `subtitles`, junto al script. Luego abre tu
|
|
copia de `subtitle.rml` y cambia la única línea de su `<head>` que enlaza el
|
|
estilo, para que quede así:
|
|
|
|
[source,html]
|
|
----
|
|
<link type="text/rcss" href="subtitle.rcss"/>
|
|
----
|
|
|
|
Un nombre dentro de un documento se cuenta desde la propia carpeta del
|
|
documento, salvo un nombre que empieza por `Singe/`, que siempre quiere decir la
|
|
carpeta del motor. El enlace tal como lo copiaste, `Singe/subtitle.rcss`, sigue
|
|
trayendo el estilo del motor. El nuevo trae el tuyo.
|
|
|
|
Cuando Singe encuentra un `subtitle.rml` junto a tu script, dibuja los
|
|
subtítulos con ese en lugar de con el suyo. Añade `-p` al comando y Singe
|
|
describe lo que va haciendo, línea a línea:
|
|
|
|
----
|
|
Singe -p --framefile=Singe/menuBackground.mkv subtitles
|
|
----
|
|
|
|
Cuando aparece la primera entrada, una de esas líneas es esta:
|
|
|
|
----
|
|
Using the game's own subtitles/subtitle.rml
|
|
----
|
|
|
|
Ahora cambia el `font-size`, el `color`, el `background-color`, el
|
|
`border-radius` o el `font-effect` en tu `subtitle.rcss`, guarda y vuelve a
|
|
ejecutarlo. El motor solo toca el contenido de `#slot` y la altura de `.cue`,
|
|
así que todo lo demás de tus dos archivos es tuyo, y nada de lo que haga Singe
|
|
al arrancar los tocará. Si `-p` dice que está usando los tuyos y el aspecto no
|
|
ha cambiado, vuelve a leer el enlace: una copia que todavía dice `Singe/` está
|
|
usando sin avisar el estilo del motor.
|
|
|
|
Como `overlayBanner` usa el mismo documento, cambiar el estilo de los subtítulos
|
|
cambia también el de tus rótulos, lo cual suele ser lo que quieres, y conviene
|
|
saberlo antes de que te preguntes por qué.
|
|
|
|
Un límite: el documento de los subtítulos es un documento, y los documentos
|
|
necesitan una GPU. En una máquina sin ella, `srtLoad` sigue leyendo tu archivo y
|
|
sigue respondiendo con la verdad, y no se dibuja nada. Un aviso lo dice una vez.
|
|
|
|
[#_try_it_21]
|
|
=== Pruébalo
|
|
|
|
. *Añade una cuarta entrada* a `subtitles.srt`, entre los segundos once y trece.
|
|
Guarda y ejecuta. Luego ponla fuera de orden, como entrada `99`, la primera
|
|
del archivo, y comprueba que sigue funcionando.
|
|
. *Dale a una entrada una marca de tiempo mala* -- escribe `00:00:05.500` con un
|
|
punto en lugar de una coma -- y ejecuta. Mira qué línea desaparece, y fíjate en
|
|
que no se dice absolutamente nada al respecto. Un archivo que se carga no es
|
|
un archivo que esté bien.
|
|
. *Cámbiales el estilo.* En tu propio `subtitle.rcss` -- la copia que está junto
|
|
a tu script, no la de `Singe` -- cambia `.cue .text` a texto amarillo sobre un
|
|
fondo totalmente transparente, y luego añade una sombra más gruesa. Después reprodúcelo sobre el vídeo y decide con sinceridad si todavía
|
|
se lee.
|
|
. *Rompe la sincronización a propósito.* Cambia todas las marcas de tiempo del
|
|
archivo para que lleguen dos segundos tarde, y mira cómo un sistema que
|
|
funciona correctamente entrega unos subtítulos inútiles. Esto es lo que te
|
|
hace un vídeo recodificado.
|
|
. *Lleva la opción a un menú.* Coge la página de pausa de la lección veinte,
|
|
añádele una casilla y conéctala a `srtEnable`. Luego guarda la elección con
|
|
`saveSet` para que siga activada la próxima vez. Esta es la versión que de
|
|
verdad quieren tus jugadores.
|
|
|
|
[#_break_it_on_purpose_20]
|
|
=== Rómpelo a propósito
|
|
|
|
Ejecuta el script sin la opción `--framefile`:
|
|
|
|
----
|
|
Singe subtitles
|
|
----
|
|
|
|
Se abre la ventana, negra, con tu mensaje de reserva, y la consola dice:
|
|
|
|
----
|
|
Warning: No subtitles were loaded from subtitles/subtitles.srt.
|
|
----
|
|
|
|
Ni un cierre inesperado ni una ventana de error, porque `srtLoad` ha respondido
|
|
`false` y tu script lo ha gestionado.
|
|
|
|
Ese es el fallo más valioso de esta lección, porque es el que ocurre sin que
|
|
nadie se dé cuenta. No hay disco, así que no hay tasa de fotogramas, así que no
|
|
hay nada en lo que convertir las marcas de tiempo, así que no se carga nada. Si
|
|
hubieras escrito `srtLoad(...)` sin más y hubieras tirado la respuesta, tu juego
|
|
habría funcionado perfectamente sin mostrar subtítulos, y te habrías enterado
|
|
cuando alguien te lo dijera.
|
|
|
|
Usa la respuesta. Siempre.
|
|
|
|
[#_what_you_learned_21]
|
|
=== Lo que has aprendido
|
|
|
|
* Un juego con voces y sin subtítulos es un juego al que algunas personas no
|
|
pueden jugar en absoluto.
|
|
* Meter los subtítulos sobre la marcha es cosa de una tarde; añadirlos al final
|
|
no.
|
|
* Los subtítulos son un archivo `.srt`: un número, dos marcas de tiempo con
|
|
`-->` entre ellas, el texto y una línea en blanco.
|
|
* `srtLoad` convierte las marcas de tiempo en números de fotograma del disco al
|
|
cargar, y por eso una entrada sobrevive a cualquier salto.
|
|
* Hay que cargarlo después del disco, y responde `false` cuando no puede cargar,
|
|
también cuando no hay disco. Comprueba la respuesta.
|
|
* `srtEnable` los activa, y un script siempre empieza con ellos desactivados.
|
|
* `srtPosition` los coloca como un porcentaje hacia abajo de la imagen, de `1` a
|
|
`95`.
|
|
* `srtClear` quita lo que se esté mostrando, y `overlayBanner` comparte el mismo
|
|
documento.
|
|
* `srtLoadTrack` lee los subtítulos del propio archivo de vídeo cuando los
|
|
lleva.
|
|
* Singe reescribe su carpeta `Singe` en cada arranque, así que para cambiar el
|
|
estilo de los subtítulos copias `subtitle.rml` y `subtitle.rcss` junto a tu
|
|
script, haces que el enlace de la copia apunte a tu propia hoja y cambias
|
|
esa.
|
|
* El texto sobre una imagen en movimiento necesita un margen de seguridad, su
|
|
propio contraste, líneas que hayas partido tú y tiempo para leerse.
|
|
|
|
[#_next_time_21]
|
|
=== La próxima vez
|
|
|
|
Hasta aquí el texto. La cuarta parte sigue sin que tengas que leerla en orden,
|
|
y la próxima lección abre una puerta que ha estado cerrada durante veinte
|
|
lecciones: `overlayGetWidth` y `overlayGetHeight` son dos números, y una escena
|
|
tiene tres. La lección veintidós es el tercero.
|