singe/docs/de/lessons/21-subtitles.adoc

523 lines
24 KiB
Text

[#_lesson_21_subtitles]
== Lektion 21: Untertitel
image::learn/21-subtitles.png[Die fertige Lektion, 480]
Irgendwann spielt jemand dein Spiel, der nicht hören kann.
Wenn in deinem Spiel gesprochen wird und es keine Untertitel hat, kann diese Person es nicht
spielen. Nicht „es ist schwerer für sie“ -- sie kommt zur ersten Szene, in der eine Figur das
sagt, was dem Spieler erklärt, was er tun soll, und hört auf. Das ist schon alles, und es ist
der Grund, warum es diese Lektion gibt, statt nur einen Absatz in Lektion neunzehn.
Der andere Grund ist praktisch. Untertitel nachträglich in ein fertiges Spiel einzubauen ist
eine Qual. Du musst jede gesprochene Zeile finden, herausfinden, auf welchem Frame sie liegt,
und dabei entdecken, dass die Hälfte deiner Zeiten falsch ist, weil dein Video mitten im Projekt
neu kodiert wurde. Machst du es, während du das Spiel schreibst, ist es ein Nachmittag. Singe
gibt dir ein System, das den schweren Teil erledigt, und diese Lektion zeigt, wie man es
benutzt.
[#_it_is_not_ordinary_text_drawing]
=== Es ist nicht einfach gezeichneter Text
Du könntest Untertitel selbst machen. Eine Liste von Zeilen mit Start- und Endzeiten führen, in
`onOverlayUpdate` auf die Uhr sehen und die aktuelle Zeile mit `fontToSprite` zeichnen. Das haben
schon Leute gemacht. Hier ist, warum du es nicht tun solltest.
Untertitel richten sich nach *der Disc*, nicht nach einer Uhr. Wenn `srtLoad` deine Datei liest,
rechnet es jeden Zeitstempel sofort in eine Frame-Nummer der Disc um, mit der Bildrate der Disc,
die geladen ist. Ab diesem Moment sieht die Engine überhaupt nicht mehr auf eine Uhr; bei jedem
gezeichneten Frame fragt sie, welcher Cue den Frame abdeckt, auf dem die Disc gerade steht.
Diese eine Entscheidung bringt dir das, was ein selbst gebautes System nie richtig hinbekommt:
*Ein Untertitel übersteht einen Sprung.* Schick die Disc irgendwohin -- `discSearch`,
`discSkipForward`, ein Einzelschritt, eine Verzweigung in ein anderes Segment -- und im nächsten
gezeichneten Frame steht die richtige Zeile da, vorwärts wie rückwärts, ohne dass etwas neu
geladen oder eine Uhr zurückgesetzt wird. In einem verzweigten Spiel wie in Lektion sechzehn, in
dem die Entscheidungen des Spielers die Disc ständig herumspringen lassen, ist das der
Unterschied zwischen funktioniert und funktioniert fast.
Es zeichnet auch an der richtigen Stelle. Das Untertitel-Dokument liegt über dem Bild, über
deinem Overlay, unter jeder GUI im Bildschirmraum, und es folgt dem Bild, wohin die Einstellungen
des Spielers es auch setzen -- ein verkleinertes Bild, ein verschobenes, ein gedrehter Automat,
ein Loch in einem Bezel. Es nimmt keine Mauseingaben an, also geht ein Lightgun-Schuss direkt
hindurch. Das alles selbst richtig hinzubekommen ist eine Woche, die du nicht eingeplant hattest.
[#_write_the_file]
=== Schreib die Datei
Untertitel kommen in eine SubRip-Datei, die auf `.srt` endet und reiner Text ist, den du in jedem
Editor tippen kannst. Es ist eines der einfachsten Formate, die es gibt. Leg neben deinem Skript
eine Datei namens `subtitles.srt` an:
----
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.
----
Ein Cue besteht aus vier Dingen. Einer Nummer auf einer eigenen Zeile. Einer Zeile mit zwei
Zeitstempeln und dazwischen einem Pfeil aus zwei Bindestrichen und einem Größer-als-Zeichen.
Einer oder mehreren Zeilen Text. Einer Leerzeile zum Abschluss.
Ein Zeitstempel ist `HH:MM:SS,mmm` -- Stunden, Minuten und Sekunden, durch Doppelpunkte getrennt,
dann ein Komma, dann Millisekunden. Das Komma ist kein Tippfehler, und ein Punkt geht nicht.
`00:00:04,200` ist vier Sekunden und eine Fünftelsekunde nach dem Start.
Die Cue-Nummern werden gelesen und weggeworfen, also müssen sie weder in der richtigen
Reihenfolge noch überhaupt richtig sein. Nummerier sie trotzdem; irgendwann wirst du Cue
einundvierzig suchen.
Cue zwei zeigt, wie ein Cue mit zwei Zeilen aussieht. Die Zeilen werden so gezeigt, wie du sie
geschrieben hast, also entscheidest *du*, wo eine lange Zeile umbricht, und das ist wichtiger,
als du denkst, und kommt weiter unten dran.
Der Parser ist mit Absicht nachsichtig bei den Dingen, die in einer von Hand bearbeiteten Datei
schiefgehen. Windows-Zeilenenden werden ohne Änderung geladen, und Leerzeichen am Anfang und Ende
jeder Zeile werden entfernt. Ein Cue, dessen Zeitstempel sich nicht lesen lassen, wird
übersprungen, und der Rest der Datei wird weiter geladen, was freundlich ist, bis du dich fragst,
wo Zeile zwölf geblieben ist. Ein paar Dinge werden nicht unterstützt: Die Tags `<i>` und `<b>`,
die manche Werkzeuge schreiben, werden als Text gezeigt, statt befolgt zu werden, und die
Positionskoordinaten, die manche Werkzeuge an die Zeitzeile anhängen, werden ignoriert. Der
Abschnitt über Untertitel in der Referenz hat die vollständige Liste.
[#_load_it_and_switch_it_on]
=== Lade sie und schalte sie ein
Drei Aufrufe, und die Reihenfolge zählt.
[source,lua]
----
if srtLoad(DIR .. "subtitles.srt") then
srtPosition(80)
srtEnable(true)
end
----
`srtLoad` liest die Datei und antwortet `true` oder `false`. Es antwortet `false` und hat dann
nichts geladen, in drei Fällen: Die Datei lässt sich nicht lesen, nichts darin lässt sich
verstehen, oder *es gibt keine Disc*. In allen drei Fällen gibt es eine Warnung mit dem
Dateinamen auf der Konsole aus. Das ist gutes Design, und du solltest es nutzen: Eine fehlende
Untertiteldatei ist es nicht wert, deswegen ein Spiel abzuschießen, aber ein Spiel stillschweigend
ohne Untertitel auszuliefern ist es wert, bemerkt zu werden.
Der Fall „keine Disc“ ist der, der dich erwischen wird. Die Zeitstempel müssen zu Frame-Nummern
mit der Bildrate der Disc werden, und bevor eine Disc offen ist, gibt es keine Bildrate, die man
benutzen könnte. Lade Untertitel also *nach* der Disc, und in einem gewöhnlichen Skript heißt
das: aus dem Hauptteil des Skripts, wo auch alles andere läuft, was du auf der obersten Ebene
geschrieben hast. Daraus folgt, dass eine `.srt`, die für ein Video mit einer Bildrate
geschnitten wurde, bei einem Video mit einer anderen an der falschen Stelle landet. Stimm die
Zeiten deiner Datei auf das Video ab, das du wirklich ausliefern wirst.
`srtEnable(true)` schaltet die geladenen Cues ein. Ein Skript fängt immer mit ausgeschalteten
Untertiteln an, also muss ein Spiel, das welche lädt, sie einschalten. Schaltest du sie wieder
aus, verschwindet, was gerade zu sehen ist, und schaltest du sie wieder ein, erscheint, was den
Frame abdeckt, auf dem die Disc gerade steht -- kein Suchen, kein Zustand, den du dir merken
musst.
Ob Untertitel an sind, ist eine Einstellung, keine Entscheidung, die du für den Spieler triffst.
Setz sie auf deine Optionsseite aus Lektion zwanzig, speichere sie mit `saveSet` aus Lektion
zwölf und gib `srtEnable`, was der Spieler zuletzt gewählt hat.
[#_where_they_sit]
=== Wo sie sitzen
[source,lua]
----
srtPosition(70)
----
`srtPosition` ist ein Prozentwert von oben nach unten im Bild, von `1` bis `95`, und der
Standard ist `80`. Er gilt für den Cue, der gerade zu sehen ist, und für jeden Cue danach. Eine
Zahl außerhalb des Bereichs wird ignoriert, statt auf den Bereich begrenzt zu werden, also lässt
ein Tippfehler die Position genau, wo sie war, und sagt nichts. Prüf deine also nach.
Achtzig Prozent liegt tief, und das mit Absicht: Der untere Teil des Bildes ist meistens der
langweiligste Teil der Einstellung. Schieb sie nach oben, wenn der untere Teil *nicht* langweilig
ist -- wenn dein Spiel eine Punkteanzeige am unteren Rand zeichnet oder wenn das
Lightgun-Fadenkreuz des Spielers dort unten wohnt.
[#_taking_one_down]
=== Einen wegnehmen
[source,lua]
----
srtClear()
----
`srtClear` nimmt sofort vom Bildschirm, was gerade dort steht, und lässt die geladenen Cues und
den eingeschalteten Zustand in Ruhe. Die Zeile, die zu sehen war, bleibt weg, bis die Disc den
nächsten Cue erreicht. Benutz es, wenn eine Szene früher endet und du nicht willst, dass die
letzte Dialogzeile über der nächsten Einstellung hängt.
Es gibt noch einen Aufruf, der die Untertitel-Mechanik mitbenutzt, und vielleicht hast du ihn
schon benutzt:
[source,lua]
----
overlayBanner("Extra life!", 20)
----
`overlayBanner` zeigt etwa dreißig gezeichnete Frames lang eine kurze Nachricht über dem Bild und
nimmt sie dann wieder weg. Es wird vom selben Dokument gezeichnet wie die Untertitel, also sieht
ein Banner aus wie ein Untertitel, und solange eines zu sehen ist, nimmt es den Platz jedes
Untertitels ein, der zurückkommt, wenn die Zeit des Banners abgelaufen ist. Sein eigenes
Höhenargument ist von `srtPosition` unabhängig und steht standardmäßig auf `47`, der Mitte des
Bildes. Nachrichten mit mehr als sechzig Zeichen werden komplett ignoriert, also scheint eine
lange überhaupt nicht zu funktionieren.
[#_subtitles_already_inside_the_video]
=== Untertitel, die schon im Video stecken
Manche Videodateien bringen ihre eigenen Untertitelspuren mit. Wenn deine das tut, brauchst du
überhaupt keine `.srt`:
[source,lua]
----
if discGetSubtitleTracks() > 0 then
srtLoadTrack(0)
else
srtLoad(DIR .. "subtitles.srt")
end
srtEnable(true)
----
`srtLoadTrack` nimmt eine Spurnummer von `0` bis `discGetSubtitleTracks() - 1`, und alles nach
dem Laden ist gleich. `discGetSubtitleLanguage(track)` sagt dir, mit welcher Sprache eine Spur
beschriftet ist, als Code aus drei Buchstaben wie `eng` oder `fra`, damit ein Spiel dem Spieler
anbieten kann, was sein Video zufällig mitbringt.
Zwei Warnungen. Eine Spur zu lesen geht einmal durch die ganze Videodatei, ohne Bilder zu
dekodieren, also dauert eine Disc in Spielfilmlänge einen Moment: Mach das, während etwas anderes
auf dem Bildschirm ist, nicht zwischen zwei Frames des Spiels. Und Untertitelspuren mit *Bildern*
der Wörter statt der Wörter selbst -- die Art, die DVDs und Blu-rays benutzen -- können nicht
gelesen werden. Sie werden mitgezählt, damit die Nummerierung zu dem passt, was andere
Videoplayer anzeigen, aber `srtLoadTrack` antwortet für sie `false`.
[#_the_whole_script_3]
=== Das ganze Skript
Dieses hier braucht ein Video. Du hast eins: `Singe/menuBackground.mkv`, das die Engine in deinen
Arbeitsordner entpackt hat, als du zum ersten Mal irgendetwas gestartet hast. Sag Singe mit
`--framefile`, dass es das als Disc benutzen soll; das schaltet auch die Disc ein:
----
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
----
Drück Feuer zum Umschalten, hoch und runter, um die Zeilen zu verschieben, und links, um an den
Anfang zurückzuspulen. Auf das Zurückspulen solltest du achten: Die Disc springt zurück auf Frame
null, und gleich im nächsten Frame ist der richtige Cue da, ohne dass du irgendetwas dafür tust.
[#_what_just_happened_17]
=== Was gerade passiert ist
[source,lua]
----
if discGetSubtitleTracks() > 0 then
loaded = srtLoadTrack(0)
end
if not loaded then
loaded = srtLoad(DIR .. "subtitles.srt")
end
----
Nimm die eigenen Untertitel des Videos, wenn es welche hat, fall auf die Datei neben dem Skript
zurück, wenn nicht, und wisse am Ende, was davon -- wenn überhaupt etwas -- funktioniert hat.
Beide Aufrufe antworten mit einem Boolean, also besteht der Rückfall aus zwei `if`-Anweisungen
und keinen Sonderfällen. `menuBackground.mkv` hat keine Untertitelspur, also bekommst du in
Wirklichkeit die Datei, die du getippt hast.
[source,lua]
----
function onInputPressed(what)
if not loaded then
return
end
----
`return` ohne etwas dahinter verlässt die Funktion sofort. Ohne geladene Untertitel gibt es für
keine dieser Tasten etwas zu tun, und früh auszusteigen ist klarer, als den ganzen Rumpf in ein
`if` zu packen. `srtEnable` aufzurufen, wenn nichts geladen ist, schadet nicht, aber Code zu
schreiben, der nur Sinn ergibt, wenn er nichts tut, ist eine Angewohnheit, die man sich besser
nicht zulegt.
[source,lua]
----
elseif what == SWITCH_LEFT then
srtClear()
discSearch(0)
discPlay()
----
Das `srtClear` ist nicht nötig. Die Engine zeigt im nächsten gezeichneten Frame sowieso den
richtigen Cue für Frame null. Es steht da, damit du es löschen und zusehen kannst, was passiert:
Die alte Zeile bleibt für einen Sekundenbruchteil stehen, während die Disc dorthin kommt, wo sie
hinwill. Bei einem langsamen Sprung sieht man dieses Aufblitzen der falschen Zeile, und vorher zu
löschen ist der Weg, es zu vermeiden.
[#_making_text_readable_over_a_moving_picture]
=== Text über einem bewegten Bild lesbar machen
Das System bringt die Wörter auf den Bildschirm. Ob jemand sie lesen kann, ist dein Problem, und
das gilt für jede Zeile Text, die du über Video zeichnest -- eine Aufforderung aus Lektion
achtzehn, eine Punktzahl, eine Auswahl an einer Verzweigung -- nicht nur für Untertitel.
*Bleib weg von den Rändern.* Fernseher schneiden seit siebzig Jahren die Ränder von Bildern ab,
und Arcade-Monitore sind schlimmer, nicht besser. Geh davon aus, dass die äußeren fünf Prozent
des Bildes auf jeder Seite auf dem Bildschirm von irgendjemandem gar nicht zu sehen sind. Halte
alles, was ein Spieler lesen muss, innerhalb davon. Darum hört `srtPosition` bei `95` auf und
nicht bei `100`.
*Kontrast ist keine Farbwahl, er ist eine Garantie.* Weißer Text über einem Bild ist weißer Text
über dem, was das Bild gerade zufällig zeigt, und in zwei Sekunden ist das vielleicht ein
Schneefeld. Der mitgelieferte Untertitelstil löst das so, wie Filmuntertitel es tun: ein dunkles
Panel, das sich eng um den Text legt, plus ein Schatten von einem Pixel. Wenn du deinen eigenen
Text über Video zeichnest, mach das eine oder das andere -- ein `overlayBox` dahinter oder eine
dunkle Kopie des Textes, um ein Pixel versetzt. Verlass dich nicht auf das Bild.
*Brich deine Zeilen selbst um.* Zwei kurze Zeilen liest man schneller als eine lange, und eine
Zeile, die umbricht, wo du es nicht ausgesucht hast, bricht meistens an der falschen Stelle. Peil
ungefähr vierzig Zeichen pro Zeile an und nicht mehr als zwei Zeilen auf einmal. Brich an einer
natürlichen Pause um: `They were wrong about / a great many things` liest sich; `They were wrong
/ about a great many things` stolpert.
*Lass sie lange genug stehen.* Eine angenehme Lesegeschwindigkeit liegt irgendwo bei fünfzehn
Zeichen pro Sekunde, also will eine Zeile mit vierzig Zeichen ungefähr drei Sekunden. Sieh dir
Cue eins in der Datei oben an: zweiunddreißig Zeichen, drei Sekunden. Wenn eine Dialogzeile kurz
und schnell ist, ist es freundlicher, den Cue noch einen Moment über das Ende des Gesprochenen
hinaus stehen zu lassen, als ihn wegzureißen.
*Setz sie dorthin, wo die Action nicht ist.* Wenn das Wichtige in der Einstellung am unteren
Bildrand ist, schieb die Untertitel für diese Szene mit `srtPosition` nach oben. Du kannst es so
oft aufrufen, wie du willst, und der Spieler merkt nie, dass du es getan hast.
[#_styling_them]
=== Sie gestalten
Die Zeilen werden von einem Dokument gezeichnet, derselben Art, die du in Lektion zwanzig
kennengelernt hast, und zwei Dateien in deinem Ordner `Singe` entscheiden, wie sie aussehen:
* `Singe/subtitle.rml` -- das Dokument. Es enthält ein einziges Element, `#slot`, in das die
Engine den aktuellen Cue oder das aktuelle Banner schreibt.
* `Singe/subtitle.rcss` -- der Stil. `.cue` ist der Block, der die Höhe trägt, die
`srtPosition` verlangt hat, und `.cue .text` ist der Textbalken darin: weiß, fett, auf einem
dunklen Panel mit runden Ecken, das sich eng um den Text legt, mit einem Schatten.
Öffne `subtitle.rcss` und lies sie -- es sind ungefähr vierzig Zeilen. Dann lass sie in Ruhe,
denn eine Änderung dort hält nicht. Bei jedem Start legt Singe seine eigene Kopie von allem im
Ordner `Singe` zurück, was verändert wurde, und sagt das:
----
>>> Updated File: Singe/subtitle.rcss
----
Dieser Ordner gehört der Engine. Dein Spiel bringt stattdessen seine eigene Kopie mit. Kopier beide
Dateien aus `Singe` in deinen Ordner `subtitles`, neben das Skript. Dann öffne deine Kopie von
`subtitle.rml` und ändere die eine Zeile in ihrem `<head>`, die den Stil einbindet, sodass sie so
lautet:
[source,html]
----
<link type="text/rcss" href="subtitle.rcss"/>
----
Ein Name in einem Dokument zählt ab dem eigenen Ordner des Dokuments, außer ein Name, der mit
`Singe/` anfängt, denn der meint immer den Ordner der Engine. Der Link, so wie du ihn kopiert hast,
`Singe/subtitle.rcss`, holt immer noch den Stil der Engine. Der neue holt deinen.
Wenn Singe eine `subtitle.rml` neben deinem Skript findet, zeichnet es die Untertitel damit statt
mit seiner eigenen. Häng `-p` an den Befehl an, und Singe beschreibt unterwegs Zeile für Zeile, was
es gerade tut:
----
Singe -p --framefile=Singe/menuBackground.mkv subtitles
----
Wenn der erste Cue erscheint, ist eine dieser Zeilen diese:
----
Using the game's own subtitles/subtitle.rml
----
Jetzt ändere `font-size`, `color`, `background-color`, `border-radius` oder `font-effect` in
deiner `subtitle.rcss`, speichere und starte es noch einmal. Die Engine setzt immer nur den Inhalt
von `#slot` und die Höhe von `.cue`, also gehört alles andere in deinen beiden Dateien dir, und
nichts, was Singe beim Start tut, rührt sie an. Wenn `-p` sagt, dass es deine verwendet, und sich
das Aussehen nicht geändert hat, lies den Link noch einmal: Eine Kopie, in der noch `Singe/` steht,
verwendet still und leise den Stil der Engine.
Weil `overlayBanner` dasselbe Dokument benutzt, gestaltest du mit den Untertiteln auch deine
Banner um, und das ist meistens, was du willst, und gut zu wissen, bevor du dich fragst, warum.
Eine Grenze: Das Untertitel-Dokument ist ein Dokument, und Dokumente brauchen eine GPU. Auf einem
Rechner ohne liest `srtLoad` deine Datei trotzdem und antwortet trotzdem ehrlich, und es wird
nichts gezeichnet. Eine Warnung sagt das einmal.
[#_try_it_21]
=== Probier es aus
. *Füg einen vierten Cue* zu `subtitles.srt` hinzu, zwischen elf und dreizehn Sekunden.
Speichere und starte es. Dann stell ihn außer der Reihe, als Cue `99`, an den Anfang der Datei,
und überzeug dich, dass es trotzdem funktioniert.
. *Gib einem Cue einen falschen Zeitstempel* -- schreib `00:00:05.500` mit einem Punkt statt
eines Kommas -- und starte es. Sieh zu, welche Zeile verschwindet, und bemerke, dass überhaupt
nichts dazu gesagt wird. Eine Datei, die lädt, ist noch keine Datei, die stimmt.
. *Gestalte sie um.* Ändere in deiner eigenen `subtitle.rcss` -- der Kopie neben deinem Skript,
nicht der in `Singe` -- `.cue .text` auf gelben Text auf einem völlig durchsichtigen Hintergrund
und füg dann einen kräftigeren Schatten hinzu. Dann spiel es
über dem Video ab und entscheide ehrlich, ob es noch lesbar ist.
. *Mach die Zeitsteuerung absichtlich kaputt.* Ändere jeden Zeitstempel in der Datei so, dass er
zwei Sekunden zu spät ist, und sieh zu, wie ein korrekt funktionierendes System nutzlose
Untertitel liefert. Genau das macht ein neu kodiertes Video mit dir.
. *Setz den Umschalter in ein Menü.* Nimm die Pausenseite aus Lektion zwanzig, füg eine Checkbox
hinzu und verbinde sie mit `srtEnable`. Dann speichere die Wahl mit `saveSet`, damit sie beim
nächsten Mal noch an ist. Das ist die Version, die deine Spieler wirklich wollen.
[#_break_it_on_purpose_20]
=== Mach es absichtlich kaputt
Starte das Skript ohne die Option `--framefile`:
----
Singe subtitles
----
Das Fenster geht auf, schwarz, mit deiner Ersatznachricht darauf, und die Konsole sagt:
----
Warning: No subtitles were loaded from subtitles/subtitles.srt.
----
Kein Absturz und kein Fehlerdialog, weil `srtLoad` mit `false` geantwortet und dein Skript damit
umgegangen ist.
Das ist der wertvollste Fehlschlag in dieser Lektion, denn er ist der, der passiert, ohne dass es
jemand merkt. Es gibt keine Disc, also gibt es keine Bildrate, also gibt es nichts, in das man
die Zeitstempel umrechnen könnte, also wird nichts geladen. Hättest du `srtLoad(...)` einfach so
hingeschrieben und die Antwort weggeworfen, wäre dein Spiel einwandfrei gelaufen und hätte keine
Untertitel gezeigt, und du hättest es erst erfahren, als es dir jemand gesagt hat.
Benutz die Antwort. Jedes Mal.
[#_what_you_learned_21]
=== Was du gelernt hast
* Ein Spiel mit Sprache und ohne Untertitel ist ein Spiel, das manche Leute überhaupt nicht
spielen können.
* Untertitel gleich beim Schreiben einzubauen ist ein Nachmittag; sie nachzurüsten nicht.
* Untertitel sind eine `.srt`-Datei: eine Nummer, zwei Zeitstempel mit `-->` dazwischen, der Text
und eine Leerzeile.
* `srtLoad` rechnet die Zeitstempel beim Laden in Frame-Nummern der Disc um, und darum übersteht
ein Cue jeden Sprung.
* Die Datei muss nach der Disc geladen werden, und das Laden antwortet `false`, wenn es nicht
klappt, auch dann, wenn es keine Disc gibt. Prüf die Antwort.
* `srtEnable` schaltet sie ein, und ein Skript fängt immer mit ausgeschalteten an.
* `srtPosition` setzt sie als Prozentwert von oben im Bild, `1` bis `95`.
* `srtClear` nimmt weg, was gerade zu sehen ist, und `overlayBanner` benutzt dasselbe Dokument.
* `srtLoadTrack` liest Untertitel aus der Videodatei selbst, wenn sie welche hat.
* Singe schreibt seinen Ordner `Singe` bei jedem Start neu, also kopierst du, um Untertitel
umzugestalten, `subtitle.rml` und `subtitle.rcss` neben dein Skript, lässt den Link der Kopie auf
dein eigenes Stylesheet zeigen und änderst dieses.
* Text über einem bewegten Bild braucht einen sicheren Rand, seinen eigenen Kontrast, Zeilen, die
du selbst umgebrochen hast, und Zeit, um gelesen zu werden.
[#_next_time_21]
=== Beim nächsten Mal
Das war das Letzte zum Thema Text. Teil vier geht weiter, ohne dass du ihn der Reihe nach lesen
musst, und die nächste Lektion öffnet eine Tür, die zwanzig Lektionen lang zu war:
`overlayGetWidth` und `overlayGetHeight` sind zwei Zahlen, und eine Szene hat drei. Lektion
zweiundzwanzig ist die dritte.