# Einfacher bewegter Punkt im Frame



## arnydaniel (7. Aug 2006)

Hi,

ich möchte einefach eine Punkt über mein Frame bzw. Panel laufen lassen. Hab dazu bis jetzt folgende beiden Klassen verfasst:

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

public class Pong extends JPanel{
	static Ball ball;
		
	public static void main(String[] args) {
		JFrame f = new JFrame("Pong");
		f.setSize(400,400);
		f.setLocation(300,150);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setVisible(true);
		Pong feld = new Pong();
		ball = new Ball( feld );
		f.add( feld );
		feld.repaint();
		f.repaint();
	}
	
	@Override
	  protected void paintComponent( Graphics g )
	  {
		g.clearRect(0,0,400,400);
	    g.fillOval(ball.posx,ball.posy,20,20);
	  }

}
```

und

```
public class Ball extends Thread {
	int posx=0;
	int posy=200;
	Pong parent;

	Ball(Pong feld)
	{
		parent=feld;
		this.start();
	}
	
	public void run()
	{
		while(true)
		{
			posx++;
			if(posx>=400) posx=0;
			parent.repaint();
			
			try{Thread.sleep(5);}
            catch(InterruptedException e){} 
		}
	}
}
```

Allerdings sehen ich den bewegten Punkt erst, wenn ich den Frame nach dem starten in der Größe verändert habe.
Warum?

Ist der oben gezeigt Weg überhaupt sinnvoll?

NDake


----------



## André Uhres (7. Aug 2006)

Du machst das frame zu früh sichtbar, wenn du nachher frame.validate() aufrufst würde es zwar auch gehen. Ich hab ausserdem die paintComponent ein wenig verbessert:

```
public static void main(String[] args) {
        JFrame f = new JFrame("Pong");
        f.setSize(400,400);
        f.setLocationRelativeTo(null);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Pong feld = new Pong();
        ball = new Ball( feld );
        f.add( feld );
        f.setVisible(true);
    }
    @Override protected void paintComponent( Graphics g ) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D)g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.fillOval(ball.posx,ball.posy,20,20);
    }
```


----------



## arnydaniel (7. Aug 2006)

Vielen Dank soweit! klappt alles prima!
Wie man sicherlich unschwer erraten kann, soll es mal ein Pong-Spiel werden.
Da ich keinen Plan habe, wie ich eine schlagbare KI hinbekommen soll, versuch ich es jetzt so zu amchen, dass 2 menschliche Spieler spielen.
Dazu muss ich ja logischer weise abfragen, welche Tasten auf der Tastatur gedrück sind. Dazu hab ich diesen Code:

```
f.addKeyListener( new KeyAdapter()
				{
					public void keyPressed(KeyEvent e)
					{
						if(e.getKeyCode() == KeyEvent.VK_W)
						{
							balken1.move( 0 );
						}
						
						if(e.getKeyCode() == KeyEvent.VK_S)
						{
							balken1.move( 1 );
						}
						
						if(e.getKeyCode() == KeyEvent.VK_UP)
						{
							balken2.move( 0 );
						}
						
						if(e.getKeyCode() == KeyEvent.VK_DOWN)
						{
							balken2.move( 1 );
						}
					}
				}	
		);
