Schlagwort-Archive: Vektorarithmetik

Mein treuester „Spacola Eclipse“-Fan hat sich soeben bei mir erkundigt, wie es denn mittlerweile um mein kleines Remake steht. Wie es der Zufall wollte, konnte es kaum einen besseren Zeitpunkt geben, mich das zu fragen. Nach mehreren Wochen fauler Abstinenz gelang es mir gestern und heute tatsächlich für ein paar Stunden einige Dinge am Code zu ändern und Kleinigkeiten von der To-Do-Liste zu streichen. Zeit für mich, meinen ereignislosen Blog mit Dev-News zu füttern.

spacolabrechnungAuf der linken Seite kann man dazu eine Abbildung sehen. Was auf den ersten Blick wie zweimal exakt derselbe Screenshot aussieht, ist in Wirklichkeit eine Gegenüberstellung von Original (oben) und Remake (unten). Ja genau, dieser kleine Aspekt hat mich bestimmt drei Stunden meines Lebens und so einige Nerven gekostet. Es handelt sich im Spiel um den Teil der „Kontoabrechnung“, also die Grafik, die man zu sehen bekommt, sobald man einen Level erfolgreich beendet hat. Hier werden jeweils gelieferte Waren in bare Münze umgerechnet und anschließend kann man schon den nächsten Level beginnen.

Es waren die vielen kleinen Dinge, die die Arbeit so langwierig machen. Pixelgenaue Abstände, Schriftzeilenhöhe, richtige Zentrierung, originalgetreues Timing, Sounds, HUD-Events während der Animation (Highscore!), sukzessives Entfernen der Sprites aus dem Inventar, dabei gleichzeitiges Hochzählen des Punktestands. Und nein, ich habe nicht einfach nur eine große Grafik eingebunden, alles wird dynamisch gezeichnet. Die Unterschiede sind marginal, aber sie sind (leider) da.

Falls sich jemand wundert, wieso auf dem unteren Screenshot das Abrechnungsergebnis nicht mit dem tatsächlichen Score übereinstimmt: Die Berechnung ist leider noch hartkodiert. Ein Fake, ein Test, nur zum Vergleichen. Alles andere ist echt.

Die zweite größere Neuerung ist, dass die Highscore jetzt vollständig in eine Datei gespeichert und beim nächsten Spielstart auch von dort wieder ausgelesen wird. Jetzt fehlt eigentlich „nur“ noch der Dialog zur Eingabe des Namens, dann wäre auch der ganze Highscore-Kram fix und fertig. Aber den Spaß hebe ich mir vermutlich doch für ein anderes Mal auf.

Bereits mit Version 0.23 kam der zweite Gegnertyp hinzu, der zwar komplett eigenständige Sprites hat, sich aber (Copy & Paste sei dank) fast genauso verhält wie der erste Gegnertyp. Ist im Moment eben noch work in progress. Außerdem gibt es jetzt die Geschwindigkeitsstufen für Hyperspeed und natürlich „Ridiculous Speed“ in Anlehnung an den Filmklassiker Spaceballs. Anfang April habe ich noch die komplette Vektorarithmetik zusammengefasst, umgeschrieben und in eine eigene Klasse ausgelagert. Damit habe ich drei Dinge erreicht: 1.: eine konsistente Implementierung der Bewegung von Spielobjekten. 2.: jede Menge überflüssiger oder redundanter Code, der jetzt rausgeflogen ist. 3.: um die 20 Klassen mussten angepasst werden, damit der Code seit der Änderung wieder kompilierbar wurde.

Achja, wir haben jetzt Ingame-Musik und die lässt sich in der Konfiguration sogar an- und abschalten. Der Song ist zwar nicht optimal, aber er ist so ziemlich der passendste, den ich bisher finden konnte. Ich werde da mal noch weitersuchen. Zuletzt kann ich noch erwähnen, dass die Raketentriebwerke der Piratenschiffe jetzt auch Partikel sprühen, wenn sie Schub geben. Das sieht deutlich wuseliger aus als noch in der letzten Version. Vor einigen Wochen hatte ich mal ein neues Preview-Video angekündigt. Ich denke, ich werde meine Ankündigung daher etwas relativieren und mit dem Video warten, bis es wieder spektakuläre Änderungen gibt.

Nachtrag vom 02.06.: Heute war ich ebenfalls ein bisschen fleißig: Der Spieler kann jetzt mit aktiviertem Schildgenerator von gegnerischen Schiffen abprallen (so wie bei Asteroiden bisher schon) oder sich von den Piraten bestehlen lassen, wenn er ohne Schild unterwegs ist. Allerdings fehlt den Piraten noch die nötige Intelligenz um das Diebesgut auch abzuliefern. Wenn der Spieler keine Ware mehr im Inventar hat, kann er den Level jetzt nicht mehr beenden. Mal sehen, vielleicht kümmere ich mich heute noch darum, dass die Gegner auch zurückfeuern können.

Nachtrag vom Nachtrag: Keine drei Stunden später ist es dann soweit: Die Gegner können jetzt aus allen Rohren zurückballern. Und als Spieler muss man sich ganz schön in Acht nehmen. Das macht das Gameplay nun tatsächlich um einiges hektischer als zuvor. Vor allem aber macht es das Gameplay um einiges sinnvoller, denn so nähert sich das Spiel langsam einem ansatzweise vorzeige- und spielbaren Zustand. Hurra!

