# Pong - noch 2 kleinere Probleme



## Neolity (18. Jan 2007)

Hallo,

ich habe angefangen mich mit Threads zu beschäftigen und im Zuge dessen wollte ich ein kleines Pong Spiel programmieren.

Dieses besteht aus 3 Klassen:

schlaeger.java:


```
import java.awt.*;

/*
Florian Quinkert, 16.01.06

Klasse schlaeger.java:
In dieser Klasse wird ein Schlaeger für ein Pong Spiel implementiert.
Dem Konstruktor wird durch die Variablen a und b die Position des Schlaegers
mitgeteilt.
*/
class schlaeger
{
	public int x = 10;
	public int y = 100;
	public int y_alt = 100;
	final int breite = 10;
	final int hoehe = 75;

	schlaeger(int a, int b)
	{		
		x = a;
		y = b;
		y_alt = y;
	}
	
	void getUp()
	{
		if (y > 40)
		{
			y_alt = y;
			y -= 10;
		}
	}

	void getDown()
	{
		if (y < 673)
		{
			y_alt = y;
			y += 10;
		}
	}
	
	public void paint(Graphics g)
	{
		g.clearRect(x, y_alt, breite, hoehe);
		g.fillRect(x, y, breite, hoehe);
	}
}
```

ball.java:


```
import java.awt.*;

/*
Florian Quinkert, 17.01.07

Klasse ball.java:
Diese Klasse definiert einen Ball fuer ein Pong Spiel. Außerdem wird durch eine 
Methode die veraenderte Flugrichtung des Balls bei einer Wandberuehrung bestimmt.
*/
class ball extends Thread
{
	private int x = 510;
	private int x_alt = 512;
	private int y = 385;
	private int y_alt = 384;
	private int breite = 10;
	private int hoehe = 10;
	private int aender_x = 5;
	private int aender_y = 5;
	
	private Fenster f;
	
	ball()
	{
	}
	
	public void run()
	{
		for (int i = 0; i < 10000; i++)
		{
			x_alt = x;
			y_alt = y;
			aenderungBestimmen();
			x += aender_x;
			y += aender_y;
			try
			{
				sleep(40);
			}
			catch (InterruptedException IE)
			{
			}
		}
	}
	
	private void aenderungBestimmen()
	{
		if (y == 745)
		{
			aender_y = -5;
		}
		if (x == 1000)
		{
			aender_x = -5;
		}
		if (y == 85)
		{
			aender_y = 5;
		}
		if (x == 10)
		{
			aender_x = 5;
		}
	}
	
	public void paint(Graphics g)
	{
		g.clearRect(x_alt, y_alt, breite, hoehe);
		g.fillRect(x, y, breite, hoehe);
	}
}
```

und Fenster.java:


```
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/*
Florian Quinkert, 16.01.07

Klasse Fenster.java:
Diese Klasse erstellt das Fenster mit einer Größe von 1024 * 768 Pixeln.
Außerdem werden in dieser Klasse die Schlaeger gezeichnet und auf Bewegungen
reagiert.
*/
class Fenster extends JFrame
implements Runnable
{
	schlaeger sl;
	schlaeger sr;
	ball b;
	
	int i = 1;
	Fenster()
	{
		super("Pong");
		
		new Thread(this).start();
		
		sl = new schlaeger(10, 100);
		sr = new schlaeger(1000, 100);
		b = new ball();
		b.start();
		
		setSize(1024,768);

		addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent we)
			{
				System.exit(0);
			}
		});
		addKeyListener(new KeyAdapter()
		{
			public synchronized void keyPressed(KeyEvent ke)
			{
				// 1. Schlaeger
				if (ke.getKeyCode() == KeyEvent.VK_W)
				{
					sl.getUp();
				}
				if (ke.getKeyCode() == KeyEvent.VK_S)
				{
					sl.getDown();
				}
		
				// 2. Schlaeger
				if (ke.getKeyCode() == KeyEvent.VK_UP)
				{
					sr.getUp();
				}
				if (ke.getKeyCode() == KeyEvent.VK_DOWN)
				{
					sr.getDown();
				}		
			}
		});
		setVisible(true);	
	}
	
	public void run()
	{
		while (i == 1)
		{
			repaint();
			try
			{
				Thread.sleep(10);
			}
			catch (InterruptedException ie)
			{
			}
		}
	}

	public void paint(Graphics g)
	{
		sl.paint(g);
		sr.paint(g);		
		b.paint(g);
	}

	public static void main(String[] args)
	{
		Fenster f = new Fenster();
	}	
}
```

