# Probleme bei Bewegung



## Freddde (23. Okt 2008)

Hallo zusammen,

ich habe ein Prob mit der Bewegung von  2D Objekten, ich erkläre kurz das Problem und werden dann meinen Code zeigen. Also ich habe ein Objekt, das sich pro Tasten druck um 50 Pixel bewgt, vorher ist eine Bedingung ob das geht. Wenn ich aber es Bewege, meist wenn ich gedrückt halte lässt es die Bedingung einfach aus. Dieses Problem hatte ich auch schonmal bei einen anderen Programm. Ich habe den Grundstruktur von dem Javatutorial für 2dGames benutzt.
Hier der Code:

```
package spiel;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class GamePanel extends JPanel implements Runnable, KeyListener{
	private static final long serialVersionUID = 1L;
	boolean game_run=true;
	long delta =0;
	long last=0;
	long fps=0;
	Sprite recht;
	Sprite recht2;
	Sprite recht3;
	Vector<Sprite> actors;
	boolean up=false;
	boolean down=false;
	boolean left=false;
	boolean right=false;
	int speed = 50;
	int zielx1=2;
	int zielx2=4;
	int ziely1=2;
	int ziely2=2;
	int x,x1,x2,y,y1,y2;
	boolean spielfeld[][]=new boolean[8][7];
	byte spielfeldvorlage[]={0,0,0,0,0,0,0,
							 0,1,1,0,1,1,0,
							 0,1,1,1,1,1,0,
							 0,1,1,1,1,1,0,
							 0,0,1,1,1,0,0,
							 0,0,1,1,1,0,0,
							 0,0,0,1,0,0,0,
							 0,0,0,0,0,0,0
	};
	int a=40;//größe
	public static void main(String[] args){
		new GamePanel (350,400);
	}
	public GamePanel(int w, int h){
		this.setPreferredSize(new Dimension(w,h));
		JFrame frame = new JFrame("Tetris für arme");
		frame.setLocation(100, 100);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.addKeyListener(this);
		frame.add(this);
		frame.pack();
		frame.setBackground(Color.black);
		frame.setVisible(true);
		doInitializations();
	}
	private void doInitializations() {
		last=System.nanoTime();
		actors=new Vector<Sprite>();
		recht3= new Sprite(150,100,100,false,this);
		recht= new Sprite(150,200,100,true,this);
		recht2= new Sprite(150,300,100,false,this);
		actors.add(recht);
		actors.add(recht2);
		actors.add(recht3);
		spielfelderzeugen();
		Thread t = new Thread(this);
		t.start();
	}
	public void run() {

		while(game_run){
			computeDelta();
			try {
				checkKeys();
			} catch (InterruptedException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
//			doLogic();
			kooli();
			moveObjects();
			repaint();
			try{
				Thread.sleep(30);
			}catch (InterruptedException e) {
				// TODO: handle exception
			}
			
		}
		
	}
	private void computeDelta() {
		delta=System.nanoTime() -last;
		last=System.nanoTime();
		fps=((long)1e9)/delta;
		
	}
	private void moveObjects() {
		for(Movable mov:actors){
			mov.move(delta);
		}
		
	}
//	private void doLogic() {
//		for(Movable mov:actors){
//			mov.doLogic(delta);
//		}
//		
//	}
	private void spielfelderzeugen() {
		int ka=0;
		for(int i=0;i<8;i++){
			for(int j=0;j<7;j++){
				if(spielfeldvorlage[ka]==1){
					spielfeld[i][j]=true;
				}
				else{
					spielfeld[i][j]=false;	
				}
				ka++;
			}
		}		
	}
	private void kooli(){
		
	}
	private void checkKeys() throws InterruptedException {
		x=((int)recht.x/50);
		y=((int)recht.y/50);
		x1=((int)recht2.x/50);
		y1=((int)recht2.y/50);
		x2=((int)recht3.x/50);
		y2=((int)recht3.y/50);
		int sleep=50;
		if(up){
			Thread.sleep(sleep);
//			if(!((y-1)<0)){
			if((spielfeld[y-1][x])){
				recht.setVerticalSpeed(-speed);	
			}
			if(spielfeld[y1-1][x1]){
				recht2.setVerticalSpeed(-speed);	
			}
			if(spielfeld[y2+1][x2]){
			recht3.setVerticalSpeed(speed);
			}
//			up=false;
		}
		if(down){
			Thread.sleep(sleep);
//			if(!((y+1)>5)){
			if(spielfeld[y+1][x]){
				recht.setVerticalSpeed(speed);	
			}
			if(spielfeld[y1+1][x1]){
			recht2.setVerticalSpeed(speed);	
			}
			if(spielfeld[y2-1][x2]){
				recht3.setVerticalSpeed(-speed);	
			}
//			down=false;
						
		}
		if(right){
			Thread.sleep(sleep);
//			if(!((x+1)>5)){
			if(spielfeld[y][x+1]){
				recht.setHorizontalSpeed(speed);
			}
			if(spielfeld[y1][x1+1]){

			recht2.setHorizontalSpeed(speed);
			}
			if(spielfeld[y2][x2-1]){
			recht3.setHorizontalSpeed(-speed);
			}
//			right=false;
		}
		if(left){
			Thread.sleep(sleep);
//			if(!((x-1)<0)){
			if(spielfeld[y][x-1]){
				recht.setHorizontalSpeed(-speed);	
			}
			if(spielfeld[y1][x1-1]){
			recht2.setHorizontalSpeed(-speed);
			}
			if(spielfeld[y2][x2+1]){
			recht3.setHorizontalSpeed(speed);
			}
//			left=false;
		}
		if(!left&&!right){
			recht.setHorizontalSpeed(0);
			recht2.setHorizontalSpeed(0);
			recht3.setHorizontalSpeed(0);
		}
		if(!up&&!down){
			recht.setVerticalSpeed(0);
			recht2.setVerticalSpeed(0);
			recht3.setVerticalSpeed(0);
		}
	}
	public void keyPressed(KeyEvent e) {
		if(e.getKeyCode()==KeyEvent.VK_UP){
			up=true;
		}
		if(e.getKeyCode()==KeyEvent.VK_DOWN){
			down=true;
		}
		if(e.getKeyCode()==KeyEvent.VK_LEFT){
			left=true;
		}
		if(e.getKeyCode()==KeyEvent.VK_RIGHT){
			right=true;
		}
		
	}
	public void keyReleased(KeyEvent e) {
		if(e.getKeyCode()==KeyEvent.VK_UP){
			up=false;
		}
		if(e.getKeyCode()==KeyEvent.VK_DOWN){
			down=false;
		}
		if(e.getKeyCode()==KeyEvent.VK_LEFT){
			left=false;
		}
		if(e.getKeyCode()==KeyEvent.VK_RIGHT){
			right=false;
		}
		
	}
	public void keyTyped(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		for(int i=0;i<7;i++){
			for(int j=0;j<8;j++){
				if(spielfeld[j][i]){
					g.setColor(Color.BLACK);
					g.fill3DRect((int)(i*40+i*10), (int)(j*40+j*10), (int)a,(int)a,true);	
				}
			}
		}
		g.setColor(Color.GREEN);
		g.drawArc((int)(zielx1*40+zielx1*10), (int)(ziely1*40+ziely1*10), (int)a-1,(int)a-1, 0, 360);
		g.drawArc((int)(zielx2*40+zielx2*10), (int)(ziely2*40+ziely2*10), (int)a-1,(int)a-1, 0, 360);
//		g.fill3DRect((int)(zielx1*40+zielx1*10), (int)(ziely1*40+ziely1*10), (int)a,(int)a,true);
//		g.fill3DRect((int)(zielx2*40+zielx2*10), (int)(ziely2*40+ziely2*10), (int)a,(int)a,true);
		if(actors!=null){
			for(Drawable draw:actors){
				draw.drawObjects(g);
			}
		}
	}

}
```
das war die GamePanel und jetzt noch die Sprite:

