= Singe-Handbuch Scott Duensing :revnumber: 3.00 :revdate: 2026 :doctype: book :toc: left :toclevels: 3 :sectnums: :sectnumlevels: 3 :title-logo-image: image:images/singeLogo.png[Singe, pdfwidth=2.6in, align=center] :source-highlighter: rouge :icons: font :experimental: :lang: de :imagesdir: .. include::locale.adoc[] [#_about_singe] == Über Singe Singe (Scott's Increasingly Nifty Game Engine, „Scotts zunehmend pfiffige Spiel-Engine“, benannt nach dem Drachen aus Dragon's Lair) ist ein Lua-basiertes Skriptsystem, mit dem sich schnell Prototypen neuer Laserdisc-Spiele bauen oder ganz neue Spiele erschaffen lassen. Die Sprache ist leicht zu lernen, sehr mächtig und schnell. Alle Funktionen, die du für dein eigenes Spiel brauchst, stehen über eine einfache Programmierschnittstelle (API) zur Verfügung. Singe bietet dem Spieleentwickler zahlreiche Funktionen. Einige der interessanteren sind: * 3D-Szenen mit Modellen, Animation, Beleuchtung und Schatten * Physik, einschließlich Gelenken, Ragdolls, Soft Bodies und Fahrzeugen * Menüs, Optionsbildschirme und HUDs, gebaut wie Webseiten * Hardware-Videodekodierung, sogar auf kleinen Rechnern * Online-Highscores und ein Katalog von Spielen zum Herunterladen und Aktualisieren * Spiele, in eine einzige Datei gepackt * Objektorientierte Programmiersprache * Animierte Sprites * Unterstützung für TrueType-Schriftarten * 32-Bit-Farbraum mit Transparenz * Mehrkanaliger, überlappender Stereo-Sound und MIDI * Unterstützung für analoge und digitale Eingabegeräte, einschließlich Lightguns * Breite Unterstützung für Video- und Audioformate Singe läuft unter Windows, macOS und Linux, auf ARM-Prozessoren ebenso wie auf Intel- und AMD-Prozessoren: auf Windows-on-ARM-Laptops, dem Raspberry Pi und Handhelds wie dem R36S. Spielern ermöglicht Singe, viele nicht emulierte und neue Spiele mit einem beliebigen Frontend oder über das mitgelieferte Menüsystem zu genießen. Seit der ersten Veröffentlichung von Singe im Jahr 2006 sind mehrere Überarbeitungen erschienen, offizielle wie inoffizielle. 2020 erschien Singe 2.00. Es war eine komplette Neuentwicklung von Grund auf, die zahlreiche Funktionen hinzufügte und dabei mit bestehenden 1.xx-Spielen kompatibel blieb. Singe 3.00 bringt 3D, Physik, Benutzeroberflächen und vieles mehr und spielt trotzdem weiterhin die Spiele, die davor kamen. Zu dem Zeitpunkt, als dieses Handbuch geschrieben wurde, ist die neueste Version {revnumber}. [#_installation_and_upgrading] == Installation und Aktualisierung [#_installing_singe] === Singe installieren Um Singe zu installieren, lade einfach die passende Binärdatei für dein System herunter. Leg sie allein in einen neuen Ordner und starte sie. Beim ersten Start legt Singe alle nötigen Verzeichnisse und Hilfsdateien an. Jetzt kannst du Spiele installieren. Auf einem Windows-PC mit ARM-Prozessor nimm die Version `Windows-aarch64`: Die Version `Windows-x86_64` läuft dort auch, emuliert, aber langsamer. [#_upgrading_singe] === Singe aktualisieren Um Singe auf eine neuere Version zu aktualisieren, leg die neue Binärdatei neben die alte in den Installationsordner und starte sie einmal mit `--refresh`. Der vorhandene Hilfsordner wird als `old-Singe-` beiseitegelegt, benannt nach der Version, die ihn geschrieben hat, und an seiner Stelle wird ein frischer Ordner `Singe/` geschrieben. Nichts wird gelöscht: Der beiseitegelegte Ordner gehört dir, du kannst ihn behalten oder entfernen, und ein zweites `--refresh` legt seinen eigenen als `old-Singe--1` beiseite, statt den ersten zu überschreiben. Die alte Binärdatei kann bleiben, wo sie ist. `Menu.sh` (oder `Menu.bat`) startet das neueste Singe, das es neben sich findet, und eine Beta gilt als älter als das Release mit derselben Nummer, sodass `Singe-v3.00b2` dem `Singe-v3.00` Platz macht, sobald es eintrifft. Das Tool Engine Update im Menü erledigt all das für dich; siehe <>. WARNING: Starte eine neue Singe-Binärdatei nie mit einem veralteten Satz Hilfsdateien. Erneuere beim Aktualisieren immer das Verzeichnis `Singe/`. [#_things_to_know] === Wissenswertes Fass den Ordner `Singe/` nicht an. Die Dateien in diesem Ordner gehören Singe und können jederzeit aktualisiert oder gelöscht werden. [#_playing_games] == Spiele spielen [#_installing_games] === Spiele installieren Ein Spiel ist entweder eine einzelne `.game`-Datei oder ein Verzeichnis. Kopiere es in denselben Ordner, in dem die Singe-Binärdatei liegt. Das mitgelieferte Menüsystem erkennt es automatisch und nimmt es ins Menü auf. [#_game_directory_layout] === Aufbau des Spieleverzeichnisses Eine Singe-Installation ist ein Spieleverzeichnis, das Folgendes enthält: das Hilfsverzeichnis `Singe`, das die Engine beim ersten Start anlegt, ein Verzeichnis pro Spiel, alle gepackten `.game`-Dateien und ein Verzeichnis `data` für alles, was die Spiele und die Engine schreiben. Die ausführbare Datei liegt meist auch dort, muss aber nicht: `--gamedir` nennt das Spieleverzeichnis von überall aus, und die `Menu.sh` (oder `Menu.bat`), die die Engine dort schreibt, startet die ausführbare Datei dann über ihren vollen Pfad. Andernfalls sucht der Launcher neben sich nach den Dateien, deren Namen mit `Singe` beginnen, und startet die beste davon, ganz im Sinne der Launcher, die `BatMaker` schreibt, damit ein Update, das die Version im Namen der ausführbaren Datei ändert, keinen Launcher hinterlässt, der auf eine Datei zeigt, die es nicht mehr gibt. „Die beste“ heißt: zuerst die Architektur dieses Rechners und danach die Version. Die Plattform im Namen wird mit dem verglichen, was das System meldet, denn ein neuerer Build für eine andere Architektur kann überhaupt nicht laufen, und ein Spieleverzeichnis auf einer Freigabe kann von einem Pi genauso gelesen werden wie von einem PC. Der Launcher ermittelt das bei jedem Start, statt es einmal gesagt zu bekommen, sodass dasselbe Verzeichnis für jeden Rechner passt, der es öffnet. Auf einem Mac gilt ein Universal-Build als nativ. Unter den Builds, die dieser Rechner ausführen kann, gewinnt der neueste: `Singe-v3.10` schlägt `Singe-v3.09`, und eine Beta verliert gegen das Release, auf das sie hinführt, also verliert `Singe-v3.00b2` gegen `Singe-v3.00`. Ein Build für eine andere Architektur wird trotzdem gestartet, wenn er der einzige ist, denn eine echte Beschwerde der Engine ist besser als die Auskunft, es sei nichts gefunden worden, und dasselbe gilt für einen Namen, den der Launcher überhaupt nicht lesen kann. ---- Singe/ Hilfsdateien, von der Engine entpackt Framework.singe Wird von jedem Spiel geladen (per dofile) Menu.singe Das mitgelieferte Spielmenü Tools.singe Die Service-Tools des Menüs (siehe Die Service-Tools) MenuDocument.singe Das Menü, als GUI-Dokument gezeichnet MenuOverlay.singe Das Menü, ins Overlay gezeichnet, für einen Rechner ohne GPU Backdrop.singe Das Intro des Menüs und das Gitter dahinter, live gezeichnet menuBackground.mkv Derselbe Hintergrund als Aufnahme, für einen Rechner ohne GPU menuIntro.flac Sein Ton, der ausblendet, wenn das Menü den Bildschirm übernimmt Menu.rml Das RmlUi-Dokument des Dokument-Renderers menu.rcss Sein Stylesheet, aufbauend auf gui.rcss gui.rcss Das mitgelieferte GUI-Theme controls.cfg.example Vorlage für Eingabebelegungen click.wav Für den Audioverzögerungs- und den Soundtest des Menüs Manual.pdf Dieses Handbuch Manual-fr.pdf Dieses Handbuch auf Französisch Manual-it.pdf Dieses Handbuch auf Italienisch Manual-de.pdf Dieses Handbuch auf Deutsch Manual-es.pdf Dieses Handbuch auf Spanisch COPYING Die GNU General Public License, Version 3 LICENSES Hinweise zu Fremdsoftware und Nachweise für Assets Collection/ Ein Verzeichnis mit Spielen games.dat Menüeinträge für die Spiele in diesem Verzeichnis AsteroidPatrol.singe Ein Skript frame_AsteroidPatrol.txt Seine Frame-Datei (oder ein Video mit demselben Basisnamen) sprite_*.png, sound_*.wav, font_*.ttf MyGame.game Ein in eine Datei gepacktes Spiel (siehe Spiele in einer Datei) data/ machine.cfg Audioverzögerung und Bildgeometrie dieses Rechners Collection/ Indizes, trace.txt, Screenshots, Spielstände dieser Spiele ---- Wo Singe nach den Dateien eines Skripts sucht und wohin ein Skript schreiben darf, ist Sache dessen, der das Skript schreibt; die Singe-Referenz behandelt beides unter „Dein Spiel verpacken“. [#bundledmenu] === Das mitgelieferte Menü `Menu.sh` (oder `Menu.bat`) startet `Singe/Menu.singe`, das mitgelieferte Menü: ein RmlUi-Dokument, `Singe/Menu.rml`, gestaltet durch `Singe/menu.rcss`, gezeichnet über einem live berechneten 3D-Hintergrund (siehe xref:Reference.adoc#gui[GUI]). Das Menü läuft ohne Disc; ein Rechner ohne GPU spielt stattdessen `Singe/menuBackground.mkv` ab, eine Aufnahme desselben Hintergrunds, hinter einer einfacheren Seite, die ins Overlay gezeichnet wird. Es liest die `games.dat` jedes Spieleverzeichnisses und jeder `.game`-Datei neben sich und listet jedes gefundene Spiel, nach Titel sortiert, am linken Bildschirmrand auf. Neben der Liste stehen die Automatengrafik, das Marquee und der Attract-Clip des ausgewählten Spiels, darunter Jahr, Genre, Plattform, Entwickler, Publisher, Portierungs-Credits und Beschreibung, und am unteren Rand eine Zeile mit Tastenhinweisen. Hoch und runter bewegen die Auswahl um ein Spiel, links und rechts bewegen sie um eine Seite; beide springen vom einen Ende der Liste zum anderen. Start oder ein beliebiger Aktionsknopf startet das ausgewählte Spiel, und die Taste, die `INPUT_SERVICE` zugeordnet ist (standardmäßig die Taste `9`), öffnet die Service-Tools (siehe <>). Mit einer Maus wählt ein Klick auf eine Zeile das Spiel aus, und ein zweiter Klick auf dieselbe Zeile startet es; das Mausrad scrollt eine Beschreibung, die zu lang für ihr Feld ist. Wenn du `--quitchord` setzt, beendet das Halten dieser Knöpfe ein Spiel zurück ins Menü und das Menü zurück zu deinem System (siehe <>). Das Menü speichert seine Auswahl in `menu.dat` in seinem Datenordner, damit es wieder beim selben Spiel steht, wenn eines beendet oder Singe das nächste Mal gestartet wird. Diese Datei ist ein Lua-Fragment, das das Menü beim Start liest und beim Beenden neu schreibt: `GAME_SELECTED` ist das Spiel, das es gerade zeigte, `SHOW_INTRO` ist false, wenn es aus einem Spiel zurückkehrt, damit man das Intro nicht zweimal aussitzen muss, und `MENU_OVERLAY` wählt einen Renderer (siehe <>). Nicht jeder Rechner kann jedes Spiel ausführen. Ein 3D-Spiel auf einer Kiste ohne 3D oder ein schweres Spiel auf einer kleinen würde scheitern oder kriechen, also sagt dir das Menü vorher Bescheid. Wenn du ein Spiel auswählst, das dieser Rechner nicht ausführen kann, sagt die Zeile unter seinen Details, was es braucht („Needs 3D, and this machine has none.“), und der Startversuch wiederholt nur das, statt mittendrin zu scheitern. Ein Spiel, das mehr Rechner will, als dieser hier ist, bekommt „It may run slowly.“ und startet trotzdem. Nichts wird versteckt. Das Menü ermittelt, wie schnell dieser Rechner ist, wenn sein Intro zum ersten Mal läuft, indem es seinen eigenen Hintergrund misst, und behält das Ergebnis in `machine.cfg`; es verlangt nie von dir, einen Benchmark laufen zu lassen. Spiele geben in ihrer `games.dat` an, was sie brauchen (xref:Reference.adoc#gamesdat[REQUIRES und TIER]), und das Tool Get Games kennzeichnet den Katalog auf dieselbe Weise. [#menurenderers] ==== Die zwei Renderer Ein GUI-Dokument wird über das GPU-Gerät gezeichnet, das auch die 3D-Szene benutzt, auf einem Rechner ohne ein solches gibt es also kein Dokument zu bauen. Das Menü regelt das selbst: `Singe/Menu.singe` fragt beim Start xref:Reference.adoc#singehasgpu[singeHasGpu] und lädt einen von zwei Renderern. `Singe/MenuDocument.singe`:: Das oben beschriebene RmlUi-Dokument, für einen Rechner mit GPU-Gerät. Es zeichnet außerdem das Intro und das Gitter hinter dem Menü als eine durchgehende 3D-Szene, sodass für keines von beiden die Disc benutzt wird. `Singe/MenuOverlay.singe`:: Sprites und `fontPrint` direkt ins Overlay, der Look, den Singe 2 hatte. Es braucht nichts außer dem Overlay, in das jedes Spiel sowieso zeichnet. Beide zeichnen dasselbe Menü, nehmen dieselben Tasten und starten dieselben Service-Tools; `Singe/Menu.singe` enthält alles, was nicht Zeichnen ist -- die Spieleliste, die Auswahl, das Starten eines Spiels -- und so gibt es ein Menü statt zwei. Der Overlay-Renderer zeigt ein Spiel auf einmal statt einer Liste, da er kein Feld zum Scrollen hat, und er schneidet eine für ihre Spalte zu lange Beschreibung ab, statt sie zu scrollen. Um den Overlay-Renderer auf einem Rechner zu sehen, der eine GPU hat, schreib `MENU_OVERLAY = true` in `menu.dat` im Datenordner des Menüs; das Menü schreibt die Zeile wieder heraus, also bleibt sie erhalten. So wird der Overlay-Pfad getestet, und so bekommt ein Automatenbauer, der den alten Look bevorzugt, ihn. [#onlineservice] ==== Online: Konten, Spiele und Punkte Das mitgelieferte Menü kann den Automaten bei einem Master-Dienst anmelden (standardmäßig `master.singeengine.com`), der drei Dinge tut: Er verwaltet das Konto, er bietet einen Katalog von Spielen zum Herunterladen und Aktualisieren an, und er führt Highscore-Bestenlisten. Zwei Service-Tools decken das ab. **Online Account** meldet an, legt ein Konto an, stellt ein Passwort wieder her und setzt die Serveradresse -- dort richtet ein Betreiber, der seinen eigenen Dienst betreibt, den Automaten darauf aus. Ein neues Konto ist erst nutzbar, wenn der per E-Mail geschickte Link geöffnet wurde. **Get Games** listet alles auf, was der Dienst anbietet, markiert, was hier installiert ist, und lädt es herunter, aktualisiert oder entfernt es. Ein Download mit mehreren Spielen (einer Sammlung oder einem Spiel in zwei Sprachen) stellt jedes davon unter seinem eigenen Namen in die Liste, mit dem Hinweis, in welchem Download es steckt, und wer eines davon holt oder entfernt, holt oder entfernt alle, denn sie sind eine Datei. Was angeboten wird, hängt vom Konto ab: Ein Dienst kann ein Spiel bestimmten Konten vorbehalten, sodass zwei Automaten, die bei verschiedenen Konten angemeldet sind, verschiedene Listen sehen können. Das Menü selbst sagt, wenn es eine neuere Version eines installierten Spiels gibt: Das Spiel trägt in der Liste eine Markierung `update`, die Zeile unter seinen Details nennt die Version, und Knopf 3 auf dieser Seite holt sie, sodass ein Automat kein Service-Tool öffnen muss, um aktuell zu bleiben. Über diesen Rechner wird nirgends etwas gespeichert: Das Menü liest die Version aus der eigenen `games.dat` jedes Spiels und fragt nach seiner eigenen Liste, sodass ein von Hand hineinkopiertes Spiel genauso bekannt ist wie eines, das hier heruntergeladen wurde. Ein Automat ganz ohne Spiele öffnet trotzdem das Menü, das sagt, wie man welche holt, und was Get Games herunterlädt oder entfernt, steht in der Liste, sobald die Service-Tools geschlossen werden. Eine Liste, die länger ist als der Bildschirm, scrollt mit der Auswahl mit, statt unten herauszulaufen, und `...` zeigt, dass es in der jeweiligen Richtung mehr gibt. Ein Spiel, das nicht mehr angeboten wird, funktioniert weiter und wird als „installed, no longer offered“ angezeigt: Es bekommt lediglich keine Updates mehr, denn ein Spieler, der ein Spiel hat, hat es. Ein Download wird mit der Prüfsumme abgeglichen, die der Katalog veröffentlicht hat, bevor er irgendetwas ersetzt, sodass eine fehlerhaft angekommene Übertragung scheitert, statt ein Spiel zu installieren, das nicht läuft. Das Konto gehört dem *Rechner*, nicht einem Spiel: Das Token liegt in `master.dat` im obersten Datenordner, sodass ein Spiel, das eine Punktzahl meldet, dieselbe Anmeldung benutzt, die das Menü vorgenommen hat. Das Passwort wird nie gespeichert, und die Datei ist verschleiert, sodass man Token und Adresse des Kontos nicht auf einen Blick herauslesen kann; eine bearbeitete Datei gilt als abgemeldet. Der Rechner muss sie unbeaufsichtigt zurücklesen können, also behandle `master.dat` trotzdem wie einen Schlüssel zum Konto: Auf einen anderen Rechner kopiert, meldet sie diesen an. Um eine Punktzahl zu melden, braucht man dieses Konto, um eine Bestenliste zu lesen aber nicht: Ein Automat, der nicht angemeldet ist, zeigt trotzdem die Online-Bestenliste eines Spiels, sofern das Spiel eine zeigt, für jedes Spiel, das der Dienst allen anbietet. Siehe xref:Reference.adoc#onlinescores[Online-Highscores] für die Seite des Spiels und `Singe/Net.singe` für den asynchronen HTTP-Client darunter -- nichts hier blockiert einen Frame, denn Lua ist in Singe kooperativ, und ein großer Download sähe sonst wie ein Hänger aus. Singe prüft das Zertifikat des Servers gegen zwei Listen zugleich: die, die es mitbringt, und die, die dein Rechner führt. Es genügt, wenn eine von beiden für den Server bürgt, sodass eine alte Singe-Kopie das Update, das sie ersetzt, immer noch erreichen kann, solange dein System seine eigene Liste aktuell hält. Du betreibst deinen eigenen Dienst mit einem Zertifikat deiner eigenen Zertifizierungsstelle? Leg das Zertifikat dieser Stelle in `cacerts.local.pem` im Datenordner. Singe schreibt diese Datei nie, also übersteht sie Updates. Wird eine Verbindung abgelehnt, sagt die Meldung, welche Listen geprüft wurden, und ein Zertifikat, das „not yet valid“ ist, bedeutet fast immer, dass die Uhr des Rechners falsch geht. [#servicetools] ==== Die Service-Tools Die Taste, die `INPUT_SERVICE` zugeordnet ist, öffnet eine Liste von Tools über der Spieleliste. Hoch und runter wählen eines aus, und Knopf 1 öffnet es; Knopf 2 führt aus einem Tool zurück zur Liste, und die Service-Taste verlässt die Tools, noch einmal gedrückt, ganz. Alles steckt in `Singe/Tools.singe`, das die Engine neben `Menu.singe` entpackt. Dort zeichnet nichts: Ein Tool baut eine Liste von Zeilen und übergibt sie dem Menü, weshalb jedes Tool auf beiden Renderern läuft (siehe <>). Nichts hier braucht ein laufendes Spiel, und nichts verändert die eigenen Dateien eines Spiels. Audio Delay:: Die Audioverzögerung der nachgeschalteten Geräte, gemessen an einem Klick und einem Blitz. Siehe xref:Reference.adoc#menucalibration[Kalibrieren über das Menü] dafür, was das Tool tut und warum es funktioniert. Input Test:: Jeder Controller, jede Maus und jede Lightgun, die die Engine sehen kann, live: der letzte Schalter, den das Spiel erhalten hätte, und wie viele angekommen sind, der Name jedes Pads mit seinen sechs Achsen und den gedrückten Knöpfen sowie Name und Position jeder Maus. Das ist der Bildschirm, der „der Knopf tut nichts“ beantwortet -- entweder kommt der Schalter an und das Spiel ignoriert ihn, oder er kommt gar nicht erst an. System Information:: Die Version der Engine, das Betriebssystem, Prozessor und Arbeitsspeicher, der Renderer und das 3D-Gerät, welche Videodecoder im Spiel sind, die eingebauten Audioformate, der SoundFont, der MIDI-Zustand, die Größen von Fenster, Zeichenfläche und Overlay sowie der Datenordner. Ein Foto dieser Seite beantwortet den größten Teil eines Fehlerberichts. Light Gun:: Ziele in der Mitte und in jeder Ecke des Overlays, über dem, was die Disc gerade zeigt. Knopf 1 markiert, wohin die Lightgun tatsächlich gezeigt hat, und behält die letzten zwölf Schüsse; Start löscht sie. Eine Lightgun, die genau auf das Bild justiert ist, setzt ihre Kreuze auf die Ziele, und eine, die es nicht ist, zeigt, in welche Richtung sie danebenliegt. Sound Test:: Knopf 1 spielt den Klick über den linken Lautsprecher, dann den rechten, dann beide, und das ist schon die ganze Prüfung auf vertauschte Kabel. Außerdem listet es die eigenen Tonspuren der Disc auf, und links und rechts schalten zwischen ihnen um. Display:: Größe, Position und Drehung des Bildes, live verändert mit den Pfeilen, den Knöpfen 3 und 4 und Münze 1, über einem Testbild: ein Raster von 16 mal 12, um das Bild gerade auszurichten, ein Graukeil in acht Stufen, um die Helligkeit einzustellen, und zwei Rahmen ganz am Rand, ein Pixel voneinander entfernt -- ein Monitor mit Overscan frisst zuerst den äußeren. Knopf 1 speichert die Werte für diesen Rechner, in derselben `machine.cfg`, die auch die Audioverzögerung benutzt, sodass sie für jedes Spiel gelten, statt einmal pro Spiel eingestellt zu werden. Start setzt alles zurück. Disc Test:: Zwölf Sprünge, über die ganze Disc verteilt, jeder mit Zeitmessung. Ein Rip, dessen Keyframes weit auseinanderliegen, springt langsam, und das einzige Symptom im Spiel ist, dass sich alles schwerfällig anfühlt; dieses Tool misst es direkt und meldet den schlechtesten der zwölf. Ein Sprung, der nach drei Sekunden nicht angekommen ist, wird mit drei Sekunden gezählt. Saved Data:: Was jedes Spiel gespeichert hat, gefunden durch Durchsuchen des obersten Datenordners statt durch Auskunft, mit der jeweiligen Größe. Knopf 3 -- nicht Knopf 1, der überall sonst „auswählen“ bedeutet -- verwirft den Spielstand des ausgewählten Spiels. Der übliche Grund ist, eine Highscore-Tabelle zu leeren, ohne das Spiel zu löschen. Engine Update:: Ein neueres Singe, wenn der Dienst eines für diesen Rechner hat. Eine Beta trägt die Version `3.00b2`, die zweite Beta von 3.00, und kommt vor 3.00 selbst, sodass einem Automaten, auf dem eine Beta läuft, das Release am Tag seiner Veröffentlichung angeboten wird. Zeigt, was läuft und was angeboten wird, und Knopf 1 holt es, prüft es gegen die Prüfsumme, die der Dienst veröffentlicht hat, legt es unter dem eigenen Namen des Release neben das laufende Singe, legt das alte als `old-` beiseite und startet neu in das neue. Das Beiseitelegen des alten kann verweigert werden, durch einen Ordner, in den dieser Benutzer nicht schreiben kann, oder durch einen Virenscanner, der die Datei festhält; das Tool sagt das und macht weiter, da der Launcher so oder so das neueste Singe im Ordner startet. Das neue Singe startet mit `--refresh`, sodass der Hilfsordner von der Version neu geschrieben wird, der er jetzt gehört, und der alte als `old-Singe-` erhalten bleibt; eine Datei, die ein älteres Singe mitbrachte und dieses nicht, kann nicht liegen bleiben und ein Spiel verwirren. Bis zu diesem Knopfdruck passiert nichts. Knopf 3 fragt den Dienst erneut. Das Menü schaut von sich aus einmal am Tag nach und sagt das in einer Zeile unter den Details des Spiels; `no_update_check = true` in `settings.cfg` stoppt die tägliche Prüfung, und das Tool funktioniert weiterhin von Hand. Online Account:: Diesen Automaten beim Master-Dienst anmelden, ein Konto anlegen, ein Passwort wiederherstellen und die Serveradresse setzen. Siehe <>. Get Games:: Der Katalog: was der Dienst anbietet, was hier installiert ist, und Herunterladen, Aktualisieren oder Entfernen. MIDI Ports:: Die Ein- und Ausgangsports dieses Rechners, welche davon Singe geöffnet hat, und die letzten paar Nachrichten, die angekommen sind. Knopf 1 sendet eine Note, Knopf 3 sucht erneut nach Ports, nachdem etwas eingesteckt wurde. Nichts wird geöffnet, bevor dieses Tool fragt, sodass ein Automat, der MIDI nie anrührt, auch nie dafür bezahlt. Frame Statistics:: Schaltet das Entwickler-Overlay ein und aus. Es bleibt bis ins Spiel hinein eingeschaltet, in der oberen linken Ecke. Siehe xref:Reference.adoc#statsenable[statsEnable]. [[controls]] == Steuerung Standardmäßig belegt Singe Controller so, als wären sie Xbox-Gamepads. Wenn dein Controller nicht erkannt wird oder du die Standardbelegungen ändern willst, so wie sie Singe erscheinen, kannst du das kostenlose SDL2 Gamepad Tool von http://generalarcade.com/gamepadtool/ benutzen. [[controlscfg]] === controls.cfg Zusätzlich zur Konfiguration deines Controllers kannst du mit `controls.cfg`-Dateien alle Eingabeoptionen für Singe als Ganzes oder für jedes einzelne Spiel neu belegen. Um zu bestimmen, wie Eingaben belegt sind, liest Singe Konfigurationseinstellungen in der folgenden Reihenfolge, und eine spätere Datei ersetzt eine frühere Eingabe für Eingabe (siehe <>): . Die Standardwerte aus Singe selbst. . `controls.cfg` aus dem Hauptskriptverzeichnis des Spiels: das, was der Autor des Spiels mitgeliefert hat. . `controls.cfg` aus dem Verzeichnis, in dem Singe gestartet wurde: die eigene des Rechners (das Verzeichnis `Singe` enthält eine Vorlage `controls.cfg.example`, die du kopieren kannst). . `controls.cfg` aus dem Verzeichnis über dem Datenordner des Spiels. . `controls.cfg` aus dem Datenordner des Spiels: deine, für genau dieses eine Spiel. Du musst nicht jede Option in einer eigenen `controls.cfg`-Datei angeben. Gib ruhig nur die Einträge an, die du ändern willst. Nach der Installation von Singe findest du eine Beispieldatei für die Eingabekonfiguration unter `/Singe/controls.cfg.example`. Welche Konfigurationsoptionen in dieser Datei zur Verfügung stehen, erfährst du, wenn du `/Singe/Framework.singe` durchliest. `--keymapfile` nennt eine einzelne Datei, die statt dieser Suche gelesen wird, was einem Frontend nützt, das keinen Zweifel daran haben will, welche Belegungen ein Spiel bekommen hat. Jeder `INPUT_`-Eintrag ist eine Liste, und jedes einzelne Element darin betätigt den Schalter. Eine Liste innerhalb dieser Liste ist eine Tastenkombination: zwei bis vier Tasten oder Knöpfe, zusammen gehalten, die den Schalter betätigt, wenn die letzte davon heruntergeht, und ihn loslässt, sobald irgendeine davon wieder hochkommt. Ein Handheld ohne Esc-Taste beendet auf diese Weise mit Select und Start zusammen: [source,lua] ---- INPUT_QUIT = { SCANCODE.ESCAPE, { GAMEPAD_0.BUTTON_BACK, GAMEPAD_0.BUTTON_START } } ---- Jede Taste und jeder Knopf in einer Kombination behält außerdem die eigene Bedeutung, sodass Select und Start, auf diese Weise zum Beenden gedrückt, auf dem Weg nach draußen auch eine Münze einwerfen und Start drücken. Wenn du eine Möglichkeit zum Beenden willst, die immer funktioniert, nimm stattdessen `--quitchord`. Wenn du einen seiner Knöpfe drückst, wartet Singe eine Viertelsekunde auf die übrigen, bevor es irgendetwas anderes tut, sodass das Beenden keine Münze einwirft und nicht Start drückt. Ein Spiel kann seine eigene Beenden-Taste abschalten, aber nicht `--quitchord`. [[devices]] === Jedes Gerät ist ein Gamepad Singe hat eine einzige Controller-Familie, `GAMEPAD_0` bis `GAMEPAD_3`, und jedes Gerät, das es öffnet, gehört dazu. SDL nennt ein Gerät nur dann ein Gamepad, wenn es eine Belegung dafür hat, und eine Arcade-Encoder-Platine, ein Spinner, ein Lenkrad oder ein Flugsteuerknüppel hat oft keine. Statt eine zweite Geräteart mit eigenen Namen mitzuschleppen, schreibt Singe für ein solches Gerät selbst eine Belegung und öffnet es dann als gewöhnliches Gamepad, sodass es `controls.cfg`, `controllerGetAxis`, `controllerGetButton` und jeden `INPUT_*`-Schalter genau so erreicht wie ein erkanntes Pad. Die Belegung, die Singe schreibt, ist eine direkte: Die Achsen des Geräts werden der Reihe nach zum linken Stick, zum rechten Stick und dann zu den beiden Triggern; seine Knöpfe werden der Reihe nach zu `BUTTON_A`, `BUTTON_B`, `BUTTON_X`, `BUTTON_Y`, `BUTTON_BACK`, `BUTTON_GUIDE`, `BUTTON_START`, `BUTTON_LEFT_STICK`, `BUTTON_RIGHT_STICK`, `BUTTON_LEFT_BUMPER` und `BUTTON_RIGHT_BUMPER`; und sein erster Hat-Switch wird zum Steuerkreuz. Ein Gerät ohne Hat-Switch verwendet stattdessen seine nächsten vier Knöpfe für das Steuerkreuz. **Ein Gerät mit mehr Bedienelementen, als das Gamepad-Modell benennen kann, verliert die überzähligen** -- mehr als sechs Achsen, mehr als fünfzehn Knöpfe oder ein zweiter Hat-Switch -- und bei einem Gerät, dessen Knöpfe nicht in dieser Reihenfolge verdrahtet sind, liegen sie an den falschen Stellen. Das ist der Preis für eine Familie statt zwei, und er lässt sich leicht korrigieren: `--program` schreibt die Belegung, die es geschrieben hat, in SDLs eigenem Format in den Trace, sodass du sie in eine `gamecontrollerdb.txt` einfügen, umordnen und stattdessen verwenden lassen kannst. `--mapjoysticks=false` schaltet das Schreiben ab; dann wird ein Gerät, das SDL nicht erkennt, überhaupt nicht geöffnet, genau wie in früheren Versionen. [[gamecontrollerdb]] === gamecontrollerdb.txt SDL bringt eine große Datenbank mit Controller-Belegungen mit, und die Community pflegt eine noch größere -- `gamecontrollerdb.txt`, von https://github.com/mdqinc/SDL_GameControllerDB. Singe sucht diese Datei an denselben vier Orten, an denen es nach `controls.cfg` sucht, in derselben Reihenfolge (siehe <>): . im Hauptskriptverzeichnis des Spiels; . im Verzeichnis, in dem Singe gestartet wurde; . im Verzeichnis über dem Datenordner des Spiels; . im Datenordner des Spiels. Jede gefundene Datei wird geladen, in dieser Reihenfolge, sodass die Datei des Rechners eine Datei schlägt, die ein Spiel mitbringt, eine Datei im Datenordner des Spiels beide schlägt und alle zusammen SDLs eigene Datenbank schlagen. Nur ein Gerät, das keine davon nennt, bekommt die Belegung, die Singe dafür schreibt: Sie ist der letzte Ausweg, nie ein Konkurrent deiner Dateien. `--program` meldet, wie viele Belegungen jede Datei hinzugefügt hat. Die Dateien schlagen auch `SDL_GAMECONTROLLERCONFIG`, die Umgebungsvariable, aus der SDL Belegungen übernimmt und die manche Handheld-Systeme für ihr eingebautes Pad setzen. Die Belegung von ArkOS für den R36S zum Beispiel lässt Select und Start weg, sodass kein Spiel sie sieht; eine Zeile in `gamecontrollerdb.txt` für dasselbe Pad bringt sie zurück. SDL liest die Variable einmal, wenn Singe startet, also gilt das für die Dateien, die das erste Spiel findet. Ein später aus dem Menü gestartetes Spiel liest zwar weiterhin seine eigenen, aber ein Pad, das die Variable nennt, behält die Belegung der Variablen. Eine Zeile dieser Datei sieht so aus und ist genau das, was der Trace für ein Gerät ausgibt, das Singe selbst belegt hat: ---- ff00d87a475300004900000000007603,Arcade Encoder,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b4,guide:b5,start:b6,leftx:a0,lefty:a1,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8, ---- [[deadzones]] === Totzonen und Trigger `DEAD_ZONE` in `controls.cfg` gibt an, wie weit sich eine Achse bewegen muss, bevor sie als gedrückter Schalter zählt, in den Rohwerten, die SDL meldet: `32767` bei vollem Ausschlag, also liegt der Standardwert `15000` knapp unter der Hälfte. Er gilt für jede Achse jedes Pads, die beiden analogen Trigger eingeschlossen, und ein Skript liest ihn als `SINGE_DEAD_ZONE`. Zwei Einstellungen grenzen das weiter ein. `DEAD_ZONES` ist eine Liste von Paaren `{ axis, dead zone }` für jeweils eine Achse, in denselben Rohwerten, für einen schwergängigen Stick oder einen abgenutzten Trigger, der nicht alles andere bewegen soll: [source,lua] ---- DEAD_ZONES = { { GAMEPAD_0.AXIS_LEFT_X, 8000 }, { GAMEPAD_1.AXIS_LEFT_TRIGGER, 30000 }, } ---- Die Achse kann als die Achse selbst oder als eine ihrer beiden Richtungen geschrieben werden (`GAMEPAD_0.AXIS_LEFT_X`, `AXIS_LEFT_X_L` und `AXIS_LEFT_X_R` bezeichnen alle dieselbe Achse). Alles, was nicht aufgeführt ist, behält `DEAD_ZONE`. `TRIGGER_THRESHOLD` gibt an, wie weit ein analoger Trigger durchgedrückt werden muss, bevor er als Knopf zählt, als *Prozent des vollen Wegs*; das ist die Einheit, die Hypseus’ `-trigger-threshold` benutzt und deren Standardwert dort `99.5` ist. Sie gilt für beide Trigger aller vier Pads. Singes Standardwert ist `0`, was bedeutet, dass die Trigger bei `DEAD_ZONE` bleiben, sodass sich für niemanden etwas ändert, der nicht danach fragt; ein Skript liest das Ergebnis in Rohwerten als `SINGE_TRIGGER_THRESHOLD`. Die beiden Einheiten lassen sich direkt umrechnen: Ein Prozent sind `32767 / 100` Rohwerte, also sind Singes `DEAD_ZONE` von `15000` gleich `45.8` Prozent, und Hypseus’ `99.5` Prozent sind `32603` Rohwerte. `--trigger_threshold` setzt dieselbe Zahl von der Befehlszeile aus und gewinnt gegen `controls.cfg`; `DEAD_ZONES` gewinnt gegen beide, da es am genauesten ist. [[joymouse]] === Die Maus mit einem Stick steuern Ein Lightgun-Spiel auf einem Automaten mit Stick und ohne Maus ist unspielbar, solange der Stick den Cursor nicht bewegen kann. `--joymouse` sorgt dafür: Der **linke Stick von Gamepad-Slot 0** bewegt den Zeiger, den das Spiel sieht, über dasselbe `onMouseMoved`, das eine echte Maus erreicht, und der Cursor wird innerhalb des Bildes gehalten. `--js_range` ist die Geschwindigkeit, `1` bis `20` mit `5` als Standard, gemessen in Videopixeln pro Frame bei vollem Ausschlag, sodass `5` ein 720 Pixel breites Bild in etwa zwei Sekunden durchquert. Die Achse beachtet ihre eigene Totzone, sodass ein driftender Stick nicht kriecht. Es ist standardmäßig aus, und darin unterscheidet sich Singe von Hypseus: Die mitgelieferte `controls.cfg` bindet diesen Stick bereits an `INPUT_UP`, `INPUT_DOWN`, `INPUT_LEFT` und `INPUT_RIGHT`, und wenn er ungefragt auch noch den Cursor steuern würde, wäre jedes bestehende Spiel überrascht. `--joymouse=false` entspricht Hypseus’ `-nojoymouse`, und ein Skript schaltet es mit `joyMouseEnable` ein und aus und liest es mit `joyMouseIsEnabled`. Ein Neuladen setzt es auf den Stand zurück, den die Befehlszeile vorgegeben hat. [[mousedevices]] === Mäuse, Lightguns und wer entscheidet `mouseSetMode(MOUSE_MANY)` ist die Entscheidung eines Spiels, bis zu vier Mäuse auseinanderzuhalten, was ein Automat mit zwei Lightguns braucht und was einem Spiel, das den Aufruf nie macht, nicht gegeben werden kann. `--manymouse` ist die Entscheidung des Benutzers und hat Vorrang: Der Modus ist von Anfang an eingeschaltet, und `mouseSetMode(MOUSE_SINGLE)` schaltet ihn nicht mehr ab. `--absolutes_only` behält nur die Geräte, die eine absolute Position melden, was eine echte Lightgun tut und eine gewöhnliche Maus nicht, sodass ein Automat mit zwei Lightguns und einer angeschlossenen Schreibtischmaus nicht von der Maus verwirrt wird. Achte darauf, wie es entscheidet: **ManyMouse, das Backend, mit dem Singe Mäuse auseinanderhält, bietet keine Möglichkeit, ein Gerät zu fragen, was für eines es ist**, also zählt ein Gerät als absolut, sobald es eine absolute Position gemeldet hat, und nicht vorher. Eine Lightgun tut das bei ihrer ersten Bewegung; bis dahin ist sie stumm, und ein rein relatives Gerät bleibt für immer stumm. Die Option ist daher ein Filter nach beobachtetem Verhalten statt nach Geräteklasse, und auf einem Rechner, auf dem kein Gerät je eine absolute Position meldet, bringt sie jede Maus zum Schweigen. `SWITCH_MOUSE_DISCONNECT` ist ein Schalter wie jeder andere, nur dass keine Taste und kein Knopf ihn auslöst: Die Engine löst ihn aus, wenn eine Maus oder eine Lightgun abgesteckt wird, einmal als Drücken und einmal als Loslassen, sodass ein Lightgun-Spiel das auf dem Bildschirm sagen kann, statt scheinbar abgestürzt zu sein. Es ist der gleichnamige Schalter von Hypseus. `controls.cfg` lässt ihn unbelegt; belege zusätzlich eine Taste damit, wenn du sehen willst, was ein Spiel tut, ohne ein Kabel zu ziehen. [[hotkeys]] === Tastenkürzel `Alt-Enter` schaltet zwischen Vollbild und Fenster um, während das Spiel läuft, wie in Hypseus. Das Spiel sieht die Taste nie. Ein Fenster, das im exklusiven Vollbild gestartet ist (`--fullscreen`), kehrt in dem Anzeigemodus dorthin zurück, den es bekommen hatte; eines, das im Fenster gestartet ist, bekommt ein randloses Fenster, das den Desktop bedeckt. Nichts anderes muss sich mitändern: Der Renderer präsentiert eine logische Größe in Videokoordinaten und skaliert sie auf das, was das Fenster gerade ist, das Videorechteck wird in denselben Koordinaten gebaut, und das Rotationsziel hat die Größe des Bildes statt des Fensters, sodass Bild, Overlay, GUIs und Mauszuordnung alle von selbst folgen. Die anderen Schalter, die ein Benutzer drücken kann -- Beenden, Pause, Screenshot, Aufnahme, die Konsole und das Umschalten des Mausfangs -- sind gewöhnliche Belegungen in `controls.cfg` und werden mit den `INPUT_*`-Namen in der Beispieldatei beschrieben. [[recording]] === Video aufnehmen `F10` startet die Aufnahme des Spiels, Bild und Ton zusammen, und erneut `F10` stoppt sie. Jede Aufnahme ist eine neue `singeNNN.mp4` im Datenordner des Spiels, neben den Screenshots, und spielt in allem, was MP4 abspielt. Das Bild ist das ganze Fenster, so wie du es siehst, Letterbox inklusive, und der Ton ist alles, was das Spiel abspielt: Musik, Soundeffekte und der eigene Soundtrack des Videos. Wo der Rechner einen Hardware-Videoencoder hat, benutzt Singe ihn, sodass die Aufnahme das Spiel sehr wenig kostet: H.264 über VA-API unter Linux, VideoToolbox unter macOS, Media Foundation unter Windows und V4L2 auf den ARM-Boards, die einen haben. Überall sonst nimmt es stattdessen MPEG-4 auf, das überall abspielt, aber größere Dateien erzeugt. Die Zeile `Recording` im Trace sagt, was benutzt wurde. Ein Rechner, der zu langsam ist, um mitzuhalten, lässt Frames in der Aufnahme aus, statt das Spiel zu verlangsamen, und der Trace sagt, wie viele, wenn die Aufnahme endet. Um stattdessen einen ganzen Lauf aufzunehmen, starte Singe mit `--record=FILENAME`. Füge `--deterministic` hinzu, und Singe nimmt jeden Frame und den exakt dazugehörigen Ton auf, egal wie lange jeder Frame zur Erstellung braucht, ohne etwas über die Lautsprecher abzuspielen. So machst du ein perfektes Video einer Demo oder eines Attract-Modus: Auf einem Desktop läuft es meist schneller als in Echtzeit. [#_settings_and_options] == Einstellungen und Optionen Fast alles, was du auf die Befehlszeile schreiben kannst, kann auch in eine Einstellungsdatei. Richte es einmal ein, und jedes Spiel benutzt es. [[settings]] === Die Einstellungsdatei Fast alles auf der Befehlszeile lässt sich auch einmal aufschreiben, in einer Datei `settings.cfg`, sodass ein Automat kein Launcher-Skript braucht, das für jedes Spiel dasselbe Dutzend Optionen mitschleppt. Sie ist Lua, wie `controls.cfg`, und Singe sucht sie an genau denselben vier Orten, in dieser Reihenfolge: . `settings.cfg` aus dem Hauptskriptverzeichnis des Spiels. . `settings.cfg` aus dem Verzeichnis, in dem Singe gestartet wurde (das Verzeichnis `Singe` enthält eine Vorlage `settings.cfg.example`, die du kopieren kannst). . `settings.cfg` aus dem Verzeichnis über dem Datenordner des Spiels. . `settings.cfg` aus dem Datenordner des Spiels. Jeder Ort wird einmal gelesen, und eine spätere Datei gewinnt Schlüssel für Schlüssel, sodass eine rechnerweite Datei die Anzeige und die Lautstärken festlegen kann, während eine Datei im Datenordner eines Spiels das Fadenkreuz dieses Spiels abschaltet. Du musst nicht jeden Schlüssel in eine Datei schreiben; schreib die, die du ändern willst. Jeder Schlüssel ist der lange Name einer Befehlszeilenoption ohne die führenden Striche, es gibt also kein zweites Vokabular zu lernen: [source,lua] ---- -- Die eigene settings.cfg des Automaten screen = 2 -- der zweite Monitor fullscreen = true volume_vldp = 80 haptic = 0 -- dieser Automat hat keine Vibration idleexit = 900 -- den Bildschirm nach fünfzehn stillen Minuten zurückgeben startsilent = true ---- Eine Option, die auf der Befehlszeile keinen Wert nimmt, nimmt hier `true` oder `false` (`yes`, `no`, `on`, `off`, `1` und `0` werden auch akzeptiert). Eine davon auf `false` zu setzen ist dasselbe, wie sie wegzulassen. Eine Option, die einen Wert nimmt, nimmt denselben Wert wie auf der Befehlszeile, als Zahl oder als String. Eine Option, `--deterministic`, nimmt einen Wert oder kommt ohne aus, und ihr Schlüssel macht es genauso: `deterministic = true` benutzt den Standardschritt, `deterministic = 20` nennt einen, und `deterministic = false` lässt die Option aus. [[configorder]] === Woher Konfigurationsdateien gelesen werden `controls.cfg`, `settings.cfg` und `gamecontrollerdb.txt` werden alle an denselben vier Orten gesucht, in derselben Reihenfolge, und eine später gelesene Datei gewinnt gegen eine früher gelesene: . *Das Hauptskriptverzeichnis des Spiels,* das bei einem gepackten Spiel in seiner `.game`-Datei liegt. Das ist es, was der Autor des Spiels mitgeliefert hat, also wird es zuerst gelesen: Es legt die Standardwerte des Spiels fest und sonst nichts. . *Das Verzeichnis, in dem Singe gestartet wurde.* Die eigenen Dateien des Rechners, etwa die Tastenanordnung eines Handhelds, kommen hierhin, und sie gewinnen gegen das, was ein Spiel mitbringt. Eine Datei ersetzt nur, was sie nennt; um also die Bindung eines Spiels von einem Knopf zu nehmen, nenne diese Eingabe: `INPUT_TEST_MODE = { SCANCODE.F2 }` in der `controls.cfg` des Rechners lässt den Testmodus nur auf der Tastatur, egal auf welchen Knopf ein Spiel ihn gelegt hat. . *Das Verzeichnis über dem Datenordner des Spiels,* für Dateien, die alle Spiele teilen, die diesen Datenordner benutzen. . *Der Datenordner des Spiels.* Deine eigenen Dateien für ein Spiel, die gegen alles andere gewinnen. Mit `--datadir=.` ist der Datenordner der Spielordner selbst; dann wird die Datei dort einmal gelesen, als die des Spiels. `--keymapfile` ersetzt die ganze Suche nach `controls.cfg` durch eine benannte Datei. [#_what_wins] === Was gewinnt . Der eingebaute Standardwert. . Die Einstellungsdatei. . Der Eintrag des Spiels in `games.dat`, für die Handvoll Einstellungen, die er trägt (siehe xref:Reference.adoc#gamesdat[games.dat]). . `machine.cfg`, für die Audioverzögerung und die Bildgeometrie, die die Service-Tools speichern (siehe <>). . Die Befehlszeile, die immer gewinnt. Eine Einstellungsdatei ist also eine Sammlung von Standardwerten, nicht etwas, das du eingetippt hast: Wenn ein Eintrag in `games.dat` einem Spiel eine Auflösung oder einen Sinden-Rahmen gibt, beschreibt dieser Eintrag das Spiel immer noch besser als eine rechnerweite Datei. Alles, was tatsächlich auf der Befehlszeile eingetippt wurde, schlägt beides. `machine.cfg` sitzt direkt unter der Befehlszeile, weil jemand das Bild eingestellt hat, während er auf genau diesen Monitor schaute, und das ist ein besserer Beleg als jede woanders geschriebene Datei; die Audioverzögerung ist die Ausnahme von dieser Ordnung schlechthin, denn sie wird zur Verzögerung des Spiels addiert, statt sie zu ersetzen. Optionen, die das Spiel nennen (`--framefile`, `--disc`, `--entry`), ein Verzeichnis nennen (`--gamedir`, `--datadir`) oder wirken müssen, bevor die Datei gefunden werden konnte (`--help`, `--apiversion`, `--noconsole`, `--pack`, `--patch`, `--unpack`) oder nur für einen einzigen Lauf gelten (`--record`, `--refresh`), können nicht in einer Einstellungsdatei gesetzt werden. Ein Schlüssel, der keine Option ist, eine dieser Optionen oder ein Wert, den die Option nicht annimmt, ist ein Fehler, der die Datei und den Schlüssel nennt, sodass ein Tippfehler nie still ignoriert wird: ---- settings.cfg: volume_vldpp is not an option. settings.cfg: datadir cannot be set here; it belongs on the command line. settings.cfg: Display scale must be between 25 and 100 percent. ---- Mit `--program` oder `--trace` listet der Kopf am Anfang von `trace.txt` jede angewendete Einstellung auf, sodass nie die Frage bleibt, welche Datei ein laufendes Spiel bekommen hat. [[commandlineoptions]] === Befehlszeilenoptionen ---- Singe [OPTIONS] gameName ---- Der Spielname ist das einzige Pflichtargument. Er kann ein `.singe`-Skript sein, ein Verzeichnis, das ein Skript gleichen Namens enthält (`MyGame` findet `MyGame/MyGame.singe`), oder ein gepacktes Spiel (`MyGame.game` startet den ersten Eintrag der `games.dat` darin, `--entry=N` einen anderen). Ein auf diese Weise gestartetes Skript oder Verzeichnis läuft auch mit seinem Eintrag in `games.dat`, wenn einer es nennt (siehe xref:Reference.adoc#gamesdat[games.dat]), sodass ein Spiel von der Befehlszeile aus genauso spielt wie aus dem Menü. Für ein Laserdisc-Spiel (`--disc`) ohne `--framefile` sucht Singe neben dem Skript nach einem Video mit demselben Basisnamen und einer beliebigen Endung, die FFmpeg demuxen kann, und danach nach einer `.txt`-Frame-Datei. Die Optionen sind danach gruppiert, was sie tun. [#_the_game_and_its_files] ==== Das Spiel und seine Dateien Welches Spiel läuft, wo es und seine Daten liegen und worauf es gespielt wird. [cols="1,2",options="header"] |=== | Option | Zweck | `-C`, `--canvas=WxH` | Weltgröße für ein Spiel ohne Disc, Standard 720x480. Wird ignoriert, wenn es eine Disc gibt. | `-d`, `--datadir=PATHNAME` | Verzeichnis für alles, was Singe schreibt: Videoindizes, `trace.txt`, Screenshots, Spielstände, die `menu.dat` des Menüs. Darin wird ein Unterverzeichnis angelegt, das nach dem Spielordner benannt ist (bei einem gepackten Spiel eines nach der Datenbank und darin eines nach dem Verzeichnis des Skripts). Standard ist `data` im Spieleverzeichnis. Singe 2.x schrieb stattdessen neben das Spiel; Spieleverzeichnisse können schreibgeschützt sein, also wird dort nichts mehr geschrieben. | `-D`, `--disc` | Ein Laserdisc-Video abspielen: das von `--framefile` genannte oder das neben dem Skript gefundene. Wird von `--framefile` impliziert. Ohne diese Option wird ein Video neben dem Skript gemeldet und ignoriert. | `-E`, `--entry=N` | Den N-ten Eintrag der `games.dat` in einer `.game`-Datei starten (Standard 1). Siehe xref:Reference.adoc#singlefile[Spiele in einer Datei]. | `-v`, `--framefile=FILENAME` | Videodatei oder Frame-Datei, die statt der neben dem Skript gefundenen benutzt wird. | `-G`, `--gamedir=PATHNAME` | Das Verzeichnis mit den Spielen, den gepackten `.game`-Dateien und dem Hilfsordner `Singe`, wenn die ausführbare Datei woanders liegt. Es wird zum Arbeitsverzeichnis, sodass der Spielname, ein relatives `--datadir` und die Namen des Packers alle von dort aus zählen; absolute Pfade funktionieren, wie sie sind. Standard ist das aktuelle Verzeichnis. | `-c`, `--showcalculated` | Die Frame-Bereiche jedes Segments einer Frame-Datei ausgeben, zur Fehlersuche. |=== [#_display] ==== Anzeige Das Fenster und wie das Bild es ausfüllt. [cols="1,2",options="header"] |=== | Option | Zweck | `-a`, `--aspect=N:D` | Das Seitenverhältnis erzwingen, nach dem eine Fenstergröße gewählt wird (`4:3`, `16:9`, `16:10`). | `-f`, `--fullscreen` | Exklusives Vollbild in der Desktop-Auflösung. | `-w`, `--fullscreen_window` | Randloses Fenster, das den Desktop bedeckt. | `--linearscale=BOOLEAN` | Das Overlay glätten, wenn das Fenster es skaliert (`true`), oder den nächstgelegenen Pixel nehmen (`false`, was Pixelgrafik scharf hält). Nimmt `true`, `false`, `yes`, `no`, `on`, `off`, `1` oder `0`. Ein Skript ändert es zur Laufzeit mit `setOverlayLinearScale`. Standard: `true`, so hat es jede Singe-Version gezeichnet; der eigene Standard von Hypseus ist das Gegenteil. | `-k`, `--nologos` | Die Startbildschirme überspringen. | `-r`, `--rotate=DEGREES` | Die ganze Darstellung im Uhrzeigersinn um `0`, `90`, `180` oder `270` Grad drehen, für einen Automaten, dessen Bildschirm seitlich eingebaut ist. Video, Overlay, GUIs, 3D-Szene und Partikel drehen sich alle zusammen, eine Vierteldrehung vertauscht die Form des Bildes, sodass ein Hochformatfenster ausgefüllt wird, und Maus- und Lightgun-Positionen werden zurückgedreht, sodass ein Klick immer noch dort landet, wo er gezeichnet wird. Nur die vier rechten Winkel werden akzeptiert. Ein Skript kann es mit `vldpSetRotate` ändern. | `--screen=N` | Das Fenster auf Bildschirm `N` öffnen, gezählt ab `1`, wie Hypseus sie zählt. Eine Zahl, die größer ist als die Zahl der Bildschirme, listet die vorhandenen Bildschirme auf und beendet. Standard: der primäre Bildschirm. | `-u`, `--stretch` | Das Video so strecken, dass es das Fenster füllt, statt sein Seitenverhältnis zu behalten. | `-x`, `--xresolution=VALUE` | Fensterbreite. Die Höhe wird, wenn sie fehlt, aus dem passenden Eintrag der eingebauten Auflösungstabelle genommen. Eine Größe, die größer ist als der Bildschirm (hier verlangt oder von der `games.dat` eines Spiels), wird passend verkleinert, ihre Form bleibt erhalten, und der Trace sagt das. Headless ausgeführt, mit `SDL_VIDEODRIVER=offscreen`, gibt es keinen Bildschirm, an den angepasst werden müsste, und das Fenster behält die verlangte Größe. | `-y`, `--yresolution=VALUE` | Fensterhöhe. |=== [#_picture_placement_bezels_and_guns] ==== Bildposition, Bezels und Lightguns Für einen Automaten: wo das Bild sitzt, die Grafik drumherum und der Rahmen, den eine Sinden-Lightgun verfolgt. Siehe <>. [cols="1,2",options="header"] |=== | Option | Zweck | `-B`, `--bezel=FILENAME` | Automatengrafik um das Bild zeichnen. Die Datei wird im Ordner `bezels` des Spieleverzeichnisses gesucht (ein gepacktes Spiel kann seine eigene mitbringen) und dann im Ordner `bezels` des Datenordners; `--bezeldir` nennt einen anderen Ordner. Jedes Format, das SDL_image liest, geht, und Transparenz bleibt erhalten. Eine Begleitdatei daneben sagt, wo in der Grafik das Bild liegt; ohne eine behält das Bild das ganze Fenster, und `--shiftx`, `--shifty` und `--scalefactor` platzieren es. Eine Grafik, die nicht gefunden wird, beendet das Programm. Siehe <>. | `-I`, `--bezeldir=PATHNAME` | Der Ordner mit der Grafik für `--bezel`, anstelle von `bezels`. Relativ zum Spieleverzeichnis oder absolut. Nur dieser Ordner wird durchsucht. Siehe <>. | `-F`, `--bezelflip` | Die Bezel-Grafik vor das Bild zeichnen statt dahinter, wie Hypseus es mit seinen eigenen Bezels macht; die Transparenz der Grafik ist dann das Loch, durch das das Spiel zu sehen ist. Ohne diese Option liegt die Grafik hinter allem, und das Bild bedeckt ihren Ausschnitt. Ein Skript wählt mit `setOverlayOnTop`, ob das Overlay und die GUIs über der Grafik bleiben. Siehe <>. | `-b`, `--scalefactor=PERCENT` | Das Bild um seine Mitte auf `PERCENT` (`25` bis `100`) des Fensters verkleinern, für Bildschirme, die ihre Ränder durch Overscan verlieren. Maus- und Lightgun-Positionen folgen dem verkleinerten Bild. Ein Skript kann es während des Spiels mit `vldpSetScale` ändern. Lässt sich mit `--shiftx`, `--shifty`, `--rotate` und `--sindengun` kombinieren; siehe <>. | `-X`, `--shiftx=PERCENT` | Das Bild waagerecht innerhalb des Platzes verschieben, den `--scalefactor` übrig gelassen hat, von `-100` (ganz an den linken Rand) bis `100` (ganz an den rechten Rand), `0` zentriert. Wie in Hypseus ist die Verschiebung ein Prozentsatz dieses Platzes und nichts weiter, also gibt es bei `--scalefactor=100` keinen Platz, und die Verschiebung bewirkt nichts: Verkleinere zuerst die Skalierung. Siehe <>. | `-Y`, `--shifty=PERCENT` | Das Bild senkrecht innerhalb des Platzes verschieben, den `--scalefactor` übrig gelassen hat, von `-100` (ganz an den oberen Rand) bis `100` (ganz an den unteren Rand), `0` zentriert. Bei voller Skalierung bewirkt es aus demselben Grund nichts. Siehe <>. | `-S`, `--sindenedge=WHERE` | Wo der Sinden-Rahmen sitzt: `video` zeichnet ihn um das Bild, `window` am Rand des Bildschirms. Ohne die Option entscheidet ein Bezel: Grafik um das Bild legt den Rahmen an den Fensterrand, weil die Kamera der Lightgun den ganzen Bildschirm sieht, und ohne Grafik liegt er um das Bild, wie er es immer getan hat. Am Fensterrand werden die beiden Ringe als Ringe gezeichnet, ganz zuletzt, sodass die Grafik zwischen ihnen und dem Bild sichtbar bleibt. Siehe <>. | `-g`, `--sindengun='PARAMS'` | Den Rahmen zeichnen, den eine Sinden-Lightgun verfolgt, und Maus- und Lightgun-Positionen auf das Bild darin abbilden: Der schwarze Ring läuft, wenn einer angegeben ist, am Rand des Videos entlang, der weiße Ring sitzt darin, und das Spiel wird in der Mitte gezeichnet. `PARAMS` ist eine Liste von Zahlen in Anführungszeichen: `WW` (Breite des weißen Rahmens in Videopixeln); `WW WB` (weiße Breite, dann ein schwarzer Rahmen außen herum); `RW GW BW WW` (eine eigene Rahmenfarbe und -breite); `RW GW BW WW WB` (dasselbe plus eine schwarze Breite); oder `RW GW BW WW RB GB BB WB` (eigene Farben und Breiten für beide). Ein Rahmen, der dem Spiel keinen Platz lässt (zweimal die weiße und die schwarze Breite zusammen erreichen die kürzere Seite des Videos), oder eine negative Breite beendet das Programm mit einer Meldung. Die Ringe werden um das gezeichnet, was `--shiftx`, `--shifty` und `--scalefactor` übrig gelassen haben, sodass ein Rahmen ein Rahmen bleibt, wie auch immer das Bild platziert ist; siehe <>. |=== [#_sound] ==== Sound [cols="1,2",options="header"] |=== | Option | Zweck | `--altaudio=SUFFIX` | `.ogg` neben dem Video der Disc statt des darin enthaltenen Tons abspielen, für eine Veröffentlichung, deren andere Sprachen als separate Dateien geliefert werden: `--altaudio=-es` neben `game.m2v` spielt `game-es.ogg`. Alle Segmente einer Frame-Datei werden zusammen umgeschaltet. Eine Datei, die nicht da ist, lässt den eigenen Ton des Spiels weiterlaufen und gibt eine Warnung aus. Der Schlüssel `AUDIO_SUFFIX` in `games.dat` tut dasselbe für ein Spiel, und ein Skript ändert es zur Laufzeit mit `discAudioSuffix`. Standard: keiner. | `-o`, `--audio=TRACK` | Standard-Tonspur (ab null gezählt) für Videos mit mehreren, etwa mehrsprachige Veröffentlichungen. | `-A`, `--audiodelay=MS` | Ton ausgleichen, der `MS` Millisekunden später zu hören ist, als die Engine messen kann (negativ, wenn er zu früh zu hören ist), `-1000` bis `1000`. Siehe xref:Reference.adoc#audiosync[Audio-Synchronisation]. | `-s`, `--nosound` | Allen Ton stummschalten. | `--soundfont=FILE` | Der SoundFont (`.sf2`), mit dem MIDI-Dateien synthetisiert werden. Singe liefert keinen mit, denn ein guter ist Dutzende Megabyte groß, für ein Format, das fast kein Spiel benutzt. Ohne diese Option sucht es nach `Singe/soundfont.sf2` -- sodass ein gepacktes Spiel seinen eigenen mitbringen kann -- und dann an den Orten, an denen eine Distribution einen installiert. Die Zeile `SoundFont:` im Trace-Kopf sagt, welcher benutzt wurde oder dass keiner gefunden wurde. Siehe xref:Reference.adoc#midi[MIDI]. Standard: die Suche. | `--startsilent` | Stumm starten und stumm bleiben bis zur ersten Eingabe irgendeiner Art, dann mit den eingestellten Lautstärken spielen. Für einen Attract-Automaten in einem ruhigen Raum. `--nosound` hat Vorrang. Standard: aus. | `-e`, `--volume_nonvldp=PERCENT` | Lautstärke von Soundeffekten und zusätzlichem Video, `0` bis `100`. | `-l`, `--volume_vldp=PERCENT` | Laserdisc-Lautstärke, `0` bis `100`. |=== [#_input] ==== Eingabe Siehe <>. [cols="1,2",options="header"] |=== | Option | Zweck | `--absolutes_only` | Nur die Mäuse behalten, die eine absolute Position melden, was eine echte Lightgun tut und eine gewöhnliche Maus nicht. ManyMouse kann nicht gefragt werden, was ein Gerät ist, also zählt ein Gerät als absolut, sobald es eine absolute Position gemeldet hat, und nicht vorher; siehe <>. Hypseus schreibt es `-absolutes-only`; der Name hier benutzt einen Unterstrich, weil ein Schlüssel einer Einstellungsdatei ein Lua-Name sein muss. Standard: aus. | `--gamepad_reorder=DIGITS` | Welches physische Pad welchen Gamepad-Slot füllt, als Aufzählungspositionen ab `0`, eine für jeden Slot der Reihe nach: `--gamepad_reorder=10` macht das zweite gefundene Pad zu Spieler eins und das erste zu Spieler zwei. Als bloße Ziffern geschrieben (`3210`) oder durch Kommas oder Leerzeichen getrennt, wie Hypseus es schreibt; eine wiederholte Position wird abgelehnt. Nicht genannte Positionen füllen die übrigen Slots in der Reihenfolge, in der SDL sie gefunden hat, und eine Position ohne Pad dahinter lässt ihren Slot leer. Standard: SDLs eigene Reihenfolge. | `--haptic=STEP` | Die stärkste Vibrationsstufe, die ein Spiel benutzen darf, `0` bis `4`. `0` schaltet Vibration ganz ab, und eine niedrigere Zahl dämpft ein Spiel, das mehr verlangt: `controllerDoRumble` vibriert nie stärker als dies. Standard: `4`, also jede Stufe, die ein Spiel verlangt. | `--joymouse=BOOLEAN` | Den linken Stick von Gamepad-Slot `0` den Mauszeiger steuern lassen, für ein Lightgun-Spiel auf einem Automaten ohne Maus. `--joymouse=false` entspricht Hypseus’ `-nojoymouse`, und ein Skript setzt es mit `joyMouseEnable()`. Siehe <>. Standard: `false`, wo der Standard von Hypseus an ist -- die mitgelieferte `controls.cfg` bindet diesen Stick bereits an die vier Richtungen. | `--js_range=SPEED` | Wie schnell dieser Stick ihn steuert, `1` bis `20`, in Videopixeln pro Frame bei vollem Ausschlag. Standard: `5`, wie in Hypseus. | `--keymapfile=FILENAME` | Die Steuerungsbelegungen aus dieser Datei lesen, statt an den vier Orten nach `controls.cfg` zu suchen, sodass ein Frontend sicher sein kann, welche Belegungen ein Spiel bekommen hat. Die eingebauten Standardwerte gelten darunter weiterhin, sodass eine unvollständige Datei trotzdem funktioniert, und eine Datei, die nicht da ist, beendet das Programm. Standard: die Suche an vier Orten, beschrieben unter <>. | `--manymouse` | Bis zu vier Mäuse auseinanderhalten, egal was das Spiel verlangt, was ein Automat mit zwei Lightguns von einem Spiel braucht, das `mouseSetMode(MOUSE_MANY)` nie selbst aufruft. Die Wahl des Benutzers hat Vorrang vor der des Spiels: `mouseSetMode(MOUSE_SINGLE)` schaltet es nicht mehr ab. Standard: aus, und das Spiel entscheidet. | `--mapjoysticks=BOOLEAN` | Eine Gamepad-Belegung für ein Gerät schreiben, das SDL nicht erkennt, sodass ein Arcade-Encoder, ein Spinner, ein Lenkrad oder ein Flugsteuerknüppel wie alles andere als `GAMEPAD_0` bis `GAMEPAD_3` geöffnet wird. `false` lässt ein solches Gerät ungeöffnet, wie es frühere Versionen taten. Siehe <>. Standard: `true`. | `-n`, `--nocrosshair` | Das Spiel bitten, kein eigenes Fadenkreuz zu zeichnen. Für Skripte als `singeWantsCrosshairs()` verfügbar. | `--nogamepad` | Alle Gamepads ignorieren, das Gegenstück zu `--nomouse`. Keines wird geöffnet, und kein Pad-Ereignis erreicht das Spiel, sodass ein klemmender Arcade-Encoder nichts drücken kann. Standard: aus. | `-m`, `--nomouse` | Maus- und Lightgun-Eingabe vollständig abschalten. | `--quitchord=BUTTONS` | Knöpfe am ersten Gamepad, die zusammen gehalten beenden, egal was das Spiel belegt und selbst wenn es seine Beenden-Taste abgeschaltet hat: der Ausweg auf einem Handheld ohne Tastatur. Ein Spiel beendet zurück ins Menü, aus dem es gestartet wurde, und das Menü beendet Singe. Zwei bis vier von SDLs Gamepad-Knopfnamen, verbunden mit `+`, etwa `back+start` (Select und Start); die Namen sind `a`, `b`, `x`, `y`, `back`, `guide`, `start`, `leftstick`, `rightstick`, `leftshoulder`, `rightshoulder`, `dpup`, `dpdown`, `dpleft` und `dpright`, wie die Belegung des Pads sie vergibt, und `--program` schreibt den Namen jedes gedrückten Knopfs in den Trace. Ein Druck auf einen der Knöpfe der Kombination wartet eine Viertelsekunde auf die übrigen, bevor er tut, was er normalerweise tut, sodass Start auf dem Weg zum Beenden kein Spiel aus dem Menü startet. Gehört in die `settings.cfg` des Rechners. Standard: keiner. | `--trigger_threshold=PERCENT` | Wie weit ein analoger Trigger durchgedrückt werden muss, bevor er als Knopf zählt, als Prozent des vollen Wegs -- die Einheit von Hypseus, dessen eigener Standard `99.5` ist. `0` lässt die Trigger bei `DEAD_ZONE`, was Singe ihnen immer gegeben hat. Gewinnt gegen `TRIGGER_THRESHOLD` in `controls.cfg`; `DEAD_ZONES` gewinnt gegen beide. `0` bis `100`; siehe <>. Standard: `0`. | `--xratio=FACTOR` | Der waagerechte Skalierungsfaktor, den ein Lightgun-Spiel mit `ratioGetX()` liest, um seine eigenen Lightgun-Koordinaten für einen Bildschirm zu strecken, dessen Form nicht zum Video passt. Singe tut nichts damit; das Spiel rechnet selbst, genau wie in Hypseus. `0` bis `100`, auf zwei Nachkommastellen gehalten, wie Hypseus es hält. Standard: `0`, was jedes Spiel, das es liest, als `1` behandelt. | `--yratio=FACTOR` | Dasselbe für `ratioGetY()`. Standard: `0`. |=== [#_video_decoding_and_performance] ==== Videodekodierung und Leistung Vor allem für kleine Rechner; siehe <>. [cols="1,2",options="header"] |=== | Option | Zweck | `--deinterlace=MODE` | Was ein Bild im Zeilensprungverfahren bekommt: `auto` (der Standard) deinterlacet nur die Frames, die die Datei als interlaced markiert, `on` deinterlacet jeden Frame, für eine Datei mit falschen Flags, und `off` rührt das Bild nie an. Eine Laserdisc enthielt Halbbilder im Zeilensprungverfahren, und ein Rip, der sie behalten hat, zeigt auf einem progressiven Bildschirm Kammartefakte; ein Rip, der schon beim Erstellen deinterlacet wurde, braucht hier nichts. Für jedes Bild, das hineingeht, kommt eines heraus, also verschieben sich Frame-Nummern nie. Standard: `auto`. | `--monochrome` | Mit dem Disc-Bild in Grau starten. Overlay, GUIs und 3D-Szene behalten ihre Farbe; ein Skript macht dasselbe mit `vldpSetMonochrome` und macht es wieder rückgängig. Standard: aus. | `--scenequality=LEVEL` | Wie viel die 3D-Szene zeichnet: `high`, alles, was ein Spiel verlangt, oder `low` für eine kleine GPU -- einen Handheld oder einen frühen Raspberry Pi -- mit der Szene in halber Auflösung in jeder Richtung und ohne Antialiasing und Bloom, egal was das Spiel verlangt. Das 3D-Bild ist weicher, helle Dinge leuchten nicht, und es läuft viel schneller, wo die GPU die Grenze war; Disc, Overlay und GUIs bleiben unberührt. Gehört in die `settings.cfg` des Rechners statt auf die Befehlszeile eines Spiels, da es den Rechner beschreibt. Standard: `high`. | `-H`, `--softwarevideo` | Video in Software dekodieren, selbst wenn die Plattform einen Hardware-Decoder bietet (VA-API oder VDPAU unter Linux, den V4L2-Decoder auf dem Pi, D3D11VA unter Windows, VideoToolbox unter macOS). Damit lässt sich der Hardware-Pfad als Ursache bestätigen oder ausschließen, wenn ein Video sich danebenbenimmt; der Programm-Trace sagt, welcher Decoder benutzt wird. | `--zerocopy=BOOLEAN` | Hardware-dekodierte Video-Frames direkt an die GPU übergeben, statt sie über die CPU zu kopieren: Rockchips MPP-Decoder und VA-API unter Linux, gezeichnet mit OpenGL ES. Das spart auf einem kleinen Rechner den größten Teil der Kosten von Vollbildvideo. Singe fällt von selbst aufs Kopieren zurück, wenn der Treiber einen Frame nicht annimmt oder wenn ein Spiel die Pixel des Bildes liest oder ändert, und der Programm-Trace sagt, was es gerade tut; `false` lässt es von Anfang an kopieren, um diesen Pfad als Ursache zu bestätigen oder auszuschließen. Standard: `true`. |=== [#_cabinets_and_front_ends] ==== Automaten und Frontends [cols="1,2",options="header"] |=== | Option | Zweck | `--apiversion` | Eine maschinenlesbare Zeile, die diesen Build beschreibt, auf die Standardausgabe schreiben und beenden, für Frontends. Siehe <>. Sonst wird nichts ausgegeben. | `--fvalue=NUMBER` | Eine Zahl, die der Launcher an das Spiel übergibt, das sie mit `getFValue()` liest. Singe tut nichts damit. `0` bis `100000`, auf drei Nachkommastellen gehalten, wie Hypseus es hält. Standard: `0`. | `-h`, `--help` | Die Übersicht der Optionen zeigen und beenden. | `--idleexit=SECONDS` | Nach `SECONDS` ohne jede Eingabe beenden -- keine Taste, kein Knopf, keine Pad-Achse, keine Maus. Für einen Attract-Automaten, der den Bildschirm zurückgeben soll. `0` beendet nie. `0` bis `86400`. Standard: `0`. | `--no_update_check` | Den Dienst nie fragen, ob es ein neueres Singe gibt. Sonst schaut das Menü einmal am Tag nach und zeigt, was es gefunden hat, unter den Details des Spiels; das Tool Engine Update funktioniert weiterhin von Hand. Standard: aus, die tägliche Prüfung findet also statt. | `-z`, `--noconsole` | Nichts ausgeben (und unter Windows kein Konsolenfenster öffnen). | `--refresh` | Den Hilfsordner `Singe` als `old-Singe-` beiseitelegen, benannt nach der Version, die ihn geschrieben hat, und einen frischen schreiben. Zum Aktualisieren: Eine Datei, die eine ältere Version mitbrachte und diese nicht, bleibt im beiseitegelegten Ordner, statt im aktiven zu liegen. Nichts wird gelöscht, und ein zweiter Lauf legt seinen eigenen als `old-Singe--1` beiseite. Das Tool Engine Update übergibt dies dem Singe, in das es neu startet. |=== [#_making_and_testing_games] ==== Spiele erstellen und testen Siehe <> für die Traces. [cols="1,2",options="header"] |=== | Option | Zweck | `--debug[=HOST:PORT]` | Das Spiel mit einem Debugger verbinden, der auf `HOST:PORT` lauscht, normalerweise ZeroBrane Studio, der es dann an Haltepunkten anhalten, Schritt für Schritt ausführen und zeigen kann, was in seinen Variablen steht; siehe xref:Reference.adoc#zerobrane[Debuggen in ZeroBrane Studio]. `HOST` ist ohne Angabe `localhost` und `PORT` ist `8172`. Hört niemand zu, spielt sich das Spiel wie gewohnt, sobald der Versuch aufgibt, nach höchstens zwei Sekunden. Standard: aus. | `--deterministic[=MS]` | Nur zum Testen: die Echtzeit ignorieren und die ganze Engine auf einer virtuellen Uhr laufen lassen, die jeden Frame um `MS` Millisekunden weiterrückt, sodass dieselbe Frame-Nummer immer denselben Moment bedeutet. Auch die Disc folgt der virtuellen Uhr, ihre Frames dauern so lange, wie sie wert sind, und die Zufallsgeneratoren werden mit derselben Zahl initialisiert, sodass sich ein Lauf pixelgenau wiederholt. Der Wert ist optional und ist zugleich der Schritt und der Startwert, `1` bis `1000`. Standard, wenn ohne Wert angegeben: `15`, die Frame-Zeit, die sich aus der eigenen Rate der Engine ergibt. Die Taktung ist in diesem Modus bedeutungslos, ebenso der Ton, es sei denn, `--record` ist auch angegeben; dann wird er im Gleichschritt mit dem Bild erzeugt; siehe xref:Reference.adoc#deterministic[Deterministischer Testmodus]. Standard: aus. | `-P`, `--pack=DIRECTORY` | Das Spiel in `DIRECTORY` in die nach den Optionen angegebene Datenbank packen, dann beenden. Siehe xref:Reference.adoc#singlefile[Spiele in einer Datei]. | `-T`, `--patch=GAME.game` | Dateien im gepackten Spiel aus dem Verzeichnis oder der Patch-Datenbank ersetzen, die nach den Optionen angegeben ist, dann beenden. | `--perfsync` | Mit `--program` warten, bis die GPU jede Stufe eines Frames fertig hat, bevor die nächste gemessen wird, sodass die Perf-Zeilen sagen, zu welcher Stufe die Zeit der GPU gehört, statt alles bei `present` zu lassen. Alles läuft langsamer, solange es an ist, also ist es zum Messen da, nicht zum Spielen; siehe <>. Standard: aus. | `-p`, `--program` | Engine-Aktivität auf der Konsole und in `trace.txt` im Datenordner protokollieren. Die Datei beginnt mit einem Kopf, der den Rechner beschreibt; siehe xref:Reference.adoc#traceheader[Der Trace-Kopf]. Alle fünf Sekunden sagt sie außerdem, wohin die Zeit des Frames gegangen ist; siehe <>. | `--record=FILENAME` | Den ganzen Lauf, Bild und Ton, als MP4 unter `FILENAME` aufnehmen, vom ersten Frame an, bis Singe beendet wird. Mit `--deterministic` wird jeder Frame behalten und der Ton schrittweise zusammen mit dem Bild erzeugt, sodass beide genau zusammenpassen und während des Laufs nichts zu hören ist. Siehe <>. Standard: aus. | `-R`, `--reload` | Die losen Skriptdateien des Spiels beobachten und das Spiel von Grund auf neu starten, wenn sich eine ändert; `F5` tut dasselbe auf Abruf. Ein Skript, das sich nicht kompilieren lässt, bleibt beobachtet, sodass das Speichern der Korrektur es neu lädt. Für die Arbeit an einem Spiel; siehe xref:Reference.adoc#reloading[Neu laden während der Arbeit]. | `-t`, `--trace` | Jeden Lua-API-Aufruf mit der Skriptzeile, die ihn gemacht hat, auf der Konsole und in `trace.txt` protokollieren. Die Datei beginnt mit einem Kopf, der den Rechner beschreibt; siehe xref:Reference.adoc#traceheader[Der Trace-Kopf]. | `-U`, `--unpack=GAME.game` | Die Dateien des gepackten Spiels in das nach den Optionen angegebene Verzeichnis schreiben, dann beenden. Eine Datenbank, deren gespeicherte Namen außerhalb dieses Verzeichnisses landen würden, wird abgelehnt. |=== Optionen können als `-x 640`, `-x640` oder `--xresolution=640` angegeben werden. Numerische Werte werden geprüft; ein falscher Wert gibt den Hilfetext aus und beendet. Neuere Optionen haben keinen kurzen Buchstaben; das Alphabet ist ausgegangen, und ein zufällig gewählter Buchstabe würde niemandem helfen. Alles hier außer den Optionen, die das Spiel nennen, ein Verzeichnis nennen oder wirken müssen, bevor eine Datei gefunden werden kann, lässt sich auch in einer Einstellungsdatei setzen, sodass ein Automat kein Launcher-Skript für jedes Spiel braucht. Siehe <>. [[apiversion]] === Die Versionszeile `--apiversion` gibt eine Zeile aus und beendet mit dem Status `0`: ---- singe version=3.00 protocol=1 ---- Das ist ein Vertrag für Frontends, und seine Form wird sich nicht ändern: * Die Zeile endet mit einem Zeilenumbruch und ist das Einzige, was auf die Standardausgabe geschrieben wird. Sonst wird nichts ausgegeben, egal was sonst auf der Befehlszeile steht. * Das erste Feld ist immer `singe`. * Jedes Feld danach ist `key=value`, getrennt durch ein Leerzeichen, ohne Leerzeichen innerhalb eines Feldes. * `version` ist das Release, dieselbe Nummer, die das Banner zeigt. * `protocol` ist die Version des Formats dieser Zeile. Sie wird nur dann `2`, wenn sich die obigen Regeln jemals ändern müssen. * Spätere Versionen können Felder hinzufügen. Ein Leser muss Schlüssel ignorieren, die er nicht kennt, statt sie als Fehler zu behandeln. [[cabinet]] == Einen Automaten einrichten Arcade-Automaten brauchen ein paar Dinge, die ein Desktop nicht braucht: das Bild von Rändern wegrücken, die der Monitor verdeckt, es für einen seitlich eingebauten Bildschirm drehen, Grafik drumherum, einen Rahmen für eine Sinden-Lightgun und eine Punktetafel. Du brauchst dieses Kapitel nur, wenn du einen Automaten baust. Stell diese Dinge einmal in der `settings.cfg` des Automaten ein, oder benutze das Tool Display im Menü (siehe <>), um das Bild einzustellen, während du es ansiehst. [[videorect]] === Das Videorechteck Alles, was ein Spiel zeigt -- die Disc, das Overlay, die GUIs, die 3D-Szene und die Partikel -- wird in ein einziges Rechteck gezeichnet, und eine Handvoll Optionen entscheidet, wo dieses Rechteck liegt. Sie wirken in dieser Reihenfolge: . *Das Fenster oder der Ausschnitt des Bezels.* Das Rechteck beginnt als das ganze Fenster. Singe arbeitet in den eigenen Koordinaten des Videos und lässt das Fenster sie mit Letterbox darstellen (`--stretch` füllt stattdessen), sodass hier nichts von der Größe des Fensters abhängt. Wenn `--bezel` eine Grafik geladen hat, die einen Ausschnitt angibt, beginnt das Rechteck stattdessen als dieses Loch, und alles Folgende platziert das Bild darin; siehe <>. . *`--scalefactor`.* Das Rechteck schrumpft um seine eigene Mitte auf diesen Prozentsatz seiner Ausgangsgröße. . *`--shiftx` und `--shifty`.* Das Rechteck bewegt sich dann innerhalb des Platzes, den die Skalierung übrig gelassen hat, `-100` ganz an der einen Seite und `100` ganz an der anderen, und genau das bedeuten Hypseus’ eigene `-shiftx` und `-shifty`. Daraus folgen zwei Dinge, die man wissen sollte: Das Bild kann nie aus dem Bildschirm geschoben werden, und *bei `--scalefactor=100` gibt es keinen Platz, und eine Verschiebung bewirkt überhaupt nichts*. Um das Bild auf einem schief eingebauten Bildschirm zu verschieben, verkleinere zuerst die Skalierung: `--scalefactor=90 --shiftx=-100` setzt das verkleinerte Bild ganz an den linken Rand. . *`--sindengun`.* Der Rahmen wird zuletzt angewendet, auf das, was Verschiebung und Skalierung übrig gelassen haben. Der schwarze Ring nimmt den Rand des Rechtecks ein, der weiße Ring sitzt darin, und das Spiel kommt in beide hinein, sodass ein Rahmen ein Rahmen bleibt, wie auch immer das Bild platziert wurde. Eine Skalierung, die so klein ist, dass sie dem Spiel keinen Platz lässt, quetscht die beiden Ringe, statt es zu verschlucken. Mit geladener Bezel-Grafik geht der Rahmen stattdessen an den Rand des Fensters und lässt das Bild in der Größe, die es schon hatte; `--sindenedge` entscheidet es so oder so. `--rotate` ist nicht Teil dieser Reihenfolge. Der Frame wird ungedreht gezeichnet, und das fertige Bild wird als Ganzes im Uhrzeigersinn gedreht, sodass eine Verschiebung das Bild entlang der eigenen Achsen des Videos bewegt und sich mit ihm dreht. Eine Vierteldrehung vertauscht außerdem die Form der dargestellten Fläche, sodass ein Hochformatfenster ausgefüllt wird, statt mit Letterbox in einen Streifen gezwängt zu werden. Maus- und Lightgun-Positionen gehen denselben Weg rückwärts: Zuerst wird die Drehung herausgerechnet, und dann wird die Position in das Rechteck abgebildet, sodass ein Klick bei jeder Kombination dieser Optionen dort landet, wo der Spieler ihn sieht. `vldpGetScale`, `vldpSetScale`, `vldpGetRotate` und `vldpSetRotate` lassen ein Skript Skalierung und Drehung ändern, während das Spiel läuft; die Verschiebung ist eine Anzeigeeinstellung und hat keinen Skriptaufruf. Keine davon ist ein Schlüssel in `games.dat`: Wie `--scalefactor` beschreiben sie den Bildschirm des Spielers, nicht das Spiel. [[bezels]] === Bezels Ein Bezel (ein Bildschirmrahmen) ist die Grafik um den Bildschirm eines Arcade-Automaten. Singe zeichnet eines aus einer einzigen Bilddatei, mit dem Bild des Spiels in einem herausgeschnittenen Loch, und kann im verbleibenden Platz eine Arcade-Punktetafel zeigen. Drei Optionen steuern es, und sie folgen der Konvention von Hypseus, sodass die Befehlszeile eines Automaten unverändert übernommen werden kann. `--bezel cabinet.png` nennt die Grafik. Sie wird in dieser Reihenfolge gesucht: . `bezels/cabinet.png` im Spieleverzeichnis -- in einem gepackten `.game` dessen eigene Kopie, sodass ein Spiel sein Bezel mitbringen kann; . `bezels/cabinet.png` im Datenordner, wo die eigene Grafik eines Benutzers liegen kann, ohne ein schreibgeschütztes Spieleverzeichnis anzufassen. `--bezeldir art/cabinets` ersetzt den Ordner `bezels` durch den genannten, relativ zum Spieleverzeichnis oder absolut, und dann wird nur dieser Ordner durchsucht. Jedes Format, das SDL_image liest, geht (`.png` ist die vernünftige Wahl, weil Transparenz wichtig ist). Eine Grafik, die die Option nennt und die Singe nicht finden kann, beendet das Programm, statt ohne sie zu laufen. Die Grafik wird über das ganze Fenster gezeichnet, egal welche Form beide haben, sodass sie sich mit dem Fenster genauso streckt wie das Bild. Gib ihr das Seitenverhältnis, mit dem du zu spielen erwartest. [#_the_cutout] ==== Der Ausschnitt Neben der Bilddatei, und nach ihr benannt, sagt eine Begleitdatei, wo das Bild hinkommt: `bezels/cabinet.png` wird durch `bezels/cabinet.cfg` beschrieben. Sie ist eine Lua-Datei, wie `controls.cfg`, und setzt eine Tabelle in den *eigenen Pixeln* der Grafik: [source,lua] ---- -- Das Loch in cabinet.png, in das das Bild gezeichnet wird, in den eigenen Pixeln der Grafik. CUTOUT = { x = 200, y = 120, width = 800, height = 500 } ---- Alle vier Felder sind Pflicht, und das Rechteck muss innerhalb der Grafik liegen; eine Begleitdatei, die nicht läuft oder ein Rechteck außerhalb der Bilddatei nennt, beendet das Programm mit einer Meldung. Weil die Zahlen die eigenen der Grafik sind, bleiben sie bei jeder Fenstergröße richtig: Bilddatei und Loch werden zusammen skaliert. Mit einem Ausschnitt wird das Bild in dieses Loch gezeichnet -- auf das Loch gestreckt, sodass das Loch die Form des Bildes bestimmt -- und `--scalefactor`, `--shiftx` und `--shifty` wirken dann *innerhalb* davon, verkleinern das Bild und schieben es im Loch zurecht. Ohne Begleitdatei behält das Bild das ganze Fenster, genau wie ohne Bezel, und diese drei Optionen platzieren es wie immer. Siehe <>. Das Loch selbst sollte in der Bilddatei transparent sein. Singe zeichnet die Grafik standardmäßig hinter das Bild, eine undurchsichtige Mitte würde also einfach verdeckt, aber `--bezelflip` setzt die Grafik nach vorn, und dann lässt nur ihre Transparenz das Spiel durch. [#_draw_order] ==== Zeichenreihenfolge Ohne `--bezelflip` ist die Grafik das Erste im Frame: Bild, Overlay, GUIs, 3D-Szene und Partikel zeichnen alle darüber. Mit `--bezelflip` zeichnet sich die Grafik stattdessen vor das Bild, und das ist die Reihenfolge, die Hypseus für seine eigenen Bezels benutzt, sodass ein Rahmen mit weichen oder geformten Kanten das Bild richtig überlappt. Ein Skript entscheidet, was in diesem Fall mit dem Overlay passiert: xref:Reference.adoc#setoverlayontop[`setOverlayOnTop(true)`] zeichnet Overlay und GUIs über die Grafik, und `false` (der Standard, auch der von Hypseus) lässt die Grafik über ihnen. Mit der Grafik hinter dem Bild ändert die Einstellung nichts, weil sowieso alles darüber liegt. xref:Reference.adoc#mainbezelloaded[`mainBezelLoaded()`] sagt einem Skript, ob eine Grafik geladen ist, und gibt ihm die Kennung der Grafik, dieselbe Zahl, die Hypseus meldet, sodass ein Spiel, das für ein bestimmtes Bezel geschrieben wurde, es erkennen kann. GUIs im Bildschirmraum und die Punkteanzeige zeichnen immer über der Grafik, denn genau darauf sollen sie sitzen. [#_the_sinden_border] ==== Der Sinden-Rahmen Eine Sinden-Lightgun beobachtet den Bildschirm auf einen hellen Rahmen. Mit geladener Bezel-Grafik gehört dieser Rahmen an den *Rand des Fensters*, nicht um das Bild, weil die Kamera der Lightgun den ganzen Bildschirm sieht, also setzt `--sindengun` ihn genau dorthin, sobald ein Bezel geladen ist. Dort wird er als zwei Ringe gezeichnet, nach allem anderen, sodass die Grafik zwischen Rahmen und Bild sichtbar bleibt und nichts den weißen Ring übermalt. Ohne Bezel liegt der Rahmen um das Bild, wie er es immer getan hat, und verkleinert es. `--sindenedge video` oder `--sindenedge window` übersteuert diese Wahl in beide Richtungen: Ein Lightgun-Automat, dessen Grafik nur eine dünne Einfassung ist, will den Rahmen vielleicht trotzdem um das Bild, und ein Automat ganz ohne Grafik will ihn vielleicht am Rand des Bildschirms. [#_the_score_panel] ==== Die Punkteanzeige Sechzehn der Hypseus-Singe-Spiele können eine Arcade-Punktetafel ansteuern: Credits sowie eine Punktzahl und eine Lebensanzeige für jeden von zwei Spielern. In Singe ist diese Punktetafel das RmlUi-Dokument `Singe/scoreBezel.rml`, gestaltet durch `Singe/scoreBezel.rcss`, beide neben die anderen Hilfsdateien geschrieben. Wie alles im Ordner `Singe` werden sie bei jedem Start neu geschrieben, Änderungen daran halten also nicht lange: Ein Spiel, das ein anderes Aussehen will, liefert eigene Kopien aus, `scoreBezel.rml` neben seinem Skript, das auf ein eigenes Stylesheet verweist, und Singe verwendet dann diese. Der mitgelieferte Stil ist eine Siebensegment-Optik: Jede Anzeige zeigt ihre Ziffern schwach beleuchtet hinter dem aktuellen Wert, so wie es eine echte Anzeige tut. Die Anzeige ist *aus*, bis ein Spiel sie mit xref:Reference.adoc#scorebezelenable[`scoreBezelEnable(true)`] anfordert, und so liefert es auch Hypseus aus, sodass ein Spiel, das nie danach fragt, sich genau wie vorher verhält und seine eigene Punktetafel mit Sprites zeichnet. xref:Reference.adoc#scorebezelgetstate[`scoreBezelGetState()`] ist die Frage, die jedes solche Spiel zuerst stellt. Wo sie hinkommt, wird für dich entschieden: Die Anzeige nimmt das tiefere der Bänder, die das Bild über und unter sich lässt -- den Platz, den der Ausschnitt eines Bezels meist lässt -- zentriert auf das Bild, und liegt am unteren Rand des Bildes, wenn keines der Bänder tief genug ist, um sie aufzunehmen. Sie wird als GUI im Bildschirmraum gezeichnet, sodass ein Spiel mit xref:Reference.adoc#guidrawscreen[`guiDrawScreen`] seine eigenen GUIs auf die Grafik daneben setzen kann. `scoreBezelEnable` von Hypseus nimmt ein zweites Argument, das unter seinen fünf Punktetafel-Backends wählt. Singe hat eines, also wird das Argument angenommen und ignoriert. [[handhelds]] == Handhelds und kleine Rechner Singe läuft auf dem Raspberry Pi und auf günstigen ARM-Handhelds wie dem R36S. Dort funktionieren dieselben Spiele wie auf einem Desktop, aber ein kleiner Rechner braucht ein wenig Hilfe, damit sie gut laufen. [#_what_a_small_machine_needs] === Was ein kleiner Rechner braucht Sprites, Text, Sound und Video funktionieren überall. Die 3D-Szene und der schicke Look des Menüs brauchen einen Grafikchip mit Vulkan oder OpenGL ES 3.1. * Ein Raspberry Pi 4 oder neuer hat beides, also funktioniert alles. Ein Pi 3 hat nur OpenGL ES 2.0, und das reicht nicht für 3D. 2D-Spiele laufen trotzdem. * Die meisten Handhelds, der R36S eingeschlossen, haben einen Mali-Grafikchip mit OpenGL ES 3.1, also funktioniert 3D dort auch. * Auf einem Rechner, der keins von beiden hat, benutzt das Menü einen einfacheren Look, der sie nicht braucht. Wenn du zum ersten Mal ein 3D-Spiel startest, baut Singe seine Shader, was auf einem kleinen Rechner ein paar Sekunden dauern kann. Sie werden im Ordner `Singe` im Datenordner gespeichert, also passiert das nur einmal. [#_settings_for_a_small_machine] === Einstellungen für einen kleinen Rechner Schreib diese in die `settings.cfg` neben der Singe-Binärdatei, damit jedes Spiel sie benutzt: `scenequality = "low"`:: Zeichnet die 3D-Szene in halber Größe, ohne Antialiasing oder Bloom. 3D sieht etwas weicher aus, läuft aber viel schneller. Video, Sprites und Menüs sind nicht betroffen. `zerocopy = true`:: Das ist schon der Standard. Video geht vom Hardware-Decoder direkt zum Grafikchip, ohne dass die CPU es kopiert. Dadurch kann ein Handheld Laserdisc-Video mit voller Geschwindigkeit abspielen. Schalte es nur ab, wenn ein Video sich danebenbenimmt und du es als Ursache ausschließen willst. `quitchord = "back+start"`:: Handhelds haben keine Esc-Taste. Select und Start zusammen halten beendet das Spiel zurück ins Menü und das Menü zurück zu deinem System, egal wie das Spiel eingerichtet ist. [#_the_r36s_and_arkos] === Der R36S und ArkOS Der R36S und ähnliche Handhelds mit ArkOS benutzen den Linux-Build `aarch64` von Singe. Leg die Singe-Binärdatei, ihren Ordner `Singe`, `Menu.sh` und deine Spiele in einen Ordner, etwa `/roms/singe`. Starte `Menu.sh` einmal, damit Singe seine Hilfsdateien anlegen kann. Um Singe aus dem Menü Ports zu starten, leg ein Skript wie das folgende in `/roms/ports`. Diese Handhelds takten ihren Prozessor und Grafikchip nur zögerlich hoch, also setzt das Skript sie auf volle Geschwindigkeit, solange Singe läuft, und stellt sie zurück, wenn es beendet wird. [source,bash] ---- #!/bin/bash # /roms/ports/Singe.sh: Singe im Menü Ports. SINGE_DIR=/roms/singe [ "$(id -u)" -eq 0 ] && ESUDO="" || ESUDO="sudo" GOVERNORS=() for g in /sys/devices/system/cpu/cpufreq/policy*/scaling_governor /sys/class/devfreq/*/governor; do [ -f "$g" ] || continue GOVERNORS+=("$g:$(cat "$g")") echo performance | $ESUDO tee "$g" > /dev/null 2>&1 done restore() { for entry in "${GOVERNORS[@]}"; do echo "${entry##*:}" | $ESUDO tee "${entry%:*}" > /dev/null 2>&1 done } trap restore EXIT cd "$SINGE_DIR" || exit 1 ./Menu.sh "$@" ---- ArkOS teilt Spielen die Knöpfe Select und Start nicht mit, also funktioniert die Beenden-Kombination erst, wenn du diese `gamecontrollerdb.txt` neben die Singe-Binärdatei legst (siehe <>): ---- 1900bb3e4b4800000011000000010000,GO-Super Gamepad,a:b0,b:b1,x:b2,y:b3,back:b12,start:b13,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpdown:b9,dpleft:b10,dpright:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux, ---- Wenn ein Knopf nicht tut, was du erwartest, starte Singe einmal mit `--program` und drück ihn. Der Trace zeigt den Namen jedes Knopfs, den du drückst, oder seine Nummer, wenn die Belegung oben ihn nicht enthält. Leg zum Schluss eine `controls.cfg` neben die Singe-Binärdatei. Diese hier legt Münze und Start auf Select und Start und hält die Test- und Service-Menüs eines Spiels von den Aktionsknöpfen fern, auf die manche Spiele sie legen. [source,lua] ---- INPUT_1P_COIN = { SCANCODE.MAIN_5, SCANCODE.C, GAMEPAD_0.BUTTON_BACK } INPUT_1P_START = { SCANCODE.MAIN_1, GAMEPAD_0.BUTTON_START } INPUT_PAUSE = { SCANCODE.P } INPUT_SCREENSHOT = { SCANCODE.F12, SCANCODE.F11 } INPUT_SERVICE = { SCANCODE.MAIN_9 } INPUT_TEST_MODE = { SCANCODE.F2 } ---- Diese Datei gewinnt gegen die, die ein Spiel mitbringt (siehe <>). Pause und Screenshot werden auf die Tastatur verlegt, weil Singe sie normalerweise auf Start und Select legt. [[troubleshooting]] == Wenn etwas schiefgeht [#_the_trace] === Der Trace Starte Singe mit `--program` (oder `-p`), um zu sehen, was es tut. Alles wird auf der Konsole ausgegeben und in `trace.txt` im Datenordner des Spiels gespeichert. Wenn du ein Problem meldest, leg `trace.txt` aus einem Lauf mit `--program` bei. `--trace` (oder `-t`) protokolliert außerdem jeden Lua-Aufruf, den ein Spiel macht, was vor allem beim Schreiben eines Spiels nützlich ist. Wenn Singe unter Linux oder macOS abstürzt, schreibt es auf die Konsole und in `trace.txt`, wo es abgestürzt ist. `trace.txt` enthält nur die eigenen Meldungen von Singe. Meldungen des Soundsystems, des Videodecoders und des Grafiktreibers gehen nur auf die Konsole. Wenn diese das Problem sein könnten, speichere die Konsole mit. Unter Linux: ---- ./Menu.sh --program &> singe.log ---- [[perflines]] === Die Perf-Zeilen lesen Mit `--program` sagt der Trace alle fünf Sekunden, wohin die Zeit gegangen ist, als Durchschnitt pro Runde durch die Frame-Schleife: ---- Perf: 58.9 frames/s shown, 353 loops; per loop 13.1 ms (worst 82.3): disc 1.1, script 0.1, scene 0.0, gui 0.4, overlay 0.0, compose 0.0, present 11.4, other 0.1 Perf script: per loop 0.1 ms of Lua and 0.0 in engine calls it made; 0.0 in engine calls altogether: overlayClear 0.01 (0.8 calls), discGetFrame 0.00 (0.8 calls) Video 3 perf: 23.8 frames/s decoded; per frame 0.5 ms, of which read back 0.0, convert 0.0 ---- * `disc` -- das Laserdisc-Video weiterschalten und seinen Frame auf die GPU bringen. * `script` -- das `onOverlayUpdate` des Spiels, das die Zeile `Perf script` aufteilt in das Lua selbst und die Engine-Aufrufe, die es gemacht hat, die teuersten Aufrufe zuerst. * `scene` -- die 3D-Szene zeichnen. * `gui` -- die GUI-Dokumente anordnen und zeichnen. * `overlay` -- das, was sich am Overlay geändert hat, an die GPU schicken. * `compose` -- nur mit `--perfsync`: die GPU zeichnet Bild, Overlay und GUIs zusammen. * `present` -- den Frame anzeigen, was das Warten auf die nächste Bildwiederholung des Bildschirms einschließt. * `other` -- alles andere: Eingabe, Sound, Physik und der Rest. Die eigene Zeile eines Videos sagt, wie schnell es dekodiert und wie viel von jedem Frame dafür draufging, ihn vom Hardware-Decoder zurückzukopieren und seine Farben umzuwandeln; null für beides bedeutet, dass seine Frames zur GPU gehen, ohne kopiert zu werden. Die GPU arbeitet der CPU hinterher, also landet ihre Zeit ohne `--perfsync` dort, wo die CPU als Nächstes auf sie warten muss, und das ist meist `present`. Ein großes `present` bei voller Rate des Bildschirms ist nur das Warten auf die Bildwiederholung; ein großes `present` darunter bedeutet, dass die GPU beschäftigt ist. `--perfsync` lässt jede Stufe auf die GPU warten, bevor die nächste beginnt, sodass `scene`, `gui`, `overlay` und `compose` ihre GPU-Zeit enthalten und `present` nur das Warten auf die Bildwiederholung bleibt. Die Bildrate sinkt, solange es an ist, weil CPU und GPU nicht mehr gleichzeitig arbeiten; vergleiche die Stufen miteinander, nicht mit der Bildrate. [#_a_button_does_nothing] === Ein Knopf tut nichts Öffne das Tool Input Test im Menü (siehe <>) und drück den Knopf. Wenn das Tool ihn sieht, ignoriert ihn das Spiel, also prüfe die `controls.cfg` des Spiels. Wenn das Tool ihn nicht sieht, prüfe deine eigene `controls.cfg` oder die Belegung deines Controllers in `gamecontrollerdb.txt`. Ein Lauf mit `--program` zeigt jeden Knopf, während du ihn drückst. [#_sound_and_picture_are_out_of_sync] === Ton und Bild sind nicht synchron Manche Fernseher, Receiver und kabellose Lautsprecher verzögern den Ton. Miss die Verzögerung mit dem Tool Audio Delay im Menü. Singe merkt sie sich für jedes Spiel. Siehe xref:Reference.adoc#audiosync[Audio-Synchronisation] für Details. Bei abgehacktem oder stotterndem Ton siehe die häufig gestellten Fragen. [#_frequently_asked_questions] == Häufig gestellte Fragen *Warum heißt es Singe?* Singe ist der Name des Drachen in Dragon's Lair. Da Singe (das Programm) als Erweiterung für Daphne (die Prinzessin in Dragon's Lair) begann, wurde das Dragon's-Lair-Thema beibehalten. *Was ist der Unterschied zwischen Daphne, Singe, Hypseus und Singe 3.xx?* Daphne ist ein echter Laserdisc-Spiel-Emulator, der eine Handvoll klassischer Laserspiele ausführen kann. Daphne/Singe (Singe 1.xx) ist die ursprüngliche Version von Singe, die eine Erweiterung für den Emulator Daphne war -- zuerst als Spiel-DLL für Daphne ausgeliefert, später dann zu einer einzigen Binärdatei zusammengeführt, aus der die Emulationsfunktionen von Daphne entfernt waren. Hypseus-Singe ist ein erweiterter Fork von Daphne mit Unterstützung für Singe 1.xx und teilweise für Singe 2.xx. Singe 2.xx ist ein komplett neues, von Grund auf gebautes Upgrade des ursprünglichen Singe, und Singe 3.xx baut darauf auf, mit 3D, Physik und vielem mehr. Kurz gesagt: Wenn du Genauigkeit willst, nimm Daphne oder Hypseus, sofern sie die Emulation des gewünschten Spiels unterstützen. Wenn es ein Singe-Spiel ist, nimm Singe, oder probier Hypseus. *Warum sollten wir es nicht einen „Emulator“ nennen?* Emulatoren benutzen die echte Software oder die ROMs des Originalspiels und geben vor, die Maschine zu sein, auf der es ursprünglich laufen sollte. Aus Sicht des Spiels läuft alles wie gewohnt. Singe dagegen verlangt, dass jedes Spiel neu implementiert (portiert) wird, um auf Singe zu laufen. Das Endergebnis mag sehr ähnlich sein, aber wie es funktioniert, ist völlig anders. *Kann ich Spiele für Singe 1.xx und 2.xx unter Singe 3.xx spielen?* Ja, wahrscheinlich. Fast alles aus Singe 1.xx wurde für neuere Versionen von Singe umgewandelt und verbessert, und die meisten Spiele für Singe 2.xx laufen, wie sie sind. Spiele, die die älteren Sprite-Funktionen benutzen, brauchen vielleicht eine kleine Änderung; siehe xref:Reference.adoc#migrating[Umstieg von Singe 2.10]. *Brauche ich ein Laserdisc-Spiel, um Singe zu benutzen?* Nein. Spiele brauchen überhaupt keine Disc. Sie können Sprites, Video, 3D und alles andere benutzen, was Singe bietet. Siehe xref:Reference.adoc#withoutadisc[Spiele ohne Disc]. *Warum zeigt sich das Spiel, das ich gerade installiert habe, nicht im Menü?* Wer auch immer das Spiel gepackt hat, hat keine ordentliche `games.dat`-Datei beigelegt. *Warum ist HD-Video langsam?* Das sollte es nicht mehr sein. Singe benutzt jetzt deine Grafikkarte zum Dekodieren von Video, wenn dein System das unterstützt, sogar auf dem Raspberry Pi und vielen Handhelds. Wenn HD-Video immer noch langsam ist, hat dein System vielleicht keine Hardware-Videodekodierung, und dann braucht hochauflösendes Video viel CPU. Ein Lauf mit `--program` zeigt, welchen Decoder Singe benutzt. *Warum stottert mein Ton unter Windows?* Benutzer haben herausgefunden, dass die meisten Ton- und Stotterprobleme von Singe mit ihrem installierten Audiotreiber zusammenhängen -- besonders bei Geräten mit Realtek. Versuch, deine Soundtreiber zu aktualisieren oder auf den generischen Windows-HD-Audio-Treiber zu wechseln. Schalte Surround-Sound ab -- nimm Stereo, nicht 5.1 oder 7.1. Wenn deine Treiber dir Stereo nicht erlauben, kannst du das mit Virtual Audio Cable beheben: . Installiere VB-CABLE (https://vb-audio.com/Cable/). . Öffne die Soundeinstellungen von Windows (Rechtsklick auf das Lautsprechersymbol in der Taskleiste, dann *Sounds*, dann *Wiedergabe*). . Klick mit der rechten Maustaste auf das Gerät *Cable Input* und wähle *Als Standardgerät festlegen*. (Deine aktuelle Tonausgabe geht vorübergehend verloren.) . Geh zur Registerkarte *Aufnahme*. . Klick mit der rechten Maustaste auf *Cable Output*, dann auf *Eigenschaften*, dann auf *Abhören*, und aktiviere schließlich *Dieses Gerät als Wiedergabequelle verwenden*. Wähle in der Dropdown-Liste dein tatsächliches Wiedergabegerät. . Du solltest wieder Ton haben. Starte Singe, und dein Ton funktioniert ohne Verzögerung. *Funktioniert 3D auf einem Raspberry Pi oder einem Handheld?* Auf einem Raspberry Pi 4 oder neuer ja. Sie haben sowohl einen Vulkan-Treiber als auch OpenGL ES 3.1, und Singe benutzt, was es davon findet. Der Pi 3 hat nur OpenGL ES 2.0, das das Skinning und die Morph-Targets der Szene nicht ausdrücken kann, also führt er 2D-Spiele (2D-Physik eingeschlossen) genau wie vorher aus und verweigert den ersten 3D-Aufruf. Der Pi 4 ist das Minimum für jedes Spiel, das das Kapitel 3D-Szenen benutzt. Dasselbe gilt für die günstigen Handhelds: Ein Mali-G31 oder G610 hat das ES 3.1, das die Szene braucht, ob er nun Vulkan hat oder nicht. Siehe <>. *Warum stottert mein Ton auf dem Raspberry Pi?* Raspberry Pi OS benutzt jetzt Pipewire als Standard-Audio-Backend. Ein Wechsel zu PulseAudio scheint das Problem zu beheben: . Führe `sudo raspi-config` in einem Terminalfenster aus. . Wähle *Advanced Options*. . Wähle *Audio Config*. . Wähle *PulseAudio*. . Drück kbd:[Tab], wähle *Ok* und lass es neu starten. [#_making_games] == Spiele erstellen Dieses Handbuch handelt davon, Singe zu betreiben: es installieren, Spiele installieren, einen Automaten einrichten, und vom Menü. Das Erstellen von Spielen behandeln zwei weitere Bücher, die ein optionaler Download vom selben Ort wie Singe sind statt ein Teil davon, da sie zusammen größer sind als die Engine. * Die *Singe-Referenz* behandelt alles, was ein Spiel tun kann: das Programmiermodell, das Spieleverzeichnis, das Packen eines Spiels in eine Datei und jede Funktion, die die Engine bietet, mit ihren Argumenten, ihren Rückgabewerten und einem Beispiel. * *Programmieren lernen mit Singe* bringt Programmieren von null an bei, in einunddreißig Lektionen, jemandem, der noch nie Code geschrieben hat. Es kommt mit den Skripten und dem kleinen Grafikpaket, das die Lektionen benutzen. Der Download enthält die beiden Bücher als PDF und HTML, die Lektionsdateien und die Lizenz. Alle drei Bücher gibt es auf Englisch, Französisch, Italienisch, Deutsch und Spanisch, und den Download gibt es in jeder dieser Sprachen: Nimm den in deiner Sprache. Die Übersetzungen dieses Handbuchs liegen schon im Ordner `Singe` daneben. Forge, das Autorenwerkzeug, das ein Spiel aus einer Beschreibung statt aus Code macht, ist ein eigenes Projekt mit eigenem Download und eigenem Buch.