Zum einen fehlt natürlich noch jegliche Spiellogik (Abprallen, Punkte zählen etc.), doch mein Problem liegt woanders. Der Ball läuft nun in einem eigenen Thread und man kann während der Ball läuft die Schläger bewegen. Bewege ich jedoch einen Schläger und kurz danach den 2. dann bricht die Bewegung des ersten Schlägers ab, obwohl ich die Taste weiterhin gedrückt halte. Braucht jeder Schläger einen eigenen Thread? Ich habe hier im Forum mal gesucht, aber keine richtigen Beispiele gefunden. Bin ich denn mit "1 Thread für Ball, einer pro Schläger" auf dem richtigen Weg?

Mfg Florian


----------



## Wildcard (18. Jan 2007)

1. Von einer get Methode erwartet man nicht das sie etwas ändert, hier ist die Bennung ganz klar verkehrt.
2. Klassen schreibt man groß
3. keyTyped ist der falsche Ansatz. Deine beweglichen Objekte brauchen einen Bewegungsvektor.
Bei keyPressed setzt du den zum Beispiel auf -5, bei keyReleased wieder auf 0.
4. Du brauchst nur einen Thread der alle Bewegungen durchführt. Alles andere wird schwieriger und unzuverlässig


----------



## Neolity (18. Jan 2007)

Wie funktioniert das mit dem Bewegungsvektor denn genau(er)?


----------



## Wildcard (18. Jan 2007)

Stell dir vor dein Thread gibt den Takt an.
Jedes bewegliche Objekt hat einen Vektor der ihm sagt um wie viel sich seine Position pro Takt verschiebt.
Der Thread ruft dann in jedem Durchlauf objekt.bewegDich() auf und das Objekt versetzt seine Position um den Vektor.


----------



## Neolity (18. Jan 2007)

ok, das hört sich sehr logisch an! 

Aber ich hab im Augenblick ein viel komischeres Problem. Ich wollte jetzt alles auf "einen Thread umrüsten". Die run Methode in der Fenster.java sieht so aus:


```
public void run()
	{
		while (true)
		{
			repaint();			
			b.aenderungBestimmen();
			try
			{
				Thread.sleep(10);
			}
			catch (InterruptedException ie)
			{
			}
		}
	}
```

In der ball.java sieht die Methode aenderungBestimmen() so aus:


```
public void aenderungBestimmen()
	{
		x_alt = x;
		y_alt = y;		
		if (y == 745)
		{
			aender_y = -5;
		}
		if (x == 1000)
		{
			aender_x = -5;
		}
		if (y == 85)
		{
			aender_y = 5;
		}
		if (x == 10)
		{
			aender_x = 5;
		}
		x += aender_x;
		y += aender_y;
	}
```

Ich hab alles kompiliert und es lief. Ich will das ganze nochmal starten und bekomme diese Fehlermeldung:

Exception in Thread "Thread-2" java.lang.NullPointerException
     at Fenster.run(Fenster.java:73)
     at java.lang.Thread.run(Unknown Source)

Zeile 73 in der Fenster.java ist diese:
b.aenderungBestimmen();

Woran liegt denn das bitte?


----------



## Wildcard (18. Jan 2007)

Naja, b ist null


----------



## Neolity (18. Jan 2007)

jo, das sagt die Fehlermeldung, aber wieso ist das so?

Er hat ja auch in allen anderen Methoden nichts zu meckern...


----------



## Wildcard (18. Jan 2007)

b ist null weil du's nicht initialisiert hast oder null gesetzt hast. Was soll ich jetzt dazu sagen?


----------



## Neolity (18. Jan 2007)

Aber im Konstruktor initialisiere ich b doch mit "b = new ball();"?!


----------



## Wildcard (18. Jan 2007)

Ist das vielleicht ein anderes b?


----------



## Neolity (18. Jan 2007)

nein, ich hab nur ein einziges b in allen Klassen, das auch nur an dieser Stelle Probleme macht!


----------



## Wildcard (18. Jan 2007)

Neolity hat gesagt.:
			
		

> nein, ich hab nur ein einziges b in allen Klassen, das auch nur an dieser Stelle Probleme macht!