Aus der Kategorie „zu doof für Mathematik, aber intelligent genug um sich trotzdem was einfallen zu lassen“: Heute habe ich mir mal wieder ausgiebig meinen alten Quellcode für meine Spacola-Maussteuerung vom August 2010 angesehen und mich daher auch mal wieder ein bisschen mit den mathematischen Grundlagen (Trigonometrie und Vektorarithmetik) auseinandergesetzt. Ein wenig Schmunzeln musste ich über meine unkonventionelle Lösung eines alten Problems, das ich damals hatte.

Man nehme einen Mauszeiger, der irgendwo in einem karthesischen Koordinatensystem liegt. Nun musste ich herausfinden, welchen Winkel der Richtungsvektor Ursprung->Mauszeiger mit der Y-Achse einschließt. Da ich selten mit der Mathematik einer Meinung war, aber dafür umso mehr gewillt, diese Aufgabe von alleine zu lösen, nahm ich mir seinerzeit Papier und Bleistift zur Hand und fing damit an, mir eine Lösung zu überlegen. Und ich fand einen Algorithmus, mit dem ich den Winkel näherungsweise bestimmen konnte.

Aber zunächst zur idealen und simpelsten Lösung:

Man benötigt im Prinzip nur Delta X und Delta Y zwischen den beiden Punkten, also den Ortsvektor. Anschließend teilt man Delta Y durch den Betrag des Vektors und berechnet aus diesem Wert den Arkus-Kosinus. Das Ergebnis muss dann noch mit 360 multipliziert und wieder durch 2 Pi geteilt werden. Schnell und effizient. Ich bin kein Mathegott, aber ein paar Minuten Suchen hat mich auf die richtige Lösung gebracht.

Witzig fand ich dagegen meinen Algorithmus, der folgendermaßen aussieht:

Ich habe beliebig viele Punkte (im Extremfall 360 Stück, in meinem Fall aber nur 40) auf einem Einheitkreis um den Mittelpunkt generiert und von jedem dieser gedachten Punkte den Abstand zur Mauszeigerkoordinate bestimmt. Mein gedanklicher Ansatz war der, dass der Punkt, der den kürzesten Abstand zur Zielkoordinate hat, mehr oder weniger exakt denselben Winkel zur Y-Achse hat. Mit dem Vorteil, dass ich dessen Winkel (da selbst generiert) genau kannte. Anschließend habe ich noch eine merkwürdige Umrechnung vom Bogenmaß ins Gradmaß durchgeführt. Das Ergebnis war zufriedenstellend.

Für letzteres Codebeispiel schlagt mich bitte nicht. Ich wusste damals schon, dass das nur ein Provisorium ist. Ich weiß noch nicht einmal mehr wofür „targetCnt“ steht.

Zugegeben, meine Lösung ist extrem unperformant und relativ ungenau, aber nichts stärkt das Ego mehr als die Gewissheit, ein Problem selbst und ohne Hilfe bewältigt zu haben, wenn man es sich vorher nicht zugetraut hätte. Wie dem auch sei, heute habe ich meinen provisorischen Algorithmus abgelöst und durch die exakte Berechnung ersetzt.

Es gibt Neuigkeiten von Spacola Eclipse. Leider keine bahnbrechenden Neuigkeiten, aber immerhin. Aus irgendeinem mir bislang unerfindlichen Grund habe ich zur Zeit genug Motivation um wieder relativ intensiv an meinem kleinen Remake zu arbeiten. Die letzten Monate habe ich mir den Quellcode immer mal wieder angesehen und ein paar Verbesserungen eingefügt, aber ich habe mich konsequent davor gedrückt, neue Kernfeatures einzubauen, die dringend nötig wären. So darf ich nun (stolz) das Ergebnis der letzten drei Tage präsentieren:

In Spacola Eclipse darf jetzt scharf geschossen werden. Ich habe das Schießen endlich implementiert. Für drei Tage Arbeit ist das mickrig, sagt ihr? Ja ist es. Aber wenn ihr die Mathematikprüfungen im Studium gerade so bestanden habt (so wie ich), dann habt ihr vielleicht eine Vorstellung davon, wie mühsam es ist, sich trigonometrische Operationen, Vektorarithmetik und Koordinatensystemumwandlungen aus dem Kopf herzuleiten ohne danach zu googlen oder ein Mathebuch herzunehmen – vor allem dann wenn die letzte Mathematikvorlesung schon ein paar Jahre her ist. Alles was ich hier mache, lerne ich durch Trial and Error. Wenn ein Algorithmus nicht funktioniert, dann nehme ich ein Stück Papier zur Hand und überlege mir eine Lösung.

Leider gibt es noch nichts worauf geschossen werden kann. Die Gegnersprites sind zwar längst angelegt, aber die Gegner-KI ist praktisch noch „leer“. Zu diesem Zweck hab ich außerdem eine abstrakte Klasse für Gegner angelegt und die wichtigsten Methoden definiert. Leider ist es extrem schwer, das Gegnerverhalten rein aus der Beobachtung des Ergebnisses nachzubilden – also wenn man nicht weiß, was im Hintergrund alles passiert. Ich kann nur versuchen, etwas zu schreiben, das dem erwarteten Verhalten nahekommt.

Der erste Gegner wird der (von mir so bezeichnete) „Peashooter“ sein. Aus dem Handbuch des Originals ist der Name des Schiffs nicht ersichtlich, also hab ich ihn genau so genannt wie er aussieht – wie diese eine Pflanze aus „Plants vs. Zombies“. Er ist einer der wenigen Gegner, die auf den Spieler feuern können, und so ziemlich der erste, dem man im Spiel begegnet.