Guten Tag allseits,
ich bin ein rechter Java-Neuling und versuche mich derzeit an einem Pong-Klon für ein Projekt - ich habe auch schon ein lauffähiges Applet produziert, mit 3 Klassen:
Leider habe ich das Konzept der Objektorientierung noch nicht so ganz durchdrungen und musste einige 'Krücken' einbauen (Übergabefunktionen in der Hauptklasse), damit ich die Position der Pads an die Klasse Ball übergeben und so eine Kollision ermitteln kann (und umgekehrt!). Die Kollisionsabfrage funktioniert zwar eher schlecht als recht, aber damit möchte ich mich später befassen.
Ich möchte auch noch eine separate Kollisionsklasse schreiben und die Ball-Klasse und die Hauptklasse vereinfachen, doch zunächst wollte ich eine 'Score'-Klasse zur Ermittlung der Punktestände einführen; nur bekomme ich leider 'NullPointerExceptions', wenn ich z.B. bei einer Kollision von einer Klasse heraus (Ball / ball1) eine statische Variable (playerScore1) in einer anderen Klasse (Score / gameScore) mit Hilfe einer Methode dieser Klasse (setGameScore()) um 1 erhöhen will (oder wenn ich aus der Score-Klasse heraus eine Methode der Ball-Klasse aufrufen will, die die Punkte von dort abruft):
Dieser Fehler tritt immer dann auf, wenn der Ball auf die linke oder rechte Spielgrenze (den Zeichenrahmen) trifft; seltsamerweise nur dann, wenn ich das Applet mit 'run file' direkt in Netbeans starte. Manchmal bleibt der Zeichenbereich dann auch weiß und es hagelt NullPointerExceptions -
nur bei einem view-Aufruf der 'index.html' mit Start im Browser funktionieren Applet und Punktezähler oberflächlich, wenn mir da nicht eine frühere Appletversion aus dem Cache einen Streich spielt, wobei ich den eigentlich gelöscht hatte...
Äußerst seltsam: nachdem ich vorgestern die Score-Klasse eingeführt hatte und der besagte Fehler aufgetreten war, habe ich abgebrochen und am nächsten Tag weitergemacht - wobei dann plötzlich kein Fehler mehr auftrat, aber nur die ersten paar Male mit Start im Browser!
Jedenfalls, hier einige Auszüge aus dem Code (entschuldigt bitte den 'Baustellen-Charakter'):
JApplePong.java (Hauptklasse)
Score.java
In dieser Version lasse ich die Punkte noch in der Ballklasse zählen und hole sie von dort ab, mit :
Ball.java
In einer neueren Version rufe ich bei Erhöhung der Spielpunkte in der Ballklasse nur eine Methode in der Scoreklasse auf:
'setPlayerScore(gameScore,1);'
[/code]
Wobei ich im Deklarationsteil der Ballklasse ein Referenzvariable auf das Exemplar 'gameScore' der Scoreklasse Bezug nehme:
Und ich nehme an, dass genau hier mein Denkfehler liegt; jedenfalls scheint bei beiden Versionen ein Verweis auf eine leere Referenz stattzufinden, wenn ich das richtig sehe - meine Funktionsaufrufe zeigen nicht auf das richtige Exemplar der Klasse...?
Die zentrale Frage: wie schaffe ich es, dass ich von anderen Klassen auf das richtige Exemplar meiner Nebenklassen (ball1, pad1, gameScore,...) und dort auf die gewünschten Objekte / Methoden zugreifen kann?
Weitere Problemchen:
Ich dachte mir, es wäre vielleicht im Sinne der Performance besser, alle Zeichen-Funktionen aus den Nebenklassen ganz herauszunehmen und nur relevante Werte für die Hauptklasse bereitzustellen - dann könnte ich mir u.a. die Übermittlung der 'Graphics2D'-Objkte sparen, doch ich glaube für den besagten Fehler oben ist eher eine fehlerhafte Zugriffsmethode auf klassenfremde Objekte verantwortlich...?
Derzeit kann ich keine 'gewonnen/verloren'-Meldung auf dem Bildschirm darstellen, während der Ball mit Thread.sleep() eingefroren wird (weil auch die Text-Zeichnung angehalten wird?), außerdem wird Punktestand '5' nicht mehr angezeigt.
Wenn ich das richtig erkannt habe, wäre mit der 'Shape'-Klasse eine weitaus sicherere Kollisionserkennung möglich; derzeit muss ich sogar zweimal Prüfen, in der Ball- und in der Padklasse (falls die Maus schneller als der Ball ist). Aber mit einer gesonderten Kollisionsklasse wäre das vielleicht auch nicht das Thema.
Momentan springt der Ball vom oberen und unteren Padrand manchmal in gleicher Richtung zurück und 'gleitet' vor allem an der Ober- und Unterkante der Pad entlang, statt abzuprallen.
Beim Start im Browser hat die System.exit()-Funktion keine Wirkung, bzw. das Spiel bricht nicht ab.
Der Mauszeiger bleibt immer sichtbar (auf Höhe des oberen Padrandes), was sehr irritierend wirkt und 'Hänger' beim Ein- und Austreten des Zeigers aus dem Zeichebereich zur Folge hat
Ich bin für jede Hilfe dankbar, vor allem zu meinem zentralen Problem des richtigen Objektzugriffs auf klassenfremde Objekte und Variablen!!
Vielen Dank im Voraus,
milchkaffee[/quote]
ich bin ein rechter Java-Neuling und versuche mich derzeit an einem Pong-Klon für ein Projekt - ich habe auch schon ein lauffähiges Applet produziert, mit 3 Klassen:
JApplePong (Hauptklasse)
Ball -> ball1 (zeichnet und bewegt Ball und beinhaltet Kollisionsabfrage)
Pad -> pad1 (zeichnet Spielpads und bewegt linken Pad mittels Mouse und rechten Pad automatisch)
Leider habe ich das Konzept der Objektorientierung noch nicht so ganz durchdrungen und musste einige 'Krücken' einbauen (Übergabefunktionen in der Hauptklasse), damit ich die Position der Pads an die Klasse Ball übergeben und so eine Kollision ermitteln kann (und umgekehrt!). Die Kollisionsabfrage funktioniert zwar eher schlecht als recht, aber damit möchte ich mich später befassen.
Ich möchte auch noch eine separate Kollisionsklasse schreiben und die Ball-Klasse und die Hauptklasse vereinfachen, doch zunächst wollte ich eine 'Score'-Klasse zur Ermittlung der Punktestände einführen; nur bekomme ich leider 'NullPointerExceptions', wenn ich z.B. bei einer Kollision von einer Klasse heraus (Ball / ball1) eine statische Variable (playerScore1) in einer anderen Klasse (Score / gameScore) mit Hilfe einer Methode dieser Klasse (setGameScore()) um 1 erhöhen will (oder wenn ich aus der Score-Klasse heraus eine Methode der Ball-Klasse aufrufen will, die die Punkte von dort abruft):
Exception in thread "AWT-EventQueue-1" java.lang.NullPointerException
at jApplets.pong.Ball.setPlayerScore(Ball.java:93)
at jApplets.pong.Ball.bewege(Ball.java:471)
at jApplets.pong.JApplePong$gScreen.paintComponent(JApplePong.java:190)
at javax.swing.JComponent.paint(JComponent.java:1027)
at javax.swing.JComponent.paintChildren(JComponent.java:864)
at javax.swing.JComponent.paint(JComponent.java:1036)
.
.
Dieser Fehler tritt immer dann auf, wenn der Ball auf die linke oder rechte Spielgrenze (den Zeichenrahmen) trifft; seltsamerweise nur dann, wenn ich das Applet mit 'run file' direkt in Netbeans starte. Manchmal bleibt der Zeichenbereich dann auch weiß und es hagelt NullPointerExceptions -
nur bei einem view-Aufruf der 'index.html' mit Start im Browser funktionieren Applet und Punktezähler oberflächlich, wenn mir da nicht eine frühere Appletversion aus dem Cache einen Streich spielt, wobei ich den eigentlich gelöscht hatte...
Äußerst seltsam: nachdem ich vorgestern die Score-Klasse eingeführt hatte und der besagte Fehler aufgetreten war, habe ich abgebrochen und am nächsten Tag weitergemacht - wobei dann plötzlich kein Fehler mehr auftrat, aber nur die ersten paar Male mit Start im Browser!
Jedenfalls, hier einige Auszüge aus dem Code (entschuldigt bitte den 'Baustellen-Charakter'):
JApplePong.java (Hauptklasse)
Code:
public class JApplePong extends javax.swing.JApplet {
/* Deklaration der Variablen, Objekte und Klassen
*
*/
// Variablen festlegen
int screenXMax, screenYMax, screenXMin = 0, screenYMin = 0;
int playerScore1, playerScore2;
boolean startup = true;
private boolean debug = false;
// Deklaration des Animations-Threadobjekts 'ballAnimeThread'
AnimeThread ballAnimeThread;
// Deklaration/Erzeugung der grafischen Klassenobjekte
Score gameScore;
Ball ball1;
Pad pad1 = new Pad(50, 50, 10, 90);
Pad pad2 = new Pad(310, 50, 10, 90);
// Rendering auf Antialiasing setzen
RenderingHints rh = new RenderingHints(
RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// Thread-Klasse 'AnimeThread' - für Animation
private class AnimeThread extends Thread {
@Override
public void run() {
// Neuzeichnen der Zeichenobjekte in einer Endlosschleife
// mit Verzögerung von (x)ms
while (true) {
if (Thread.interrupted()) break;
repaint();
pause(18);
}
}
}
@Override
public void init() {
try {
java.awt.EventQueue.invokeAndWait(new Runnable() {
public void run() {
initComponents();
gScreen.requestFocus();
}
});
// 'ballAnimeThread'-Threadobjekt erzeugen starten
// (neuer Thread mit minimaler Priorität für min. CPU-Last)
ballAnimeThread = new AnimeThread();
ballAnimeThread.setPriority(Thread.MIN_PRIORITY);
ballAnimeThread.start();
}
catch (Exception ex) { ex.printStackTrace(); }
}
// Deklaration der erweiterten JPanel-Klasse 'gScreen' (incl. Maus-Listener)
private class gScreen extends JPanel implements MouseMotionListener {
@Override
/** automatisches Auffrischen der graphischen Komponenten
* mittels Aufruf der Funktion 'paintComponent' bzw.
* durch Überschreiben ihrer Superklasse mit 'g'
*/
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// Rendering mit Antialiasing für bessere Zeichenqualität und flüssige Animation
g2.setRenderingHints(rh);
super.paintComponent(g2);
// Initilisierung
if ( startup == true ) {
// Hintergrundfarbe setzen und Grenzen des Zeichenrahmens ermitteln
// des Zeichenrahmens mit Einrechnung des Ballradius + 1
gScreen.setBackground(Color.darkGray);
screenXMax = getWidth();
screenYMax = getHeight();
// Erzeuge Ball-Objekt 1
ball1 = new Ball((int)screenXMax/2, (int)screenYMax/2, 30);
//ball1.resetBall();
gameScore = new Score(screenXMin, screenYMin, screenXMax, screenYMax);
// Hinzufügen von Mausbewegungs-Listener für aktuelle Klasse
addMouseMotionListener(this);
startup = false;
}
// Anzeige der Spielerpunkte
//playerScore1 = ball1.getPlayerScore(1);
//playerScore2 = ball1.getPlayerScore(2);
gameScore.countScores(g2); [b][color=red]<<<<<<<<<<< Fehlerquelle[/color][/b]
// Textmeldung in graphische Komponente 'g2' schreiben
g2.drawString("\nPick and drag the ball via mouse - \n" +
"Hit SPACE to exit.", (int)screenXMax/2 - 150, (int)screenYMax - 20);
// Zeichnen der Objekte
pad1.setPadStops(screenYMin,screenYMax);
pad2.setPadStops(screenYMin,screenYMax);
pad2.setPadStartPos(screenXMax - 50, (int)screenYMax/2);
pad1.zeichne(g2);
pad2.zeichne(g2);
ball1.setBorders(screenXMin, screenXMax, screenYMin, screenYMax);
ball1.zeichne(g2);
ball1.bewege(g2);
// Krücken:
// ball1.receivePad (hole aktuelles Pad aus pad1 und reiche an ball1 weiter)
// ball1.receivePad(pad1.getPadLB(), pad1.getPadUB(), pad1.getPadW(), pad1.getPadH());
ball1.receivePad1(pad1.getPad()[0], pad1.getPad()[1], pad1.getPad()[2], pad1.getPad()[3]);
ball1.receivePad2(pad2.getPad()[0], pad2.getPad()[1], pad2.getPad()[2], pad2.getPad()[3]);
//pad1.receiveBall(ball1.getBall()[0], ball1.getBall()[1], ball1.getBall()[2], ball1.getBall()[3], ball1.getBall()[4]);
pad2.receiveBall(ball1.getBall()[0], ball1.getBall()[1], ball1.getBall()[2], ball1.getBall()[3], ball1.getBall()[4]);
//pad1.receivePadBounce(ball1.getPadBounce()[0], ball1.getPadBounce()[1]);
//pad2.receivePadBounce(ball1.getPadBounce()[0], ball1.getPadBounce()[1]);
pad1.receivePadBounce(ball1.isCollision(1)[2], ball1.isCollision(1)[3]);
pad2.receivePadBounce(ball1.isCollision(2)[2], ball1.isCollision(2)[3]);
pad2.botPlayer();
.
.
Score.java
Code:
public class Score {
int screenXMax, screenYMax, screenXMin = 0, screenYMin = 0;
int playerScore1, playerScore2;
Ball ball1;
Pad pad1;
Score(int screenXMin, int screenYMin, int screenXMax, int screenYMax) {
this.screenXMin = screenXMin;
this.screenYMin = screenYMin;
this.screenXMax = screenXMax;
this.screenYMax = screenYMax;
}
void countScores( Graphics2D g2 ) {
//playerScore1 = ball1.getPlayerScore(1);
//playerScore2 = ball1.getPlayerScore(2);
playerScore1 = ball1.getPlayerScore(1); [b][color=darkred]<<<<<<<<<<<<<< Fehlerquelle[/color][/b]
playerScore2 = ball1.getPlayerScore(2); [b][color=red]<<<<<<<<<<<<<< Fehlerquelle[/color][/b]
g2.setColor(Color.WHITE);
g2.drawString("Punkte Spieler: " + playerScore1, screenXMin + 10, screenYMin + 50);
g2.drawString("Punkte Computer: "+ playerScore2, screenXMax - 120, screenYMin + 50);
//g2.drawString("Sie haben verloren.", ((int)screenXMax/2) - 50, (int)screenYMax/2);
//System.out.println(Thread.currentThread().getName());
if (playerScore1 == 5 || playerScore2 == 5) {
//try {
if (playerScore1 == 5) {
g2.drawString("Punkte Spieler: " + playerScore1, screenXMin + 10, screenYMin + 50);
g2.drawString("Sie haben gewonnen!", ((int)screenXMax/2) - 50, (int)screenYMax/2);
//pause(1500);
System.out.println("P1scored");
}
if (playerScore2 == 5) {
g2.drawString("Punkte Computer: " + playerScore2, screenXMax - 120, screenYMin + 50);
g2.drawString("Sie haben verloren.", ((int)screenXMax/2) - 50, (int)screenYMax/2);
//pause(1500);
System.out.println("P2scored");
}
//Thread.sleep(1500);
//pause(1500);
ball1.resetPlayerScores();
ball1.resetBall();
//}
//catch (InterruptedException e) {}
}
}
In dieser Version lasse ich die Punkte noch in der Ballklasse zählen und hole sie von dort ab, mit :
Ball.java
Code:
.
.
class getPlayerScore {
public int getPlayerScore(int ply) {
int ps = 0;
if (ply == 1) ps = playerScore1;
else if (ply == 2) ps = playerScore2;
return ps;
}
}
.
.
'setPlayerScore(gameScore,1);'
[/code]
Wobei ich im Deklarationsteil der Ballklasse ein Referenzvariable auf das Exemplar 'gameScore' der Scoreklasse Bezug nehme:
Code:
Score gameScore;
Und ich nehme an, dass genau hier mein Denkfehler liegt; jedenfalls scheint bei beiden Versionen ein Verweis auf eine leere Referenz stattzufinden, wenn ich das richtig sehe - meine Funktionsaufrufe zeigen nicht auf das richtige Exemplar der Klasse...?
Die zentrale Frage: wie schaffe ich es, dass ich von anderen Klassen auf das richtige Exemplar meiner Nebenklassen (ball1, pad1, gameScore,...) und dort auf die gewünschten Objekte / Methoden zugreifen kann?
Weitere Problemchen:
Ich dachte mir, es wäre vielleicht im Sinne der Performance besser, alle Zeichen-Funktionen aus den Nebenklassen ganz herauszunehmen und nur relevante Werte für die Hauptklasse bereitzustellen - dann könnte ich mir u.a. die Übermittlung der 'Graphics2D'-Objkte sparen, doch ich glaube für den besagten Fehler oben ist eher eine fehlerhafte Zugriffsmethode auf klassenfremde Objekte verantwortlich...?
Derzeit kann ich keine 'gewonnen/verloren'-Meldung auf dem Bildschirm darstellen, während der Ball mit Thread.sleep() eingefroren wird (weil auch die Text-Zeichnung angehalten wird?), außerdem wird Punktestand '5' nicht mehr angezeigt.
Wenn ich das richtig erkannt habe, wäre mit der 'Shape'-Klasse eine weitaus sicherere Kollisionserkennung möglich; derzeit muss ich sogar zweimal Prüfen, in der Ball- und in der Padklasse (falls die Maus schneller als der Ball ist). Aber mit einer gesonderten Kollisionsklasse wäre das vielleicht auch nicht das Thema.
Momentan springt der Ball vom oberen und unteren Padrand manchmal in gleicher Richtung zurück und 'gleitet' vor allem an der Ober- und Unterkante der Pad entlang, statt abzuprallen.
Beim Start im Browser hat die System.exit()-Funktion keine Wirkung, bzw. das Spiel bricht nicht ab.
Der Mauszeiger bleibt immer sichtbar (auf Höhe des oberen Padrandes), was sehr irritierend wirkt und 'Hänger' beim Ein- und Austreten des Zeigers aus dem Zeichebereich zur Folge hat
Ich bin für jede Hilfe dankbar, vor allem zu meinem zentralen Problem des richtigen Objektzugriffs auf klassenfremde Objekte und Variablen!!
Vielen Dank im Voraus,
milchkaffee[/quote]