Archiv des Monats: November 2012

So viel zu tun, so wenig Zeit. Irgendwie finde ich es traurig, dass ich im Prinzip zu überhaupt nichts mehr komme, wenn ich nicht manchmal einfach ein Stoppschild aufstelle (und Leute enttäusche). Die Wochenenden sind bereits komplett verplant, bevor sie überhaupt angefangen haben, und unter der Woche geht ja sowieso nichts, wenn man erst um 21 Uhr sein täglich zu absolvierendes Alltagsprogramm abgespult hat. Aber genug Geheule für heute. Der nächste Urlaub kommt bestimmt.

Trotz allem ist es mir ein großes Vergnügen, die neuesten Fortschritte bei meinem kleinen Feierabend-Hobby-Projekt vorzustellen: Mein Dongleware-Remake Spacola Eclipse ist jetzt praktisch „spielbar“ in der Version 0.19. Das letzte Mal als ich nennenswert am Code arbeitete, war Anfang Juli. Vor einer Woche packte es mich dann endlich wieder, als ich mich der alten Sound-Problematik annahm. Nach langem Herumgebastele und mit der Unterstützung eines Indie-Spieleentwicklers konnte ich es zu meiner Zufriedenheit hinbiegen. Es geht tatsächlich, allerdings muss man sich um das Abspielen selbst kümmern. Der Sound funktioniert seitdem besser denn je und es sind viele Ingame-Samples dazugekommen. Dadurch hatte ich die nötige Motivation um auch andere Dinge anzupacken.

Im Anschluss schrieb ich lässig den Code für die Asteroiden und die Kollisionserkennung runter. Asteroiden kann man nun zerstören und mit dem Schiff an ihnen abprallen. Zugegeben, die Mathematik hinter dem „Abprall“-Effekt von Asteroiden, die wollte ich mir nicht mit dicken Mathebüchern herleiten. Da geht es um Drehung von Koordinatensystemen, damit man eine eindimensionale Kollision berechnen kann und den Abprallwinkel und die Abprallgeschwindigkeit beider Objekte bekommt. Gruseliges Zeug wenn man schnell fertig werden will. Für die Methode ließ ich mich bei anderen intelligenten Programmierern inspirieren. Es funktioniert noch nicht perfekt, aber immerhin.

In der Folge kamen weitere Powerups hinzu, so z.B. alle Schuss-Powerups und die Extraleben. An Stationen kann man jetzt andocken, so dass man entweder wüst beschimpft wird, oder das Sonnensystem vom Spiel als erfolgreich abgeschlossen beendet wird. Ja genau, endlich kann man im Spiel vorankommen und die Levels zumindest gewinnen. So kann man nach und nach alle Sonnensysteme auf der Übersichtskarte abhaken. Verlieren kann man bisher noch nicht, da das Sterben noch nicht implementiert ist und es weiterhin noch keine Gegner gibt (kommt, kommt!). Die Sektoren sind bisher alle zufallsgeneriert, was leider nicht ganz richtig ist, da das Original-Spacola hier gewisse Konfigurationen kennt, die in die Levelgenerierung mit einfließen. Auch der Zielsektor ist fest nach einem bestimmten Schema berechnet und nicht komplett dem Zufall überlassen. Für den Moment muss es aber so gehen.

Die Preis-, Fahndungs- und Bonuslisten sind fast fertig. Die Preise stimmen alle und die Screens sind alle eingebaut, aber bisher sind eben nur die Sprites für die Lieferartikel eingebunden – die Sprites für Gegner und andere Hindernisse fehlen noch. Ebenfalls fehlen die animierten Sprites für das Beschleunigen des eigenen Raumschiffs. Zur Vereinfachung habe ich stattdessen zwei Partikelstrahler-Objekte bei den Triebwerken platziert, die beim Beschleunigen Pixelpartikel emittieren. Sieht eigentlich sehr viel besser aus als im Original, aber es bleibt am Ende natürlich nicht so. Vermutlich lasse ich diesen Effekt für spätere Versionen drin.

„Wie bitte? Sound in Java? Wer würde denn so etwas wollen? Und dann wahrscheinlich auch noch 100% plattformunabhängig, ja? Wer Sound in Java haben will, soll wenigstens furchtbar leiden müssen. Also gut, wir machen es! Aber wir machen es so schlecht wie möglich, damit es niemand benutzen will!“

So oder so ähnlich muss das wohl bei Sun geklungen haben, als man sich irgendwann notgedrungen entschloss eine Java Sound API zu entwickeln. Ich kann mir jedenfalls nicht anders erklären, wieso es im Jahr 2012 immer noch nicht möglich ist, anständig mit JavaSound zu arbeiten, wenn es um so simple Dinge wie Ausgabe von z.B. WAVE-Audio geht. Es funktioniert – keine Frage – aber es macht keinen Spaß und es ist eine performancetechnische Katastrophe.