```
package spiel;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.geom.Rectangle2D;


public class Sprite extends Rectangle2D.Double implements Drawable, Movable {
	long delay;
	long animation =0;
	GamePanel parent;
	int currentpic=0;
	protected double dx;
	protected double dy;
	int[] a={30};
	int[] b={30};
	boolean d;
	
	public Sprite( double x, double y, long delay,boolean a, GamePanel p){
		this.x=x;
		this.y=y;
		this.delay=delay;
		this.width=40;
		this.height=40;
		parent=p;
		d=a;
	}

	

	public void drawObjects(Graphics g) {

		if(d){
			g.setColor(Color.RED);	
		}
		else{
			g.setColor(Color.GREEN);
		}
		g.fill3DRect((int)x, (int)y, (int)width,(int)height,true);
		
	}

	public void doLogic(long delta) {
		
		
	}
	public void move(long delta) {
		if(dx!=0){
			x+= dx;
		}
		if(dy!=0){
			y+= dy;
		}
		
	}
	public void setVerticalSpeed(double d){
		dy=d;
	}
	public void setHorizontalSpeed(double d){
		dx=d;
	}
	public double getVerticalSpeed(){
		return dy;
	}
	public double getHorizontalSpeed(){
		return dx;
	}
}
```


----------



## Quaxli (23. Okt 2008)

Ich hab's jetzt nicht im Detail durchprobiert, aber grundsätzlich sieht die checkKeys()-Methode nicht wirklich prickelnd aus.

Zum Einen weiß ich nicht, was der Thread.sleep(..) dort soll, außer daß er Dir Dein Programm unnötig verzögert. Zum Anderen haben die Bedingungen, ob Bewegung oder nicht dort nichts verloren. Die solltest Du entweder in eine doLogic()-Methode des zu bewegenden Objektes packen oder zur Not in die Move-Methode(). Dort kannst Du dann immer noch entscheiden, ob die Bewegung wirklich erfolgen soll und die entsprechende Logik ist wenigstens beim entsprechenden Objekt hinterlegt und nicht irgendwo abseits versteckelt.