gibt's nicht. Wenn es das gleiche ist, dann ist es entweder null, oder nicht.
Versuchst du evtl. darauf zuzugreifen bevor es initialisiert wird?


----------



## Neolity (18. Jan 2007)

Das ist jetzt die ganze Fenster Klasse:


```
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/*
Florian Quinkert, 16.01.07

Klasse Fenster.java:
Diese Klasse erstellt das Fenster mit einer Größe von 1024 * 768 Pixeln.
Außerdem werden in dieser Klasse die Schlaeger gezeichnet und auf Bewegungen
reagiert.
*/
class Fenster extends JFrame
implements Runnable
{
	schlaeger sl;
	schlaeger sr;
	ball b;
   
	int i = 1;
	Fenster()
	{
		super("Pong");
      
		new Thread(this).start();
      
		sl = new schlaeger(10, 100);
		sr = new schlaeger(1000, 100);
		b = new ball();
      
		setSize(1024,768);

		addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent we)
			{
				System.exit(0);
			}
		});
		addKeyListener(new KeyAdapter()
		{
			public synchronized void keyPressed(KeyEvent ke)
			{
				// 1. Schlaeger
				if (ke.getKeyCode() == KeyEvent.VK_W)
				{
					sl.getUp();
				}
				if (ke.getKeyCode() == KeyEvent.VK_S)
				{
					sl.getDown();
				}

				// 2. Schlaeger
				if (ke.getKeyCode() == KeyEvent.VK_UP)
				{
					sr.getUp();
				}
				if (ke.getKeyCode() == KeyEvent.VK_DOWN)
				{
					sr.getDown();
				}      
			}
		});
		setVisible(true);   
	}
   
	public void run()
	{
		while (i == 1)
		{
			repaint();
			b.aenderungBestimmen();
			try
			{
				Thread.sleep(10);
			}
			catch (InterruptedException ie)
			{
			}
		}
	}

	public void paint(Graphics g)
	{
		sl.paint(g);
		sr.paint(g);      
		g.fillRect(b.x, b.y_alt, b.breite, b.hoehe);
		g.fillRect(b.x, b.y, b.breite, b.hoehe);
	}

	public static void main(String[] args)
	{
		Fenster f = new Fenster();
	}
}
```

Wie du siehst, greife ich mehrfach auf b zu, aber es macht nur an der genannten Stelle Probleme...


----------



## Wildcard (18. Jan 2007)

Du startest den Thread bevor du b initialisierst  :roll:


----------



## Neolity (19. Jan 2007)

oh sch.... 

Vielen vielen Dank für deine sehr schnelle Hilfe!!!


----------



## Neolity (19. Jan 2007)

So, hab gestern nacht und heute noch weiter daran rumgebastelt.

Ich bin jetzt soweit, dass ich beide Schläger gleichzeitig bewegen kann, der Computer entscheidet, ob ein Ball den Schläger trifft oder nicht und setzt entsprechend den Punktestand für den jeweiligen Spieler hoch.

Das Programm hat jedoch noch 2 Schönheitsfehler:

- Der Ball wird bewegt, indem die alte Position übermalt wird und an der neuen Position neu gezeichnet wird. Das funktioniert eigentlich auch sehr gut, doch in ganz seltenen Fällen bleibt ein Rest des Balls bestehen und wird nicht übermalt. Das kommt unregelmäßig und sehr selten vor, nervt aber trotzdem etwas. Vielleicht hat da jemand eine Idee.

- In der paint Methode schreibe ich mit drawString den Punktestand. Jedoch wurde nicht nur die gerade aktuelle Zahl geschrieben, sondern bei einer Änderung einfach darüber geschrieben. Ich habe jetzt am Anfang der paint Methode ein fillRect eingebaut, dass den Punktestand übermalt und später durch drawString der aktuelle Punktestand wieder angezeigt wird. Dabei ist jedoch das Problem, dass die beiden Punktestände am flimmern sind. Lasse ich die beiden Rechtecke weg und füge am Anfang super.paint(g) ein, dann wird zwar der Punktestand immer korrekt aktualisiert, doch nun flimmert alles und die Hintergrundfarbe stimmt nicht mehr.

Da aber Code mehr sagt, als 1000 Worte, schaut es euch am besten selber an:

rapidshare.com/files/12435050/Pong.rar.html


----------



## Neolity (21. Jan 2007)

Keiner ne Ahnung?


----------