Gestraft ist man vor allen Dingen dann, wenn man sich aus Gründen des Minimalismus und im Sinne der größtmöglichen Platzersparnis entschließt, weitestgehend unabhängig von den bekannten teilweise mehrere Megabyte großen Java-Soundbibliotheken irgendwelcher Fremdanbieter bleiben zu wollen, die vereinzelt scheinbar sogar 3D-Audio in Java realisieren können. Aber sowas wollte ich gar nicht. Ich wollte einfach nur Audiodateien ausgeben ohne zusätzlichen Ballast von irgendwelchen Multimediabibliotheken und Java-Spiele-Komplett-Engines einbinden zu müssen. Ich bräuchte sowieso nur Start, Stopp und einstellbare Loops, mehr nicht. Zum Glück kann das JavaSound alles. Theoretisch.

Man hat die Wahl der Qual zwischen Pest und Cholera. Es gibt java.applet.AudioClip, welches den Vorteil hat, wirklich extrem einfach zu bedienen zu sein. Man kann da gar nichts falsch machen. Leider funktioniert das mit vielen WAVE-Dateien nicht, wenn sie z.B. eine etwas exotischere Samplingfrequenz haben. Auch gibt es Probleme mit sehr kurzen oder sehr langen Audiodateien. Und das Loopen und Abspielen ist mir dann eigentlich doch zu spartanisch. Looppoints wären schon nötig gewesen.

Für so etwas gibt es JavaSound mit javax.sound.sampled.Clip. Funktioniert ähnlich einfach, und bringt gleich die nötigsten Methoden mit, man kann sogar „Vor- und Zurückspulen“ und die Anzahl der Loops setzen. Clip leidet allerdings unter einer unglaublich miesen Performance. Das macht sich beim Abspielen eines einzelnen Samples gar nicht bemerkbar, außer man hält den Speicher- und CPU-Verbrauch seiner JVM sehr genau im Auge. Nein, das ganze Ausmaß des Grauens entdeckt man erst, wenn man – wie das z.B. in Spielesoftware recht üblich ist – den selben Clip in sehr kurzen Abständen mehrfach hintereinander abspielt (z.B. Sprung- oder Schieß-Geräusche). Die ganze Anwendung beginnt zu ruckeln, die Sounds werden teilweise verschluckt, manchmal überhaupt nicht abgespielt. Das ist so natürlich nicht akzeptabel. Ich vermute es liegt einfach am nicht unerheblichen Overhead für das Starten und Stoppen der Threads jedes einzelnen Sounds.

Es gab da noch eine weitere Kleinigkeit, die mir die Haare zu Berge stehen ließ. Bei Clip lassen sich zwar bequem die Looppunkte setzen, beim ersten Abspielen mittels loop() scheint es diese aber komplett zu ignorieren. Erst beim zweiten und bei jedem weiteren Mal geht es dann plötzlich wie gewünscht. Ich habe alle erdenklichen Kombinationen versucht, den Audiopuffer geleert, und alle Methoden getestet, die diese Klasse mit sich bringt. Da war nichts zu machen. Ich musste mir schließlich mit einem billigen Workaround behelfen, das Sample zuvor „heimlich“ einmal für eine Millisekunde anzuspielen und sofort mit anschließendem Rewind zurücksetzen, damit es dann gleich beim ersten Mal richtig loopt.

JavaSound hat noch soviele Kinderkrankheiten, dass es beinahe schon absurd ist, wenn man bedenkt, wie lange es Java schon gibt. Sogar die deutlich jüngere Dalvik VM unter Android bietet mehr und leistet mehr, ist vor allem sehr viel spielefreundlicher in dieser Hinsicht. Multimedia in Java ist wohl leider noch etwas, das äußerst stiefmütterlich von Sun bzw. Oracle behandelt wird. Okay, dafür gibt es ja wenigstens JavaFX 2.0. Vielleicht taugt das ja für solch verrückte und völlig abwegige Experimente wie Soundausgabe in einer Java-Anwendung.

Ich dachte bis heute morgen noch, ich sei mittlerweile lange genug Java-Entwickler, um vor solchen blöden Fehlern gefeit zu sein. Stellt sich heraus, dass man wirklich viel Zeit mit sinnloser Fehlersuche selbst in simpelstem Code verschwenden kann.

Heute schrieb ich etwas in meiner favorisierten Java-IDE Eclipse, das ich in der Art praktisch täglich unzählige Male schreibe:

List<String> myList = new ArrayList<String>();

List und ArrayList wurden mir rot unterstrichen, weil er die Klassen nicht kannte. Es dauert natürlich nur wenige Klicks und Eclipse generiert die fehlenden Imports blitzschnell. So weit so normal. Doch dann wird mir List erneut rot unterstrichen, mit der Fehlermeldung „The type List is not generic; it cannot be parameterized with arguments <String>„.

Ungläubig starrte ich die Fehlermeldung an. Ich war mir eigentlich total sicher, dass List Generics verwendet. Sicherer ging es fast nicht. Die Fehlermeldung sagte also genau das Gegenteil von dem aus, was meiner Ansicht nach den Tatsachen entsprechen sollte. Oder doch nicht? Plötzlich begann ich zu zweifeln. Werde ich etwa schon senil? Wieso ist ArrayList parametrisierbar, aber List auf einmal nicht? Ist das irgendwie sinnvoll?

