580 lines
24 KiB
Text
580 lines
24 KiB
Text
[#_lesson_21_subtitles]
|
||
== Leçon 21 : Les sous-titres
|
||
|
||
image::learn/21-subtitles.png[La leçon terminée, 480]
|
||
|
||
Quelqu'un qui n'entend pas va jouer à votre jeu.
|
||
|
||
Si votre jeu a des paroles et pas de sous-titres, cette personne ne le pourra
|
||
pas. Pas « ce sera plus difficile pour elle » -- elle arrivera à la première
|
||
scène où un personnage dit ce qui explique au joueur quoi faire, et elle
|
||
s'arrêtera là. C'est tout, et c'est la raison pour laquelle cette leçon existe
|
||
au lieu d'être un paragraphe de la leçon dix-neuf.
|
||
|
||
L'autre raison est pratique. Ajouter des sous-titres après coup à un jeu
|
||
terminé est une misère. Il faut retrouver chaque réplique, déterminer sur
|
||
quelle image elle tombe, et découvrir que la moitié de vos synchronisations
|
||
sont fausses parce que votre vidéo a été réencodée au milieu du projet. Fait
|
||
pendant que vous écrivez le jeu, c'est un après-midi. Singe vous donne un
|
||
système qui fait la partie difficile, et cette leçon explique comment vous en
|
||
servir.
|
||
|
||
[#_it_is_not_ordinary_text_drawing]
|
||
=== Ce n'est pas du texte ordinaire
|
||
|
||
Vous pourriez faire les sous-titres vous-même. Garder une liste de lignes avec
|
||
leurs heures de début et de fin, regarder l'horloge dans `onOverlayUpdate`, et
|
||
dessiner la ligne du moment avec `fontToSprite`. Certains l'ont fait. Voici
|
||
pourquoi vous ne devriez pas.
|
||
|
||
Les sous-titres sont synchronisés sur *le disque*, pas sur une horloge. Quand
|
||
`srtLoad` lit votre fichier, elle convertit chaque horodatage en numéro d'image
|
||
du disque, sur-le-champ, en utilisant la fréquence d'images du disque chargé. À
|
||
partir de là, le moteur ne regarde plus du tout une horloge ; à chaque image
|
||
dessinée, il demande quel sous-titre couvre l'image sur laquelle se trouve le
|
||
disque.
|
||
|
||
Cette seule décision vous offre ce qu'un système fait maison ne réussit
|
||
jamais : *un sous-titre survit à un saut*. Envoyez le disque n'importe où --
|
||
`discSearch`, `discSkipForward`, un pas, un embranchement vers un autre
|
||
segment -- et la bonne ligne est affichée à l'image dessinée suivante, en
|
||
avant comme en arrière, sans rien recharger ni remettre aucune horloge à zéro.
|
||
Dans un jeu à embranchements de la leçon seize, où les choix du joueur font
|
||
sauter le disque sans arrêt, c'est la différence entre ce qui marche et ce qui
|
||
marche presque.
|
||
|
||
Le système dessine aussi au bon endroit. Le document des sous-titres se place
|
||
par-dessus l'image, au-dessus de votre overlay, en dessous de toute GUI en
|
||
espace écran, et il suit l'image partout où les réglages du joueur la mettent
|
||
-- une image réduite, une image décalée, une borne tournée, un trou dans un
|
||
bezel. Il ne prend aucune entrée de la souris, donc un tir de pistolet optique
|
||
le traverse sans s'arrêter. Réussir tout ça vous-même, c'est une semaine que
|
||
vous n'aviez pas prévue.
|
||
|
||
[#_write_the_file]
|
||
=== Écrivez le fichier
|
||
|
||
Les sous-titres vont dans un fichier SubRip, qui se termine par `.srt` et qui
|
||
est du texte brut que vous pouvez taper dans n'importe quel éditeur. C'est l'un
|
||
des formats les plus simples qui existent. Créez un fichier appelé
|
||
`subtitles.srt` à côté de votre 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.
|
||
----
|
||
|
||
Un sous-titre, c'est quatre choses. Un numéro seul sur sa ligne. Une ligne avec
|
||
deux horodatages et, entre eux, une flèche faite de deux traits d'union et d'un
|
||
signe supérieur. Une ou plusieurs lignes de texte. Une ligne vide pour finir.
|
||
|
||
Un horodatage s'écrit `HH:MM:SS,mmm` -- les heures, les minutes et les
|
||
secondes séparées par des deux-points, puis une virgule, puis les
|
||
millisecondes. La virgule n'est pas une faute de frappe, et un point ne fera
|
||
pas l'affaire. `00:00:04,200`, c'est quatre secondes et un cinquième après le
|
||
début.
|
||
|
||
Les numéros des sous-titres sont lus puis jetés, donc ils n'ont pas besoin
|
||
d'être dans l'ordre, ni même d'être justes. Numérotez-les quand même ; un jour,
|
||
vous chercherez le sous-titre quarante et un.
|
||
|
||
Le sous-titre deux montre à quoi ressemble un sous-titre de deux lignes. Les
|
||
lignes sont affichées comme vous les avez écrites, donc c'est *vous* qui
|
||
décidez où une longue ligne se coupe, ce qui compte plus que vous ne le
|
||
croiriez et qui est expliqué plus bas.
|
||
|
||
L'analyseur est volontairement tolérant envers ce qui tourne mal dans un
|
||
fichier modifié à la main. Les fins de ligne Windows se chargent telles
|
||
quelles, et les espaces au début et à la fin de chaque ligne sont retirés. Un
|
||
sous-titre dont les horodatages ne s'analysent pas est sauté et le reste du
|
||
fichier continue de se charger, ce qui est sympathique jusqu'au moment où vous
|
||
vous demandez où est passée la ligne douze. Quelques choses ne sont pas prises
|
||
en charge : les balises `<i>` et `<b>` que certains outils écrivent sont
|
||
affichées comme du texte au lieu d'être appliquées, et les coordonnées de
|
||
positionnement que certains outils ajoutent à la ligne de temps sont ignorées.
|
||
La section Sous-titres de la Référence en donne la liste complète.
|
||
|
||
[#_load_it_and_switch_it_on]
|
||
=== Chargez-les et allumez-les
|
||
|
||
Trois appels, et l'ordre compte.
|
||
|
||
[source,lua]
|
||
----
|
||
if srtLoad(DIR .. "subtitles.srt") then
|
||
srtPosition(80)
|
||
srtEnable(true)
|
||
end
|
||
----
|
||
|
||
`srtLoad` lit le fichier et répond `true` ou `false`. Elle répond `false`, sans
|
||
rien avoir chargé, dans trois cas : le fichier ne peut pas être lu, rien dedans
|
||
ne s'analyse, ou *il n'y a pas de disque*. Dans les trois cas, elle affiche à
|
||
la console un avertissement qui nomme le fichier. C'est une bonne conception et
|
||
vous devriez vous en servir : un fichier de sous-titres manquant ne vaut pas
|
||
qu'on tue un jeu pour ça, mais livrer sans s'en apercevoir un jeu sans
|
||
sous-titres vaut qu'on le remarque.
|
||
|
||
Le cas « pas de disque » est celui qui vous attrapera. Les horodatages doivent
|
||
devenir des numéros d'image à la fréquence d'images du disque, et tant qu'aucun
|
||
disque n'est ouvert, il n'y a pas de fréquence d'images à utiliser. Chargez
|
||
donc les sous-titres *après* le disque, ce qui, dans un script ordinaire, veut
|
||
dire depuis le corps du script, là où s'exécute tout ce que vous avez écrit au
|
||
niveau principal. Il s'ensuit qu'un `.srt` découpé pour une vidéo à une
|
||
certaine fréquence d'images tombe au mauvais endroit sur une vidéo à une autre.
|
||
Synchronisez votre fichier sur la vidéo que vous allez vraiment livrer.
|
||
|
||
`srtEnable(true)` allume les sous-titres chargés. Un script démarre toujours
|
||
avec les sous-titres éteints, donc un jeu qui les charge doit les allumer. Les
|
||
éteindre de nouveau retire ce qui est affiché, et les rallumer affiche ce qui
|
||
couvre l'image sur laquelle se trouve le disque à cet instant -- rien à
|
||
chercher, aucun état à garder.
|
||
|
||
Laisser les sous-titres allumés est un réglage, pas une décision que vous
|
||
prenez à la place du joueur. Mettez-le dans votre page d'options de la leçon
|
||
vingt, enregistrez-le avec `saveSet` de la leçon douze, et passez à `srtEnable`
|
||
ce que le joueur a choisi en dernier.
|
||
|
||
[#_where_they_sit]
|
||
=== Où ils se placent
|
||
|
||
[source,lua]
|
||
----
|
||
srtPosition(70)
|
||
----
|
||
|
||
`srtPosition` est un pourcentage de la hauteur de l'image, compté depuis le
|
||
haut, de `1` à `95`, et la valeur par défaut est `80`. Il s'applique au
|
||
sous-titre affiché à cet instant et à tous ceux qui suivent. Un nombre hors de
|
||
cette plage est ignoré au lieu d'être ramené dans les limites, ce qui veut dire
|
||
qu'une faute de frappe laisse la position exactement où elle était, sans rien
|
||
dire, alors vérifiez les vôtres.
|
||
|
||
Quatre-vingts pour cent, c'est bas, et c'est bas exprès : le bas de l'image est
|
||
en général la partie la moins intéressante du plan. Remontez-les quand le bas
|
||
n'est *pas* ennuyeux -- quand votre jeu dessine les scores le long du bord
|
||
inférieur, ou quand le réticule du pistolet optique du joueur vit par là.
|
||
|
||
[#_taking_one_down]
|
||
=== En retirer un
|
||
|
||
[source,lua]
|
||
----
|
||
srtClear()
|
||
----
|
||
|
||
`srtClear` retire immédiatement ce qui est à l'écran, et laisse tranquilles les
|
||
sous-titres chargés et l'état allumé. La ligne qui était affichée reste
|
||
retirée jusqu'à ce que le disque atteigne le sous-titre suivant. Servez-vous-en
|
||
quand une scène se termine plus tôt et que vous ne voulez pas que la dernière
|
||
réplique traîne sur le plan suivant.
|
||
|
||
Un autre appel partage la mécanique des sous-titres, et vous vous en êtes
|
||
peut-être déjà servi :
|
||
|
||
[source,lua]
|
||
----
|
||
overlayBanner("Extra life!", 20)
|
||
----
|
||
|
||
`overlayBanner` affiche un court message par-dessus l'image pendant une
|
||
trentaine d'images dessinées, puis le retire. Il est dessiné par le même
|
||
document que les sous-titres, donc un bandeau ressemble à un sous-titre, et
|
||
tant qu'il est affiché il prend la place de tout sous-titre, qui revient quand
|
||
le bandeau expire. Son propre argument de hauteur est distinct de
|
||
`srtPosition` et vaut `47` par défaut, le milieu de l'image. Les messages de
|
||
plus de soixante caractères sont purement et simplement ignorés, donc un
|
||
message long a l'air de ne pas marcher du tout.
|
||
|
||
[#_subtitles_already_inside_the_video]
|
||
=== Des sous-titres déjà dans la vidéo
|
||
|
||
Certains fichiers vidéo transportent leurs propres pistes de sous-titres. Si
|
||
c'est le cas du vôtre, vous n'avez pas du tout besoin d'un `.srt` :
|
||
|
||
[source,lua]
|
||
----
|
||
if discGetSubtitleTracks() > 0 then
|
||
srtLoadTrack(0)
|
||
else
|
||
srtLoad(DIR .. "subtitles.srt")
|
||
end
|
||
srtEnable(true)
|
||
----
|
||
|
||
`srtLoadTrack` prend un numéro de piste de `0` à `discGetSubtitleTracks() - 1`
|
||
et, une fois le chargement fait, tout est identique.
|
||
`discGetSubtitleLanguage(track)` vous dit dans quelle langue une piste est
|
||
étiquetée, sous la forme d'un code de trois lettres comme `eng` ou `fra`, pour
|
||
qu'un jeu puisse proposer au joueur ce que sa vidéo se trouve transporter.
|
||
|
||
Deux mises en garde. Lire une piste parcourt une fois tout le fichier vidéo,
|
||
sans décoder aucune image, donc un disque de la longueur d'un long métrage
|
||
prend un moment : faites-le pendant que quelque chose d'autre est à l'écran,
|
||
pas entre deux images de jeu. Et les pistes de sous-titres qui contiennent des
|
||
*images* des mots au lieu des mots -- le genre qu'utilisent les DVD et les
|
||
Blu-ray -- ne peuvent pas être lues. Elles sont comptées, pour que la
|
||
numérotation corresponde à ce que montrent les autres lecteurs, mais
|
||
`srtLoadTrack` répond `false` pour elles.
|
||
|
||
[#_the_whole_script_3]
|
||
=== Le script complet
|
||
|
||
Celui-ci a besoin d'une vidéo. Vous en avez une : `Singe/menuBackground.mkv`,
|
||
que le moteur a extraite dans votre dossier de travail la première fois que
|
||
vous avez lancé quoi que ce soit. Dites à Singe de s'en servir comme disque
|
||
avec `--framefile`, qui allume aussi le disque :
|
||
|
||
----
|
||
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
|
||
----
|
||
|
||
Appuyez sur tir pour les allumer ou les éteindre, sur haut et bas pour
|
||
déplacer les lignes, et sur gauche pour revenir au début. C'est le retour au
|
||
début qu'il faut regarder : le disque saute à l'image zéro et le bon
|
||
sous-titre est affiché dès l'image suivante, sans que vous ayez rien fait pour
|
||
ça.
|
||
|
||
[#_what_just_happened_17]
|
||
=== Ce qui vient de se passer
|
||
|
||
[source,lua]
|
||
----
|
||
if discGetSubtitleTracks() > 0 then
|
||
loaded = srtLoadTrack(0)
|
||
end
|
||
if not loaded then
|
||
loaded = srtLoad(DIR .. "subtitles.srt")
|
||
end
|
||
----
|
||
|
||
Prenez les sous-titres de la vidéo elle-même quand elle en a, rabattez-vous
|
||
sur le fichier à côté du script quand elle n'en a pas, et finissez en sachant
|
||
lequel des deux a marché -- si l'un des deux a marché. Les deux appels
|
||
répondent par un booléen, donc le repli tient en deux instructions `if`, sans
|
||
cas particulier. `menuBackground.mkv` ne transporte aucune piste de
|
||
sous-titres, donc ce que vous obtiendrez réellement, c'est le fichier que vous
|
||
avez tapé.
|
||
|
||
[source,lua]
|
||
----
|
||
function onInputPressed(what)
|
||
if not loaded then
|
||
return
|
||
end
|
||
----
|
||
|
||
Un `return` sans rien après quitte la fonction immédiatement. Sans
|
||
sous-titres chargés, aucune de ces touches n'a rien à faire, et partir tôt est
|
||
plus clair que d'envelopper tout le corps dans un `if`. Appeler `srtEnable`
|
||
sans rien de chargé est sans danger, mais écrire du code qui n'a de sens que
|
||
lorsqu'il ne fait rien est une habitude qu'il vaut mieux ne pas prendre.
|
||
|
||
[source,lua]
|
||
----
|
||
elseif what == SWITCH_LEFT then
|
||
srtClear()
|
||
discSearch(0)
|
||
discPlay()
|
||
----
|
||
|
||
Le `srtClear` n'est pas nécessaire. Le moteur affichera de toute façon le bon
|
||
sous-titre pour l'image zéro à l'image dessinée suivante. Il est là pour que
|
||
vous puissiez le supprimer et regarder ce qui se passe : l'ancienne ligne reste
|
||
affichée une fraction de seconde pendant que le disque arrive là où il va. Sur
|
||
un saut lent, ce flash de la mauvaise ligne se voit, et effacer d'abord est la
|
||
façon de l'éviter.
|
||
|
||
[#_making_text_readable_over_a_moving_picture]
|
||
=== Rendre le texte lisible sur une image qui bouge
|
||
|
||
Le système met les mots à l'écran. Que quelqu'un arrive à les lire, c'est
|
||
votre problème, et ça vaut pour chaque ligne de texte que vous dessinez
|
||
par-dessus de la vidéo -- une consigne de la leçon dix-huit, un score, un choix
|
||
d'embranchement -- pas seulement pour les sous-titres.
|
||
|
||
*Restez loin des bords.* Les téléviseurs coupent les bords des images depuis
|
||
soixante-dix ans, et les moniteurs d'arcade sont pires, pas meilleurs. Partez
|
||
du principe que les cinq pour cent extérieurs de l'image, de chaque côté,
|
||
peuvent ne pas exister du tout sur l'écran de quelqu'un. Gardez à l'intérieur
|
||
tout ce qu'un joueur doit lire. C'est pour ça que `srtPosition` s'arrête à
|
||
`95` et pas à `100`.
|
||
|
||
*Le contraste n'est pas un choix de couleur, c'est une garantie.* Du texte
|
||
blanc sur une image, c'est du texte blanc sur ce que l'image est en train de
|
||
montrer, et dans deux secondes ce sera peut-être un champ de neige. Le style
|
||
de sous-titres fourni règle ça comme le font les sous-titres de cinéma : un
|
||
panneau sombre qui épouse le texte, plus une ombre d'un pixel. Si vous
|
||
dessinez votre propre texte sur de la vidéo, faites l'un ou l'autre -- un
|
||
`overlayBox` derrière, ou une copie sombre du texte décalée d'un pixel. Ne
|
||
comptez pas sur l'image.
|
||
|
||
*Coupez vos lignes vous-même.* Deux lignes courtes se lisent plus vite qu'une
|
||
longue, et une ligne qui passe à la ligne là où vous ne l'avez pas choisi se
|
||
coupe en général au mauvais endroit. Visez une quarantaine de caractères par
|
||
ligne et pas plus de deux lignes à la fois. Coupez à une pause naturelle :
|
||
`They were wrong about / a great many things` se lit bien ; `They
|
||
were wrong / about a great many things` trébuche.
|
||
|
||
*Laissez-les assez longtemps.* Une vitesse de lecture confortable tourne autour
|
||
de quinze caractères par seconde, donc une ligne de quarante caractères
|
||
demande environ trois secondes. Regardez le sous-titre un dans le fichier
|
||
ci-dessus : trente-deux caractères, trois secondes. Si une réplique est courte
|
||
et rapide, garder le sous-titre affiché un temps de plus après la fin de la
|
||
parole est plus gentil que de le faire disparaître d'un coup.
|
||
|
||
*Mettez-les là où l'action n'est pas.* Si ce qui compte dans le plan se trouve
|
||
en bas de l'image, remontez les sous-titres pour cette scène avec
|
||
`srtPosition`. Vous pouvez l'appeler aussi souvent que vous voulez, et le
|
||
joueur ne remarquera jamais que vous l'avez fait.
|
||
|
||
[#_styling_them]
|
||
=== Leur mise en forme
|
||
|
||
Les lignes sont dessinées par un document, du même genre que ceux de la leçon
|
||
vingt, et deux fichiers de votre dossier `Singe` décident de leur apparence :
|
||
|
||
* `Singe/subtitle.rml` -- le document. Il contient un seul élément, `#slot`,
|
||
dans lequel le moteur écrit le sous-titre ou le bandeau du moment.
|
||
* `Singe/subtitle.rcss` -- le style. `.cue` est le bloc qui porte la hauteur
|
||
demandée par `srtPosition`, et `.cue .text` est la barre de texte à
|
||
l'intérieur : blanc, gras, sur un panneau sombre arrondi qui épouse le texte,
|
||
avec une ombre.
|
||
|
||
Ouvrez `subtitle.rcss` et lisez-le -- il fait une quarantaine de lignes. Puis
|
||
laissez-le tranquille, parce qu'une modification faite là ne dure pas. À chaque
|
||
démarrage, Singe remet sa propre copie de tout ce qui a été modifié dans le
|
||
dossier `Singe`, et le dit :
|
||
|
||
----
|
||
>>> Updated File: Singe/subtitle.rcss
|
||
----
|
||
|
||
Ce dossier appartient au moteur. Votre jeu apporte plutôt sa propre copie.
|
||
Copiez les deux fichiers depuis `Singe` dans votre dossier `subtitles`, à côté
|
||
du script. Puis ouvrez votre copie de `subtitle.rml` et changez la seule ligne
|
||
de son `<head>` qui relie le style, pour qu'elle se lise :
|
||
|
||
[source,html]
|
||
----
|
||
<link type="text/rcss" href="subtitle.rcss"/>
|
||
----
|
||
|
||
Un nom à l'intérieur d'un document part du dossier du document lui-même, sauf
|
||
un nom qui commence par `Singe/`, qui désigne toujours le dossier du moteur. Le
|
||
lien tel que vous l'avez copié, `Singe/subtitle.rcss`, va toujours chercher le
|
||
style du moteur. Le nouveau va chercher le vôtre.
|
||
|
||
Quand Singe trouve un `subtitle.rml` à côté de votre script, il dessine les
|
||
sous-titres avec celui-ci au lieu du sien. Ajoutez `-p` à la commande et Singe
|
||
décrit ce qu'il fait au fur et à mesure, une ligne à la fois :
|
||
|
||
----
|
||
Singe -p --framefile=Singe/menuBackground.mkv subtitles
|
||
----
|
||
|
||
Quand le premier sous-titre apparaît, l'une de ces lignes est celle-ci :
|
||
|
||
----
|
||
Using the game's own subtitles/subtitle.rml
|
||
----
|
||
|
||
Changez maintenant la `font-size`, la `color`, la `background-color`, le
|
||
`border-radius` ou le `font-effect` dans votre `subtitle.rcss`, enregistrez, et
|
||
relancez. Le moteur ne touche jamais qu'au contenu de `#slot` et à la hauteur
|
||
de `.cue`, donc tout le reste de vos deux fichiers est à vous, et rien de ce que
|
||
fait Singe à son démarrage n'y touchera. Si `-p` dit qu'il utilise les vôtres et
|
||
que l'apparence n'a pas changé, relisez le lien : une copie qui dit encore
|
||
`Singe/` utilise en silence le style du moteur.
|
||
|
||
Comme `overlayBanner` utilise le même document, changer le style des
|
||
sous-titres change aussi celui de vos bandeaux, ce qui est en général ce que
|
||
vous voulez et qui vaut d'être su avant que vous vous demandiez pourquoi.
|
||
|
||
Une limite : le document des sous-titres est un document, et les documents ont
|
||
besoin d'un GPU. Sur une machine qui n'en a pas, `srtLoad` lit quand même
|
||
votre fichier et répond quand même honnêtement, et rien n'est dessiné. Un
|
||
avertissement le dit une fois.
|
||
|
||
[#_try_it_21]
|
||
=== Essayez
|
||
|
||
. *Ajoutez un quatrième sous-titre* à `subtitles.srt`, entre onze et treize
|
||
secondes. Enregistrez et lancez. Puis mettez-le dans le désordre, en tant que
|
||
sous-titre `99`, en premier dans le fichier, et vérifiez qu'il marche
|
||
toujours.
|
||
. *Donnez à un sous-titre un mauvais horodatage* -- écrivez `00:00:05.500` avec
|
||
un point au lieu d'une virgule -- et lancez. Regardez quelle ligne disparaît,
|
||
et remarquez que rien du tout n'est dit à ce sujet. Un fichier qui se charge
|
||
n'est pas un fichier juste.
|
||
. *Changez leur style.* Dans votre propre `subtitle.rcss` -- la copie qui est à
|
||
côté de votre script, pas celle de `Singe` -- changez `.cue .text` pour
|
||
avoir du texte jaune sur un fond complètement transparent, puis ajoutez une
|
||
ombre plus marquée. Ensuite, regardez-le par-dessus la vidéo et décidez
|
||
honnêtement s'il est encore lisible.
|
||
. *Cassez la synchronisation exprès.* Changez chaque horodatage du fichier pour
|
||
qu'il soit en retard de deux secondes, et regardez un système qui marche
|
||
parfaitement livrer des sous-titres inutiles. Voilà ce que vous fait une
|
||
vidéo réencodée.
|
||
. *Mettez l'interrupteur dans un menu.* Reprenez la page de pause de la leçon
|
||
vingt, ajoutez une case à cocher, et branchez-la sur `srtEnable`. Puis
|
||
enregistrez le choix avec `saveSet` pour qu'il soit encore allumé la fois
|
||
suivante. C'est la version que vos joueurs veulent vraiment.
|
||
|
||
[#_break_it_on_purpose_20]
|
||
=== Cassez-le exprès
|
||
|
||
Lancez le script sans l'option `--framefile` :
|
||
|
||
----
|
||
Singe subtitles
|
||
----
|
||
|
||
La fenêtre s'ouvre, noire, avec votre message de repli dessus, et la console
|
||
dit :
|
||
|
||
----
|
||
Warning: No subtitles were loaded from subtitles/subtitles.srt.
|
||
----
|
||
|
||
Pas de plantage et pas de boîte de dialogue d'erreur, parce que `srtLoad` a
|
||
répondu `false` et que votre script s'en est occupé.
|
||
|
||
C'est l'échec le plus précieux de cette leçon, parce que c'est celui qui
|
||
arrive sans que personne ne le remarque. Il n'y a pas de disque, donc pas de
|
||
fréquence d'images, donc rien en quoi transformer les horodatages, donc rien
|
||
ne se charge. Si vous aviez écrit `srtLoad(...)` tout seul en jetant la
|
||
réponse, votre jeu aurait tourné parfaitement sans montrer aucun sous-titre, et
|
||
vous l'auriez découvert quand quelqu'un vous l'aurait dit.
|
||
|
||
Servez-vous de la réponse. À chaque fois.
|
||
|
||
[#_what_you_learned_21]
|
||
=== Ce que vous avez appris
|
||
|
||
* Un jeu avec des paroles et sans sous-titres est un jeu auquel certaines
|
||
personnes ne peuvent pas jouer du tout.
|
||
* Mettre les sous-titres au fur et à mesure, c'est un après-midi ; les ajouter
|
||
après coup, non.
|
||
* Les sous-titres sont un fichier `.srt` : un numéro, deux horodatages avec
|
||
`-->` entre eux, le texte, et une ligne vide.
|
||
* `srtLoad` transforme les horodatages en numéros d'image du disque au
|
||
chargement, et c'est pour ça qu'un sous-titre survit à n'importe quel saut.
|
||
* Il faut charger les sous-titres après le disque, et l'appel répond `false`
|
||
quand il ne peut pas charger, y compris quand il n'y a pas de disque.
|
||
Vérifiez la réponse.
|
||
* `srtEnable` les allume, et un script démarre toujours avec les sous-titres
|
||
éteints.
|
||
* `srtPosition` les place à un pourcentage de la hauteur de l'image, de `1` à
|
||
`95`.
|
||
* `srtClear` retire ce qui est affiché, et `overlayBanner` partage le même
|
||
document.
|
||
* `srtLoadTrack` lit les sous-titres dans le fichier vidéo lui-même quand il en
|
||
contient.
|
||
* Singe réécrit son dossier `Singe` à chaque démarrage, donc pour changer le
|
||
style des sous-titres, vous copiez `subtitle.rml` et `subtitle.rcss` à côté de
|
||
votre script, vous faites pointer le lien de la copie vers votre propre
|
||
feuille, et c'est celle-ci que vous modifiez.
|
||
* Du texte sur une image qui bouge a besoin d'une marge de sécurité, de son
|
||
propre contraste, de lignes coupées par vous, et de temps pour être lu.
|
||
|
||
[#_next_time_21]
|
||
=== La prochaine fois
|
||
|
||
C'en est fini du texte. La quatrième partie continue sans que vous ayez à la
|
||
lire dans l'ordre, et la prochaine leçon ouvre une porte restée fermée pendant
|
||
vingt leçons : `overlayGetWidth` et `overlayGetHeight` sont deux nombres, et
|
||
une scène en a trois. La leçon vingt-deux parle du troisième.
|