Daher habe ich bei C++ eine Pause eingelegt und teste jetzt Java.
Mein erster Eindruck. Seinen persönlichen Level erreicht man relativ schnell.
Kann ich mich in Java ableveln, wird die Rückkehr nach C++ nicht so schwer sein.
Wichtiger ist es für mich, endlich einmal Grafikspiele zu entwickeln.
Als Spielthema habe ich mir etwas Einfaches ausgesucht. Sätze raten.
In der ersten Version wird der Quellcode nur das Wesentlichste haben.
Hier kann man die Codezeilen noch gut zählen.
Für mich ist es bei diesem Thread wichtig, darauf hinzuweisen:
dass ich als Hobbyist für Einsteiger schreibe und
die Hoffnung habe, dass die Profis hier Impulse setzen können, damit ich auch etwas davon habe.
Es geht los. Geschrieben habe ich es auf Eclipse unter Java 7.0.
Der eigentliche Quelltext ist in der Klasse SaetzeRaten. Mit der StartMain wird das Spiel nur gestartet. So besteht die Möglichkeit, dass Spiel einfach in eine Spielsammlung zu integrieren.
Code: Alles auswählen
public class StartMain {
public static void main(String[] args) {
// Kontrollmeldung auf der Konsole
System.out.println("Sätze raten; Start");
// mit new wird immer ein Objekt erzeugt.
// Eine Referenzvariable brauchen wir nicht
// Kommen wir nach main zurück, ist das Spiel zu Ende
new Satzraten();
// Kontrollmeldung auf der Konsole
System.out.println ("Sätze raten; Ende");
}
}
Dies stellt Java standardmäßig zur Verfügung. Dafür müssen wir swing importieren und daraus aus der Klasse JFrame ableiten. Da wir alles geerbt haben, müssen nur noch einige Paramter gesetzt werden:
Code: Alles auswählen
import javax.swing.*;
public class Satzraten extends JFrame {
// Konstruktor, der Einstiegspunkt dieser Klasse
public Satzraten () {
super("Rate den Satz");
setSize(600, 400);
setLocation(200, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
}
Also copy / paste und dann starten.
Ein leeres Fenster erscheint. Mit „super“ wird der Konstruktor der abgeleiteten Klasse aufgerufen und gleichzeitig der Text hinterlegt. Dies muss immer der erste Aufruf im Konstruktor sein. Wir hätten es hier auch weglassen können und stattdessen setTitle („Rate den Satz“); setzen können.
Danach wird die Größe des Fensters festgelegt.
Lokalisiert wird das Fenster in Pixel vom Bildschirm obenlinks.
Das weiße Kreuz auf rotem Rechteck schließt in der Regel das Window. Das passiert bei unserem Fenster nur, wenn wir die Close-Methode mit dem Merkmal EXIT_ON_CLOSE aufrufen. Ansonsten lässt sich das Fenster nur mit Ctrl C schließen oder Eclipse muss geschlossen werden.
Zuletzt wird das Fenster auf „sichtbar“ gestellt.
Als nächstes werden wir einige Labels und Buttons placieren. Wobei das Plazieren ein Thema für sich ist. In Java gibt es verschiedene Layout-Manager, die alle mehr oder weniger steuerbar sind. Das heißt, man gibt je nach Verwendung vor, nach welchem Stil die Komponenten auf das Fenster gelegt werden.
Ein Layout wird nicht direkt ins Fenster gesetzt, sondern man benutzt Container. In unserem Fall werden wir aus swing das „JPanel“ benutzen.
Ein JPanel kann beliebig viele verschiedene Komponenten aufnehmen und auch geschachtelt werden. Daher lege ich erst einmal Hauptpanel an, in der die anderen Panels eingebunden werden.
Mit new wird das Panelobjekt erzeugt. Damit es sichtbar ist, muss es zu unserem Fenster hinzugefügt werden. Da wir im Konstruktor sind, wird mit this auf dieses Fenster verwiesen und mit add zugefügt. Diese Vorgehensart gilt für alle Komponenten.
Code: Alles auswählen
JPanel hauptPanel = new JPanel ();
this.add(hauptPanel);
Der Konstruktor ist für die Erzeugung des Objektes zuständig. Damit es übersichtlich bleibt, lagern wir den Code für die Komponenten aus. Anstatt
JPanel topPanel = new JPanel ();
Schreiben wir:
Code: Alles auswählen
topPanel = initTopPanel();
hauptPanel.add(topPanel);
Code: Alles auswählen
private JPanel initTopPanel () {
JPanel panel = new JPanel ();
GridLayout gridLayout = new GridLayout(3,1,10,10);
panel.setLayout(gridLayout);
lblTitel = new JLabel ("Rate den Satz");
panel.add(lblTitel);
lblSatztafel = new JLabel (satzKodiert);
panel.add(lblSatztafel);
return panel;
}
Code: Alles auswählen
// Instanzvariable
JPanel topPanel;
JLabel lblTitel;
JLabel lblSatztafel;
String satzKodiert = " ";
Mit return geht es zum Konstruktor zurück. Die Referenz wird der Variablen topPanel übergeben und das hauptpanel übernimmt es mit add.
Wenn wir jetzt erneut das Programm starten, sehen wir die erste Komponente.
Weiter geht’s mit dem nächsten panel:
Code: Alles auswählen
Im Konstruktor fügen wir wie gehabt hinzu.
spielPanel = initspielPanel();
hauptPanel.add(spielPanel);
Code: Alles auswählen
private JPanel initspielPanel () {
JPanel panel = new JPanel ();
GridLayout gridLayout = new GridLayout(3,10,10,10);
panel.setLayout(gridLayout);
azbutton = new JButton [26];
char c;
for (int i = 0; i < 26; i++) {
c = (char) (i+65);
System.out.println(i + " " + c);
azbutton[i] = new JButton(String.valueOf(c) );
azbutton[i].addActionListener(lauscher);
panel.add(azbutton[i]);
}
Code: Alles auswählen
JPanel spielPanel;
JButton [] azbutton;
char [] arrKodiert; // brauchen wir etwas später
char [] arrKlar; // brauchen wir etwas später
Jetzt ist es wichtig, die Funktionalität panel mit Komponenten anlegen, verstanden wurde.
Denn hier kommen noch einige Sachen neu hinzu.
Ein char-Array für die 26 Buchstaben wird erzeugt. Da char-Zeichen im ASCII in Form von Integerzahlen hinterlegt sind (A = 65 … Z =91) habe ich in der for-Schleife pro Schleifengang die entsprechende ASCII-Codierung erzeugt und durch das char in Klammern in ein char-Zeichen gewandelt.
Als Test lasse ich es in der Konsole ausgeben.
Die nächste Zeile füllt das Array. Da JButton kein char als Text akzeptiert, nach String geparst.
Testen ist angesagt. Kommentiere die Zeile
// azbutton.addActionListener(lauscher);
zwecks Test aus. Dann sollte das Programm laufen. Danach die Kommentierung wieder entfernen.
Jetzt kommt der interessante Teil: der Lauscher. Will man, dass bei Tastendruck der A-Z Schalter etwas passiert, müssen Rahmenbedingungen gesetzt werden.
Die Komponente wie zum Beispiel unser button muss die Lauscherfähigkeit haben,
Jeder einzelne button muss ein Lauscher haben, dies geschieht durch den ActionListener.
Das Gehörte muss verarbeitet werden. Das passiert mit Hilfe des ActionEvent
ActionEvent und ActionListener müssen importiert werden.
Code: Alles auswählen
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
Code: Alles auswählen
// Innere Klasse
private final class SchalterLauscher implements ActionListener {
public void actionPerformed (ActionEvent e) {
String s;
s = e.getActionCommand();
char ch = s.charAt(0);
System.out.println("s String: " + s);
System.out.println("ch Zeichen: " + ch);
entkodieren(ch);
System.out.println("ch Zeichen: " + ch);
System.out.println("ch+26 Zeichen: " + (ch+32));
}
private void entkodieren(char c) {
for ( int i = 0; i < arrKodiert.length; i++) {
if ( (arrKlar[i] == c) || (arrKlar[i] == (c+32) ) ) {
arrKodiert[i] = arrKlar[i];
}
}
satzKodiert = "";
for ( int i = 0; i < arrKodiert.length; i++) {
satzKodiert = satzKodiert + arrKodiert [i];
}
System.out.println("satzKodiert: " + satzKodiert);
lblSatztafel.setText(satzKodiert);
}
} // Ende innere Klasse
Zuerst erzeugen wir ein Objekt der inneren Klasse, siehe bei den Instanzvariablen
Wir müssen bei der inneren Klasse den ActionListener implementieren und zwingend die Methode actionPerformed erstellen, sonst gibt es Fehlermeldungen.
Wenn wir jetzt das Programm starten, läuft es, bis wir eine Taste drücken. Es passiert was.
Leider nichts gutes, nur Fehlermeldungen. Es fehlen Programmteile, also abwarten.
Zurück zur Methode actionPerformed.
Die Methode stellt Infos über das button-klicken zur Verfügung. In dem String s lasse ich mir angeben, welche Taste gedrückt wurde.
Da es immer nur ein Zeichen ist, habe ich es als char mit der nächsten Zeile ausgelesen.
Es kommen Kontrollprints auf der Konsole.
Mit der Buchstabentaste wurde konkret ein Buchstabe gedrückt. Dieser Buchstabe wird als char-Zeichen der Methode entkodieren(ch) übergeben. Es gibt noch einmal einen Kontrollausdruck und die Methode actionPerformed ist abgearbeitet.
Jetzt zur Methode entkodieren()
Wir durchlaufen mittels for-Schleife den kodierten Array. Kodiert bedeutet, alle Buchstaben wurden durch ein Stern ersetzt. Die anderen Zeichen wie Punkt, Komma usw. bleiben wie sie sind. Jedesmal, wenn der gedrückte Buchstabe im Satz vorkommt, wird in if verzweigt. Aus dem Klarsatz wird der entsprechende Groß- oder Kleinbuchstabe entnommen und bei dem kodierten Satz gegen das Sternchen ausgetauscht.
Wir sind schon ganz schön weit. Viel fehlt nicht mehr.
Im Konstruktor fehlt uns nur noch eine Zeile:
Code: Alles auswählen
spielschleife();
Code: Alles auswählen
private void spielschleife() {
System.out.println("Start der Spielschleife");
kodiereSatz();
lblSatztafel.setText(satzKodiert);
Der Printbefehl ist nur zur Kontrolle da. Alle Printbefehle können bei Funktionsfähigkeit gelöscht werden.
Die Methode kodiereSatz wird aufgerufen.
Code: Alles auswählen
private void kodiereSatz() {
arrKlar = new char[satzKlar.length()];
arrKodiert = new char[satzKlar.length()];
//aus String den Array erzeugen
for ( int i = 0; i < satzKlar.length(); i++) {
arrKlar[i] = satzKlar.charAt(i);
}
// Die Kodierung durchführen
for ( int i = 0; i < satzKlar.length(); i++) {
if ( ( (arrKlar[i] < 91 ) && (arrKlar[i] > 64) ) ||
( (arrKlar[i] < 123) && (arrKlar[i] > 96) ) ) {
arrKodiert[i] = '*';
}
else {
arrKodiert[i] = arrKlar[i];
}
}
// kodierten String erzeugen
satzKodiert = "";
for ( int i = 0; i < arrKodiert.length; i++) {
satzKodiert = satzKodiert + arrKodiert [i];
}
System.out.println("satzKodiert: " + satzKodiert);
lblSatztafel.setText("satzKodiert");
}
Mit der zweiten for-Schleife wird im kodierten Array mit einer if-Verzweigung jeder Buchstabe in ein Sternchen gewandelt.
Jetzt sind wir mit der Basisversion fertig. Aus meiner Sicht haben wir ein ablauffähiges Programm. Wenn man jetzt einen anderen Ratesatz will, muss man den neuen Satz im String satzklar hinterlegen.
Im ersten Durchgang wollte ich nur die Spiellogik darlegen. Mit 160 Codezeilen ist das Wesentliche realisiert. Wir haben eine Grafikanwendung mit Nachrichtenaustausch.
Um es als Spiel zu bezeichnen, fehlt noch der zu schaffende Spielreiz und Service wie ein Satzarchiv und viel Kosmetik.
Wenn alles umgesetzt werden soll, wird sich das Codevolumen um einiges steigern.
Zum Schluss möchte ich noch einmal darauf hinweisen, dass ich es als Hobby betreibe und es als Anregung für Einsteiger gedacht ist.
Wenn sich jemand die Zeit nimmt, es durchzugehen, würde ich mich um eine ehrliche Antwort freuen (es sei denn, es kommt knüppeldick).
Wenn Profis sich die Zeit nehmen, Verbesserungen am bestehenden Code zu formulieren, wäre es Klasse.
Daher noch einmal der Code komplett:
Code: Alles auswählen
import java.awt.GridLayout;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Satzraten extends JFrame{
// Instanzvariable
JPanel topPanel;
JPanel spielPanel;
JLabel lblTitel;
JLabel lblSatztafel;
String satzKlar = "Du interessierst dich fuer Spieleentwicklung? Besuche ZFX developia!";
String satzKodiert = " ";
char [] arrKodiert;
char [] arrKlar;
JButton [] azbutton;
// Ein Objekt der inneren Klasse erzeugen
SchalterLauscher lauscher = new SchalterLauscher();
// Konstruktor, der Einstiegspunkt dieser Klasse
public Satzraten () {
super("Die Basisversion, Funktionalität ist gegeben");
setSize(600, 400);
setLocation(200, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
JPanel hauptPanel = new JPanel ();
this.add(hauptPanel);
topPanel = initTopPanel();
hauptPanel.add(topPanel);
spielPanel = initspielPanel();
hauptPanel.add(spielPanel);
spielschleife();
}
private JPanel initTopPanel () {
JPanel panel = new JPanel ();
GridLayout gridLayout = new GridLayout(3,1,10,10);
panel.setLayout(gridLayout);
lblTitel = new JLabel ("Rate den Satz");
panel.add(lblTitel);
lblSatztafel = new JLabel (satzKodiert);
panel.add(lblSatztafel);
return panel;
}
private JPanel initspielPanel () {
JPanel panel = new JPanel ();
GridLayout gridLayout = new GridLayout(3,10,10,10);
panel.setLayout(gridLayout);
azbutton = new JButton [26];
char c;
for (int i = 0; i < 26; i++) {
c = (char) (i+65);
System.out.println(i + " " + c);
azbutton[i] = new JButton(String.valueOf(c) );
azbutton[i].addActionListener(lauscher);
panel.add(azbutton[i]);
}
return panel;
}
private void spielschleife() {
System.out.println("Start der Spielschleife");
kodiereSatz();
lblSatztafel.setText(satzKodiert);
}
private void kodiereSatz() {
arrKlar = new char[satzKlar.length()];
arrKodiert = new char[satzKlar.length()];
//aus String den Array erzeugen
for ( int i = 0; i < satzKlar.length(); i++) {
arrKlar[i] = satzKlar.charAt(i);
}
// Die Kodierung durchführen
for ( int i = 0; i < satzKlar.length(); i++) {
if ( ( (arrKlar[i] < 91 ) && (arrKlar[i] > 64) ) ||
( (arrKlar[i] < 123) && (arrKlar[i] > 96) ) ) {
arrKodiert[i] = '*';
}
else {
arrKodiert[i] = arrKlar[i];
}
}
// kodierten String erzeugen
satzKodiert = "";
for ( int i = 0; i < arrKodiert.length; i++) {
satzKodiert = satzKodiert + arrKodiert [i];
}
System.out.println("satzKodiert: " + satzKodiert);
lblSatztafel.setText("satzKodiert");
}
// Innere Klasse
private final class SchalterLauscher implements ActionListener {
public void actionPerformed (ActionEvent e) {
String s;
s = e.getActionCommand();
char ch = s.charAt(0);
System.out.println("s String: " + s);
System.out.println("ch Zeichen: " + ch);
entkodieren(ch);
System.out.println("ch Zeichen: " + ch);
System.out.println("ch+26 Zeichen: " + (ch+32));
}
private void entkodieren(char c) {
for ( int i = 0; i < arrKodiert.length; i++) {
if ( (arrKlar[i] == c) || (arrKlar[i] == (c+32) ) ) {
arrKodiert[i] = arrKlar[i];
}
}
satzKodiert = "";
for ( int i = 0; i < arrKodiert.length; i++) {
satzKodiert = satzKodiert + arrKodiert [i];
}
System.out.println("satzKodiert: " + satzKodiert);
lblSatztafel.setText(satzKodiert);
}
} // Ende innere Klasse
}
public class StartMain {
public static void main(String[] args) {
// Kontrollmeldung auf der Konsole
System.out.println("Sätze raten; Start");
// mit new wird immer ein Objekt erzeugt.
// Eine Referenzvariable brauchen wir nicht
// Kommen wir nach main zurück, ist das Spiel zu Ende
new Satzraten();
// Kontrollmeldung auf der Konsole
System.out.println ("Sätze raten; Ende");
}
}
Terep