Ich begann hilflos, die Zeile irgendwie zu modifizieren. War List auf einmal allergisch gegen String geworden? Nein, daran lag es nicht, auch andere Parameter nahm er nicht an. Ich hätte den Parameter weglassen können, oder ich hätte auch direkt ArrayList anstelle von List verwenden können, das hätte funktioniert, aber Eclipse sollte mich doch nicht etwa dazu kriegen, die wichtigsten Programmierparadigmen zu vergessen. Ich vermutete, dass Eclipse einfach mal wieder seine Tage hatte und mich zu Unrecht irgendwelcher Anfängerfehler beschuldigte. An der Zeile war alles in Ordnung, postulierte ich.

Ich begann also doch das Orakel von Google zu bemühen, weil ich offenbar außer Stande war, mir selbst bei solch einem trivialen Problem zu helfen. Eine Quelle behauptete nun, dass es wohl mit dem Compliance-Level des Compilers zu tun hatte, das versehentlich auf eine Version vor Java 1.5 gestellt sein musste, also bevor Generics in Java eingeführt wurden. Ein kurzer Blick in die Compiler-Optionen des Projekts widerlegte das. Mit dem Compliance-Level war alles in Ordnung. In Zukunft also wieder auf konkrete Implementierungen programmieren?

Zum Glück nicht, denn des Rätsels Lösung fand ich direkt im Anschluss, und ich bin erschrocken über die Tatsache, dass ich an dieser Stelle vielleicht erst ganz zuletzt gesucht hätte. Ich habe mich bei den Imports entweder verklickt oder Eclipse hat mich einfach nur auf den Arm nehmen wollen. Als ich List importieren wollte, habe ich wie automatisch die oberste Option ausgewählt, weil das in dem Fall normalerweise immer funktioniert. Ausnahmsweise dachte Eclipse, es wäre besonders witzig wenn ganz oben die wenig bekannte java.awt.List stehen würde, anstelle der sehr viel häufiger genutzten gleichnamigen Klasse java.util.List.

Nun, die AWT-List verwendet tatsächlich keine Generics, Eclipse hat also Recht behalten. Aber der Fehler ist so dämlich, dass es mir eine Lehre war, die Imports allzu leichtfertig zu handhaben. Künftig prüfe ich höchstpersönlich jede einzelne importierte Klasse auf Richtigkeit.

Einer der Spielekomponisten, die ich am meisten schätze, ist neuerdings auf Kickstarter mit seinem eigenen Projekt zu finden: Allister Brimble, der fantastische Hausmusiker der britischen Kult-Spieleschmiede Team17, die in den 90ern viele große Amiga-Knaller lieferten, will einige seiner bekanntesten Soundtracks in einer aufwändig remasterten Version auf zwei CDs veröffentlichen. Nachdem Chris Hülsbeck vor einigen Monaten dasselbe versuchte und damit höchst erfolgreich war, ist es mir nun eine umso größere Freude zu sehen, dass auch andere Amiga-Musiker ihre Werke entstauben wollen.

Leider ist Kickstarter immer noch scheiße und ohne Kreditkarte kann man als Europäer leider nichts spenden, daher bin ich raus. Aber ich kann zumindest ein bisschen die Werbetrommel für dieses tolle Projekt rühren, dann können andere Leute spenden und Allister Brimble erreicht womöglich das Spendenziel. Und wenn ich viel Glück habe, gibts die CDs hinterher ja vielleicht sogar über andere Wege zu ergattern.

Das Projekt nennt sich „Allister Brimble – The Amiga Works„, in dem neue Versionen bekannter Amiga-Spielemusik zu Superfrog, Alien Breed, Body Blows, Project X, Assassin und diversen anderen Highlights zu finden sein werden. Vor allem von Superfrog ist angekündigt, dass sämtliche Leveltunes neu eingespielt werden, daran wäre ich ganz besonders interessiert. Wer 50 britische Pfund oder mehr spendet, der bekommt sogar ein handsigniertes Exemplar von Brimbles erstem Album „Sounds Digital“, das ich damals nur als digitalen Download zusammen mit der Compilation „The Best of Allister Brimble“ auf seiner Webseite bekommen konnte. Wohlgemerkt, das war vor über 12 Jahren, seitdem gibt es das nicht mehr. „Sounds Digital“ ist ein wundervolles Album, auf dem bereits u.a. die remasterten Titelsongs von Project X und Assassin zu hören waren. Daher bin ich schon gespannt, was sich nun genau an diesen Songs ändern wird.

Kickstarter kann sich ruhig mal um Spender aus anderen Ländern als den USA und dem Vereinigten Königreich kümmern. Finde ich extrem ärgerlich, dass es keine alternativen Zahlungsweisen gibt. Es ist ja nun nicht so als gäbe es Kickstarter erst seit einer Woche. Ach verdammt, dann hol ich mir halt so eine bekackte Kreditkarte von Amazon. Dann hat der gemeine Internetkonzern mal wieder gewonnen. Ein Hoch auf das Monopol.