```
Balken.move() ändert einfach nur die Y-Position des jeweiligen Balkens.
Allerdings funktioniert die Tastenabfrage nur bedingt.
Wenn ich z.B. auf Pfeil-nach-oben klicke und diesen gedrückt halte und dann auf W und den anderen Balken zu bewegen, vergisst er, dass auch der andere Balken bewegt werden muss!
Wie bekomme ich es also hin, dass ich quasi 2 oder mehr Keys gleichzeitig abfrage?

Danke


----------



## moormaster (7. Aug 2006)

arnydaniel hat gesagt.:
			
		

> Wie bekomme ich es also hin, dass ich quasi 2 oder mehr Keys gleichzeitig abfrage?



Das Key Event wird immer dann aufgerufen, wenn ein Tastendruck oder das Loslassen einer Taste empfangen wurde. Die jeweilige Taste kann man mit einer Methode abfragen (wie du es ja auch schon gemacht hast). Diese Methode gibt Informationen über die EINE Taste, welche zu diesem Event geführt hat. D.h. du kannst  nicht abfragen, welche Tasten gerade gedrückt sind. Du kannst dir sowas nur "merken".

Im KeyAdapter gibt es 3 Methoden, welche zu den entsprechenden Situationen aufgerufen werden:

keyTyped(KeyEvent e)
keyPressed(KeyEvent e)
keyReleased(KeyEbent e)

keyTyped wird aufgerufen, wenn eine Taste gedrückt und wieder losgelassen wurde.
keyPressed wird aufgerufen, wenn eine Taste gedrückt wurde
keyReleased wird aufgerufen, wenn eine Taste losgelassen wurde.

Was du du nun brauchst, ist jedes Mal, wenn keyPressed auslöst, dir zu merken, dass die jeweils übergebene Taste gerade gedrückt ist.
Wenn keyReleased aufgerufen wird, änderst du diesen Status wieder zurück und merkst Dir somit, dass die jeweilige Taste nicht mehr gedrückt ist.

Nun brauchst du aber noch etwas, was ständig den Tastenstatus aus den Variablen ausliest, wo du dir merkst, welche Tasten noch immer gedrückt sind. Genau da muss dann auch die eigentliche Programm Logik rein, welche entscheidet, welcher Balken sich wohin bewegt. Dazu wäre es vielleicht sinnvoll, sich mit Threads oder Timern zu beschäftigen, so dass im Hintergrund in regelmäßigen Abständen der Tastaturstatus überwacht wird und die Balken mit jedem Zyklus ein Stück in die entsprechenden Richtungen wandern.


----------



## flohrian (8. Aug 2006)

```
boolean bKeyDownW, bKeyDownS, bKeyDownUp, bKeyDownDown;
```


```
f.addKeyListener( new KeyAdapter()
				{
					public void keyPressed(KeyEvent e)
					{
						if(e.getKeyCode() == KeyEvent.VK_W)
						{
							bKeyDownW = true;
						}
						
						if(e.getKeyCode() == KeyEvent.VK_S)
						{
							bKeyDownS = true;
						}
						
						if(e.getKeyCode() == KeyEvent.VK_UP)
						{
							bKeyDownUp = true;
						}
						
						if(e.getKeyCode() == KeyEvent.VK_DOWN)
						{
							bKeyDownDown = true;
						}
					}


					public void keyReleased (KeyEvent e)
					{
						if(e.getKeyCode() == KeyEvent.VK_W)
						{
							bKeyDownW = false;
						}
						
						if(e.getKeyCode() == KeyEvent.VK_S)
						{
							bKeyDownS = false;
						}
						
						if(e.getKeyCode() == KeyEvent.VK_UP)
						{
							bKeyDownUp = false;
						}
						
						if(e.getKeyCode() == KeyEvent.VK_DOWN)
						{
							bKeyDownDown = false;
						}
					}

				}	
		);
```

Sollte imho klappen.
Dann muss halt noch regelmäßig abgefragt werden:


```
if (bKeyDownW == true){
balken1.move(0);
}
if (bKeyDownS == true){
balken1.move(1);
}
[...]
```

Belehrt mich, wenn ich daneben liege, ist schließlich mein erster Post hier 

Mfg
Flo


----------



## moormaster (8. Aug 2006)

Das ist vom Prinzip her das, was ich gemeint habe. Bis auf die Stelle mit dem regelmäßigen Abfragen.

Ich hoffe, du hast das nicht in eine normale Endlosschleife gepackt; das würde dann zu 100% Dauer-CPU Last führen, weshalb du das lieber in einen Thread packen solltest, wo nach jedem Schleifendurchlauf eine gewisse Zeit "geschlafen" wird, so dass Rechenzeit für andere Aufgaben bleibt.


----------



## Vorbote der Apokalypse (19. Sep 2006)

Nochma zur KI:
Was hälst du davon einfach den anderen Balken immer in die Richtung des Balls bewegt? Man könnte dann sogar Schwierigkeits Stufen einbauen. Je nachdem wie schnell der Balken ist.
PS: Programm interiissiert mich könntest du den Quelltext mal an Vorbote_der_Apokalypse@web.de schicken?


----------

