Informatik -- Lehrveranstaltung vom 19.06.2024
(EN google-translate)
(PL google-translate)
Entwicklung eines einfachen "Arcade Games"
In den 1980er Jahren kamen so genannte Arcade Games auf, einfache Action-Spiele gegen den Computer, wie Space-Invaders, Pacman, Racing u.ä.
Mit der Processing-Entwicklungsumgebung lässt sich so etwas gut realisieren.
Als Motivation sei angeführt:
|
Grundkonzept
Das Grundkonzept wird hier vorgegeben und kann dann beliebig verfeinert und erweitert werden:
|

Bild 0-1: Entwurfsskizze.
Spezifizierungen:
|
Transiente Ereignisse
Es gibt Spielereignisse, die dazu führen, dass das Spiel von einem MODE in einen anderen übergeht. Beispiele:
|
Legen Sie alle möglichen Übergänge und Zustände zu Beginn der Entwicklung fest.
Die Spielfiguren können als Objekte von entsprechenden Klassen umgesetzt werden, um später auch beispielsweise "Gesichter" ergänzen zu können.
Snippets (Kleine Code-Abschnitte, die bestimmte auftretende Programmierprobleme lösen)
#import java.util.Random; Random zufall = new Random(System.currentTimeMillis()); public void setup() { } public void draw() { int z = zufall.nextInt(10); //Liefert eine gleichverteilte Zufallszahl zwischen 0..9. }
Code 0-1: Zufallszahlen erzeugen.
int MODE=0; public void zeichneStartbildschirm() { ... } public void draw() { switch(MODE) { case 0: zeichneStartbildschirm(); break; case 1: ... break; ... default: break; } }
Code 0-2: Die switch-Anweisung, um zwischen Modi zu unterscheiden.