> Ich habe den Grundstruktur von dem Javatutorial für 2dGames benutzt.



Aber wirklich nur in groben Zügen. Im Tutorial findest Du in checkKeys() weder Thread.sleep() noch umfangreiche Logiken  :### 


Deine Bedingungen sind ja auch etwas unorthodox:


```
if(!((y-1)<0))
...
```

Das könnte man schon auch einfacher haben 

Um zu überprüfen, warum eine Bedinung nicht greift, gibt es im Übrigen eine ganz einfach Methode. Schreib einfach ein System.out.println(...) vor ddie entsprechende if-Bedingung und gibt die Parameter aus, die in der Bedingung abgefragt werden, dann bekommst Du ganz schnell raus, warum die Bedingung nicht greift.


----------



## Freddde (23. Okt 2008)

Der Thread.sleep war erstma dafür da, das mein Problem, was bei dir nichtmals einmal erwähnt wird, zulösen. Ich kann auch die Methode gerne umschreiben, aber du hast etwas aus meinen code etwas zitiert was auskommentiert ist. 
Das Prob ist nicht das die if-Bedingung nicht greift, sondern das er sie manchmal ignoriert werden. Meine Vermutung dazu ist das die Methode in einen Multithread läuft. So kann das Programm 2mal nebeneinander laufen und dann sind 2mal die Bedingungen erfüllen. Ich weiss aber nicht direkt wie ich das Problem löse das es halt kein Multithread ist.


----------



## Guest (24. Okt 2008)

was auch manchmal hilf ist debuggen... jede variable auf zustand prüfen usw....
vllt hilfts... viele machen das nicht und denken in foren fragen hilft ^^


----------



## Quaxli (25. Okt 2008)

Freddde hat gesagt.:
			
		

> Der Thread.sleep war erstma dafür da, das mein Problem, was bei dir nichtmals einmal erwähnt wird, zulösen. ....ist.



Tja, ich hab ja auch nur ein Tutorial geschrieben und nicht den Almanach der Spieleprogrammierung  Du wirst noch öfter auf Probleme stoßen, die bei mir nicht behandelt wurden 
Fakt ist aber auch, daß es bei mir SO nicht gemacht wird! 



			
				Freddde hat gesagt.:
			
		

> Das Prob ist nicht das die if-Bedingung nicht greift, sondern das er sie manchmal ignoriert werden



Was heißt in dem Zusammenhang manchmal? Geht es nach dem Starten nicht und nach einem Neustart dann doch oder setzt es zwischendurch aus?



			
				Gast hat gesagt.:
			
		

> was auch manchmal hilf ist debuggen...



Prinzipiell gebe ich Dir recht  Nur habe ich beim Entwickeln von Spielen die Erfahrung gemacht, daß System.out.println(...) in vielen Fällen besser ist, weil der Spielfluß im Gegensatz zum Debuggen nicht unterbrochen wird und man die Ausgabe (je nach Fenstergröße) unmittelbar in der Konsole sieht.
Dies ist z. B. vorteilhaft, wenn Bewegung in abhängigkeit vom Delta des letzten Schleifendurchlaufs berechnet werden, der beim Debuggen natürlich sehr viel größer ist, als wenn das Spiel ohne Unterbrechung läuft.


----------



## Quaxli (25. Okt 2008)

Ich hab Deinen Code gerade mal kopiert und importiert und habe keine Probleme - wenn man davon absieht, daß die Bewegung noch nicht ganz ausgefeilt ist (weißt Du vermutlich selbst  ).

Sonst konnte ich keine Probleme feststellen.  ???:L


----------



## Freddde (25. Okt 2008)

Also wenn man z.b. einfach irgendeine richtung gedrückt hält, geht er aus dem spielfeld. Das liegt dadran, das der checkkeys ein multithread offen amcht, dann wird mehr mals geöffnen, so kann es sein das die bedingung auch immer noch wahr ist, aber wie kann ich das ändern.


----------



## Quaxli (26. Okt 2008)

Freddde hat gesagt.:
			
		

> .. Das liegt dadran, das der checkkeys ein multithread offen amcht, dann wird mehr mals geöffnen, ..



Nein, tut er nicht. Deine Logik ist nicht sauber und wenn Du die Grenzen des Arrays verläßt, wirft Dein Programm einen IndexOutOfBounds-Fehler und reagiert dann natürlich nicht mehr, das hat nichts mit irgendwelchen Threads zu tun. Programmiere die Logik sauber, dann ist's gut. Die gehört außerdem aus der checkKeys-Methode raus und ins Sprite rein.

Ich habe den Eindruck, daß Du die Konsolenausgabe nicht beachtest und Dich auf Mutmaßungen stützt. Laß das! Besorg Dir eine vernünftige IDE (z. B. Eclipse für umsonst) oder öffne die Konsole, wenn Du Dein Programm startest, dann erkennst Du Fehler sofort.


----------

