UML
Nachfolgend sind nun die einzelnen UML-Diagramme und die Logik, die dem Spiel zu Grunde
liegt aufgeführt.
Anwendungsfalldiagramm


Einfaches Klassendiagramm
Dieses Klassendiagramm enthält nur die Klassen selbst, keine Variablen und Methoden. In diesem Zustand hat es auch schon vor dem Programmieren von Genesis existiert. Das komplexe Klassendiagramm konnte ich zuvor noch nicht so eindeutig anfertigen, da es während des Programmierens eben doch immer wieder zu Änderungen im Programm kam, wodurch sich dieses verändert hätte.
Das einfache Klassendiagramm ist während des Programmierens sehr gut dazu geeignet immer vor Augen zu haben, wie die einzelnen Klassen miteinander verbunden sind. Aber auch die Fertigstellung des komplexen Klassendiagramms (nächste Seite) ist sinnvoll, da es andern hilft sich in das Programm hineinzudenken, bzw. auch dem Programmierer hilft, wenn er sich den Quellcode lange Zeit nicht angeschaut hat.
Komplexes Klassendiagramm
Dieses Diagramm ist nicht so aufgebaut, wie es in einem „realen Spiel“ ist (da hätte ja ein Spielplan mit der Zeit mehrere Bauteile), sondern so, wie es dem Quellcode von Genesis entspricht, und da besitzt ein ein Spielplan eben immer genau ein Bauteil (warum das so ist, kann man im Kapitel „Quellcodeverständnis“ nachlesen).
Zustandsdiagramm
Logik
Muster
Folgende Zeichnungen zeigen die ersten Muster, aus denen sich mein Spiel entwickelte
und auf denen es basiert.
Das Bauteil
Das Bauteil ist auf einem Gitter mit 3*3 Feldern gespeichert, das mit einem zweidimensionalen Feld simuliert wird. Das Bauteil besitzt außerdem noch ein zweites Feld, das benötigt wird, wenn man das Bauteil dreht, dort werden dann die zwischengespeicherten, neuen Werte festgehalten. In den Feldern wird die Form und die Farbe des Bauteils gespeichert. Hierzu werden die Felder mit int-Werten gefüllt. Dabei bedeuten die Zahlen 1 bis 9 je eine andere Farbe, die Zahl 100, dass diese Stelle leer ist. Dadurch kann das Bauteil anfangs immer auf eine der folgenden Arten aufgebaut sein:
Dieses Muster wird durch mehrere zweidimensionale Felder simuliert, von denen im folgenden erklärt wird, was die einzelnen Belegungen bedeuten:
Zum Zeichnen des Planes wird auf zusammensetzungPlan[][] zurückgegriffen, da dieses Feld die Werte für Farben und Koordinaten mithilfe der int-Werte speichert. Mit teile[][] kann man dafür einzelne Bauteile unterscheiden, was für das Herunterrutschen der Reihen über einer abgebauten Reihe wichtig ist. Dazu ist außerdem noch verschiebbarRechts[][] und verschiebbarLinks[][] nötig. Die Felder voll1[] bis voll3[] speichern die Reihen, die im aktuellen Spielzug vollständig sind, voll1[] links des Sockels, voll2[] rechts davon und voll3[] darüber.
Zusammenspiel zwischen Bauteil und Spielplan
Während des Spielens von Genesis wir insgesamt nur ein einziges Objekt des Typs Bauteil erzeugt. Anstatt immer wieder ein neues Bauteil zu erzeugen werden die Werte des einen immer wieder zurückgesetzt, wenn es fest auf dem Boden ist. Dies geschieht durch die Methode neu( ), die das Bauteil auch in seinem Konstruktor aufruft. Das Bauteil übergibt seine Koordinaten und sein Aussehen nach jeder Bewegung an den Spielplan, der diese Werte in seinen Feldern festhält und fest abspeichert, falls das Bauteil beendet ist, also fest auf dem Boden sitzt.
Diese Art des Zusammenspiels hat den Vorteil, dass alle wichtigen Werte im Spielplan gespeichert und nicht auf viele verschiedene Bauteile verteilt sind. Das vereinfacht die Logik und damit natürlich auch das Verstehen des Programms für Außenstehende.
Verschieben von Reihen
Dies war de wohl schwiererigste und langwierigste Teil des Projekts. Durch den zusätzlichen Sockel, den ich in die Spielfläche eingebaut habe haben sich einige Problem ergeben: man konnte nicht wie im normalen Tetris einfach alle Reihen über der abgebauten um eins nach unten fallen lassen, sondern musste die Besonderheiten abfragen. Folgender Falle war dabei zu beachten.
Überstehende Bauteile der anderen Flächen sollen nicht mit herabfallen, aber Teile der eigenen Seite schon, auch wenn sie bis in die anderen Sektoren reichte (mit Sektoren ist die Einteilung des Spielfeldes in die 3 Bereiche rechts, links und mitte gemient, die durch den Sockel gegeben ist):
In diesem Fall soll also zum Beispiel sobald das blaue Teil eingeordnet ist keines der Teile in den roten Kreisen sich bewegen. Dies hat sich besonders an den Sektorübergreifenden Stellen, insbesondere an den Ecken des Sockels, als problematisch erwiesen.
Gelöst habe ich dieses Problem letztendlich dadurch, dass ich 2 zweidimensionale Felder erstellte, in denen gespeichert wurde, welche Stellen sich bewegen dürfen, wenn rechts, bzw. links des Sockels eine Reihe abgebaut wurde. Alles, was sich für rechts abgebaute Reihen nicht bewegen durfte musste innerhalb des Baus (also aller Teile, die sich gegensitig stützen), irgendwo einmal die y-Koordinate 19, also direkt oberhalb des Sockels, auf dem Sockel oder links davon durchbrochen haben. Für links des Sockels zählt das natürlich gerade andersrum. Daher werden dann in den jeweiligen Feldern diese Stellen als unbewegbar festgehalten. Durch die Methode verschiebbarkeitFestlegen( ), der das entsprechende Feld übergeben wird, werden dann auch alle Bauteile, die zu dem Bau des Bauteils mit den entsprechenden Koordinaten gehören, als unbewegbar festgelegt. Das wird dadurch erreicht, dass alle direkt an die Urspungsstelle kreuzenden Stellen in einem Einzugsbereich von 3*3 Feldern, die die gleichen Werte in teile[]
[] haben ebenfalls als ubverschiebbar festgelegt werden, also das gesamte Bauteil. Dann werden auch die Stellen direkt darüber als unbewegbar festgelegt und als neuen Ursprung angesehen. Dies wird nun solange wiederhlt, wie es neue Ursprünge gibt.
Falls es nun also eine vollständige Reihe gibt, werden die genannten Schritte gemacht und die entsprechende Reihe entfernt. Bei jedem Teil, das nun verschiebbar ist und die Stellen des Plans direkt darunter frei sind, werden nun die neuen Werte in die Felder des Plans gespeichert. Es wird also praktisch eine Stelle des Spiels nach dem anderen nach unten gesetzt, was aber letztendlich als eine Bewegung auf dem Bildschirm erscheint.
Die Animationen
Die Animationen werden einfach dadurch simuliert, dass immer wieder neue Bilde auf den Bildschirm gezeichnet werden und dazwischen Pausen verschiedener Länge aufgerufen werden. (Wie man Pausen erzeugt ist im Kapitel „neuverwendete Befehle“ zu finden)