public void mouseClicked() { if(mouseX>550 && mouseY<100 && MODE==0) //Beispiel { MODE=1; } }
Code 0-3: Bei Tastendruck starten
ÜBUNG
|
|
ENTWICKLUNGSSCHRITTE
Spiel001, nur das Raster und die Matrix
int[][] mat = new int[11][11]; public void setup() { size(750,550); frameRate(30); mat[5][5] = 1; mat[0][0] = 3; mat[0][1] = 2; } public void draw() { background(255); float kante = 50; for(int i=0;i<mat.length;i++) { for(int k=0;k<mat[i].length;k++) { noFill(); stroke(0); rect(k*kante,i*kante,kante,kante); } } }
Code 0-4: Spiel001, nur das Raster und die Matrix.
Spiel002, Spielfiguren sichtbar
int[][] mat = new int[11][11]; public void setup() { size(750,550); frameRate(30); mat[5][5] = 1; mat[0][0] = 3; mat[0][1] = 2; } public void draw() { background(255); float kante = 50; for(int i=0;i<mat.length;i++) { for(int k=0;k<mat[i].length;k++) { noFill(); stroke(0); rect(k*kante,i*kante,kante,kante); if(mat[i][k]%10==1) { fill(0,0,255); noStroke(); ellipse(k*kante+kante/2,i*kante+kante/2,kante,kante); } else if(mat[i][k]%10==2) { fill(0,255,0); noStroke(); ellipse(k*kante+kante/2,i*kante+kante/2,kante/2,kante/2); } else if(mat[i][k]%10==3) { fill(255,0,0); noStroke(); triangle(k*kante+kante/2,i*kante,k*kante,(i+1)*kante,(k+1)*kante,(i+1)*kante); } } } }
Code 0-5: Spiel002, Spielfiguren sichtbar.
Spiel003, Spieler bewegen
int[][] mat = new int[11][11]; int x_spieler, y_spieler; public void setup() { size(750,550); frameRate(30); x_spieler = 5; y_spieler = 5; mat[y_spieler][x_spieler] = 1; mat[0][0] = 3; mat[0][1] = 2; } public void draw() { background(255); float kante = 50; for(int i=0;i<mat.length;i++) { for(int k=0;k<mat[i].length;k++) { noFill(); stroke(0); rect(k*kante,i*kante,kante,kante); if(mat[i][k]%10==1) { fill(0,0,255); noStroke(); ellipse(k*kante+kante/2,i*kante+kante/2,kante,kante); } else if(mat[i][k]%10==2) { fill(0,255,0); noStroke(); ellipse(k*kante+kante/2,i*kante+kante/2,kante/2,kante/2); } else if(mat[i][k]%10==3) { fill(255,0,0); noStroke(); triangle(k*kante+kante/2,i*kante,k*kante,(i+1)*kante,(k+1)*kante,(i+1)*kante); } } } } void keyPressed() { if (key == CODED) { int x_alt = x_spieler; int y_alt = y_spieler; if (keyCode == UP) { y_spieler++; mat[y_spieler][x_spieler] = mat[y_alt][x_alt]; mat[y_alt][x_alt] = 0; } else if (keyCode == DOWN) { y_spieler--; mat[y_spieler][x_spieler] = mat[y_alt][x_alt]; mat[y_alt][x_alt] = 0; } else if (keyCode == LEFT) { x_spieler--; mat[y_spieler][x_spieler] = mat[y_alt][x_alt]; mat[y_alt][x_alt] = 0; } else if (keyCode == RIGHT) { x_spieler++; mat[y_spieler][x_spieler] = mat[y_alt][x_alt]; mat[y_alt][x_alt] = 0; } } else { } }
Code 0-6: Spiel003, Spieler bewegen.
Informatik -- Lehrveranstaltung vom 24.06.2024
Themen
|
1. Objektorientierte Entwicklung eines Arcade-Games
Nachdem in der vornagegangenen Lehrveanstaltung einige Erfahrung in der Entwicklung eines Spiels auf prozeduraler Ebene gewonnen wurde, soll nun das gleiche Spiel mit einem objektorientierten Ansatz entwickelt werden.
Dazu wird vorgeschlagen, eine Klasse "Spiellogik" ins Zentrum zu stellen, die das Spiel in seinem Ablauf und seinen Daten repräsentiert, jedoch keinerlei Visualisierung besitzt.
Um um ein Objekt vom Typ Spiellogik dann Benutzerinteraktion und Visualisierung drum herum aufzubauen, ergeben sich gewisse Anforderungen an die Klasse Spiellogik:
Es muss eine Reihe von Prüfmethoden geben, die zurück geben, ...
|
Das Spiel muss in einen Anfangszustand versetzt werden können und das Spiel sollte dann gestartet werden. Entsprechende Methoden könnten heißen:
|
Die beweglichen Gegner sollten über eine Methode von ihrer aktuellen Position aus in eine nachfolgende übergehen. Eine entsprechende Methode könnte heißen:
|
Schließlich sollte es eine Methode geben, die einen Zug des Spielers ermöglicht. Diese könnte so beschaffen sein, dass sie nur vollzogen wird, wenn der gewünschte Schritt möglich ist. Dann sollte sie true zurück geben, sonst false. Die möglichen Richtungen sollten durch Zahlen kodiert sein: nach rechts 1, nach links 2, nach oben 3, nach unten 4:
|
Insgesamt ergibt sich für die Klasse folgender vorläufiger Entwurf:
public class Spiellogik { int[][] mat;//Spielbrett int punkte; boolean verloren,gewonnen,laeuft; public Spiellogik(int kante, int anzahl_gegner, int anzahl_essen) { mat = new int[kante][kante]; } public void initialisieren() { punkte = 0; gewonnen = false; verloren = false; laeuft = false; } public void starten() { laeuft = true; } public void bewegeGegner() { } public boolean bewegeSpieler(int richtung) { } public boolean spielerHatGewonnen() { //alle Essen-Objekt sind weg, aber der Spieler ist noch da. } public boolean spielerHatVerloren() { //Der Spieler ist weg (gefressen von einem Gegner) } public boolean spielLaeuft() { } }
Code 0-7: (Unvollständiger) Entwurf der Klasse Spiellogik.
Neben den aufgeführten public-Methoden, kann es eine Reihe an private-Hilfsmethoden in Spiellogik geben, wie beispielsweise: private boolean koordinatenSindImSpielfeld(int zeile, int spalte).
Interaktion
|
Visualisierung
|
|
Eine fortgeschrittene Umsetzung könnte ein Interface iVis vorsehen, in dem festgelegt ist, dass alle Vis... Objekte eine Methode draw(...) besitzen. Alle diese Visualisierungsobjekte könnten dann ein einem Array gemerkt werden.
Schließlich sollte es eine Klasse Spielfeld geben, die in der Lage ist, die Spielsituation auf der Grundlage des Siellogik-Objektes darzustellen. Das Spielfeld-Objekt sollte als innere Objekte die Vis... Objekte besitzen.
Kodierung der Spielfiguren und -elemente in int[][] mat
|
Es sollen im Unterricht zunächst gemeinsam die folgenden Entwicklungsschritte angeschaut werden:


ÜBUNG
AUFGABE 13.1 -- Implementierung der Methode bewegeGegner()
Sorgen Sie zuerst als Vorübung dafür, dass immer die aktuelle Punktzahl angezeigt wird.
Die nachfolgende einfache objektorientierte Version des Arcade-Games ist fast vollständig:

Lediglich die Objektmethode bewegeGegner() in der Klasse Spiellogik muss noch implementiert werden.
|
AUFGABE 13.2 -- Spiel "aufpeppen"
Im Sinne der letzte Woche und heute gemachten Angaben soll die bereit gestellte Version des Spiels nun in freier Regie verbessert und verfeinert werden:
|
Mailen Sie mir gerne Ihre Varianten, um sie hier als studentische Lösungen bereit stellen zu können.
AUFGABE 13.3 -- eigenes Spiel
Überlegen Sie sich auf der Grundlage der bisher gemachten Erfahrungen ein eigenes Spiel, vielleicht eines, das auch für zwei Personen funktioniert.


Bild 0-2: Screenshot zu ArcadeOOP006.zip.
2. Beantwortung von Fragen zur anstehenden Klausur
public class Zahl { protected int x; public void setX(int x) { this.x = x; } } //Klasse ZahlB public class ZahlB extends Zahl { public int getX() { return this.x; } } public void setup() { Zahl z1 = new Zahl(); z1.setX(7); ZahlB z2 = new ZahlB(); z2.setX(5); System.out.println("z2="+z2.getX()); } public void draw() { }
Code 0-8: Minimales Beispiel für Vererbung.

Bild 0-3: Zugehöriges UML-Klassendiagramm.