# Moorhuhn-Klon - Nur das 1. Huhn ist "treffbar"



## Jack159 (1. Nov 2012)

Hallo,

Ich versuche mich gerade an einem Moorhuhn-Klon und bin aktuell soweit, dass alle 3 Sekunden von rechts nach links fliegend ein neues Huhn spawnt. Die Hühner sollten per Mausklick abgeschossen werden können. Auf der Konsole erfolgt testweise bei erfolgtem Treffer eines Huhns die Meldung "Treffer!".
Mein Problem ist, dass nur das 1. Huhn treffbar ist. Alle anderen Hühner sind nicht treffbar. Ich verstehe nicht wieso....

Ich habe das ganze Projekt im Anhang als .jar Datei samt .java und .class Datein angehangen.
Von .jar Datein habe ich keine Ahnung, lässt sich so nicht starten die Datei, jedoch läuft es über Eclipse...

Alternativ habe ich meine Klassen unten aufgelistet:

Ob das ganze jetzt schön sauber nach Konventionen gecodet ist, ist mir erstmal egal. Darum kümmere ich mich später.




```
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;


public class App {
	
	public static Panel p1;
	public static int mousex;
	public static int mousey;
	
	public static void main(String[] args) {
		
		
		
		Frame f1 = new Frame();
	    p1 = new Panel(f1);
		Thread1 t1 = new Thread1();
		t1.start();
		Thread2 t2 = new Thread2();
		t2.start();
		Thread3 t3 = new Thread3();
		t3.start();
		
		
		MouseListener a = new MouseListener(){

			@Override
			public void mouseClicked(MouseEvent arg0) {
				System.out.println("geklickt an Position X: "+arg0.getX()+"    Y: "+arg0.getY());
				mousex = arg0.getX();
				mousey = arg0.getY();
				
				
			}

			@Override
			public void mouseEntered(MouseEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void mouseExited(MouseEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void mousePressed(MouseEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void mouseReleased(MouseEvent arg0) {
				// TODO Auto-generated method stub
				
			}
			
			};
			f1.addMouseListener(a);
			
		
	}

}
```



```
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;

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


public class Panel extends JPanel {
	
	Image mh = Toolkit.getDefaultToolkit().getImage( "mh.gif" );
	
	public Panel(JFrame a) {
		a.add(this);
	}
	
	public void paintComponent(Graphics g) {
		g.setColor(Color.WHITE);
		g.fillRect(0, 0, 1000, 700);
		g.setColor(Color.BLACK);
		
		//Moorhühner zeichnen
		for(Moorhuhn mh : Thread2.mhliste) {
			g.drawImage(mh.getImage(), mh.getX(), mh.getY(), null);
		}
		
		//Für alle Moorhühner prüfen, ob Mausklickposition mit Moorhuhn übereintrifft. Falls ja -> Treffer.
		for(Moorhuhn mh : Thread2.mhliste) {
			
			if(App.mousex>mh.getX() && App.mousex<mh.getX()+80  &&  App.mousey>mh.getY()+20 && App.mousey<mh.getY()+80) {
				
				
				System.out.println("TREFFER");
				
			}else {
				App.mousex=0;
				App.mousey=0;
			}
		}
		
			
	}

}
```



```
import java.awt.Image;
import java.awt.Toolkit;


public class Moorhuhn {
	
	public int x;
	public int y;
	public Image img;
	
	public Moorhuhn() {
		setX(800);
		setY(249);
		loadImage();
	}
	
	public void setX(int x) {
		this.x = x;
	}
	
	public void setY(int y) {
		this.y = y;
	}
	
	public int getX() {
		return x;
	}
	
	public int getY() {
		return y;
	}
	
	private void loadImage() {
		img = Toolkit.getDefaultToolkit().getImage( "mh.gif" );
	}
	
	public Image getImage() {
		return img;
	}

}
```




```
import javax.swing.JFrame;


public class Frame extends JFrame {
	
	public Frame() {
		this.setSize(1000, 600);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setLocationRelativeTo(null);
		this.setVisible(true);
		
	}

}
```



```
public class Thread1 extends Thread {
	
	
	public void run() {
		
		while(true) {
			
			App.p1.repaint();
			
		}
		
	}

}
```




```
import java.util.Vector;


public class Thread2 extends Thread {
	
	public static Vector<Moorhuhn> mhliste;
	
	public void run() {
		
		mhliste = new Vector<Moorhuhn>();
		
		while (true) {
			
			
			mhliste.add(new Moorhuhn());
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			mhliste.add(new Moorhuhn());
			
		}
		
	}

}
```



```
public class Thread3 extends Thread {
	
	public void run() {
		
		while(true) {
			
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			//Moorhühner bewegen
			for(Moorhuhn mh: Thread2.mhliste) {
				mh.setX(mh.getX()-5);

			}
			
		}
		
	}

}
```


----------



## noobadix (1. Nov 2012)

Hi!

Jar startet hier nicht:


```
Failed to load Main-Class manifest attribuite from Moorhuhn-Klon.jar
```

...heißt's in der Konsole.

Warum prüfst du auf Treffer eigentlich in der Methode "paintComponent(...)"? Wird die nicht viel zu selten aufgerufen?

Übrigens ist es wohl empfehlenswerter, anstelle der Klasse Thread den SwingWorker zu benutzen. Ich war nämlich verunsichert durch die Angabe "Swing ist nicht threadsicher.". Hat bei meinem Moorhuhn-Klon zumindest gut funktioniert.

Gruß!


----------



## Jack159 (1. Nov 2012)

noobadix hat gesagt.:


> Hi!
> 
> Jar startet hier nicht:
> 
> ...




Alternativ die Klassen entpacken und die App.java starten/kompilieren, dann müsste es starten (die .jar geht bei mir auch nicht).

In der Klasse "Thread1" rufe ich im dortigen Thread "t1" in der run*Methode durchgängig die repaint()-Methode auf.

Ich habe die Prüfung auf einen Treffer auch mal testweise in die public void mouseClicked(MouseEvent arg0) Methode verlagert, jedoch tritt dort das selbe Problem auf.

Komisch ist ja, dass die Treffer-Prüfung nur beim 1. Huhn problemlos funktioniert....Ich weiß echt nicht, wo der Fehler liegen könnte...


----------



## noobadix (1. Nov 2012)

Ok, Danke!

Jetzt startet das Programm und es läuft IRRE langsam. 

In voller Rechengeschwindigkeit fortwährend "repaint()" aufzurufen scheint mir nicht sonderlich sinnvoll, das reicht auch, wenn du das nach jedem "Moorhuhnschritt" ausführst und ich glaube, es genügt, wenn du es auf dem Spielpanel aufrufst und außerdem: Benutze SwingWorker!

Du könntest die Moorhühner auch als JPanel oder nur als Container realisieren und denen dann jeweils einen MouseListener dranhängen, sodass du nicht bei jedem Klick alle Hühner durchgehen musst.
Übrigens gibt es auch "MouseAdapter" anstelle von "MouseListener", wenn du nur einzelne Methoden des MouseListener überschreiben magst:


```
dingsbums.addMouseListener(new MouseAdapter(){
     public void mouseClicked(MouseEvent e){
          //cooles Zeug machen
     }
});
}
```

EDIT:
Nicht SwingWorker, sry. Sondern "Timer" !

Das kann dann so aussehen:

```
Timer moorhuhnStepTimer = new Timer(100, new MSTListener());
timer.start();
...
class MSTLIstener implements ActionListener{
     public void actionPerformed(ActionEvent e){
          for(Moorhuhn huhn : moorhuehner){
               huhn.takeStep();
          }
          gamePanel.repaint();
     }
}
```


----------



## TKausL (1. Nov 2012)

```
for(Moorhuhn mh : Thread2.mhliste) {
            
            if(App.mousex>mh.getX() && App.mousex<mh.getX()+80  &&  App.mousey>mh.getY()+20 && App.mousey<mh.getY()+80) {
                
                
                System.out.println("TREFFER");
                
            }else {
                App.mousex=0;
                App.mousey=0;
            }
        }
```

Deswegen kannst du nur das 1. Huhn treffen. Fällt dir nichts auf?


----------



## Jack159 (2. Nov 2012)

TKausL hat gesagt.:


> ```
> for(Moorhuhn mh : Thread2.mhliste) {
> 
> if(App.mousex>mh.getX() && App.mousex<mh.getX()+80  &&  App.mousey>mh.getY()+20 && App.mousey<mh.getY()+80) {
> ...



Nein, ich sehe nicht, wo dort der Fehler liegen könnte....

Wenn ich das ganze wie folgt umändere:


```
for(Moorhuhn mh : Thread2.mhliste) {
            
            if(App.mousex>mh.getX() && App.mousex<mh.getX()+80  &&  App.mousey>mh.getY()+20 && App.mousey<mh.getY()+80) {
                
                
                System.out.println("TREFFER");
                App.mousex=0;
                App.mousey=0;
                
            }
        }
```

dann funktioniert das Treffen zwar für alle Hühner, jedoch habe ich dann das Problem, dass wenn ich z.b. 2cm vor einem Huhn einen "Fehltreffer" lande, dann zwar zunächst wie erwartet keine Treffermeldung erfolgt, jedoch wenn das nächstbeste Huhn an diesen Fehltrefferpunkt vorbeifliegt, erhalte ich nachträglich eine Treffermeldung. Daher muss ich doch App.mousex und App.mousey bei einem Fehltreffer auf 0 setzen, um genau dies zu verhindern. Dies habe ich mit meiner 1. Version aus dem Startpost versucht, aber dann funktioniert die Trefferabfrage komischerweise nur noch für das 1. Huhn....


@ noobadix:
Inwiefern ist Swing nicht threadsicher?


----------



## TKausL (2. Nov 2012)

Jack159 hat gesagt.:


> Nein, ich sehe nicht, wo dort der Fehler liegen könnte....
> 
> Wenn ich das ganze wie folgt umändere:
> 
> ...



Natürlich funktioniert die Abfrage nur für das 1. Huhn, da du ja bereits die mausposition auf 0:0 setzt wenn das 1. Huhn nicht getroffen wurde.


----------



## Jack159 (2. Nov 2012)

TKausL hat gesagt.:


> Natürlich funktioniert die Abfrage nur für das 1. Huhn, da du ja bereits die mausposition auf 0:0 setzt wenn das 1. Huhn nicht getroffen wurde.



Ich verstehe immer noch nicht....

Hast du das Spiel gestartet? Mit "1. Huhn" meine ich ich nicht das 1. Huhn, was ich abschießen will, sondern ich meine wirklich das 1. Huhn, welches von rechts nach Links herfliegt. (Nur um sicherzugehen, dass wir nicht aneinander vorbeireden^^)

Aber wenn ich doch irgendwo hinklicke und einen Fehltreffer lande, dann muss die Mausposition doch auf 0:0 gesetzt werden, da ich sonst eventuell später eine falsche Treffermeldung bekomme, falls eben dort an der Stelle ein Huhn vorbeifliegt und ich bis dahin nicht woanders hingeklickt habe?!

Edit:
Jetzt habe ich die Lösung....
Das Problem ist, dass die repaint() Methode und somit auch die for-each Schleife ständig die ganze Zeit aufgerufen wird (Durch t1). Wenn ich die Trefferprüfung nur dann aufrufe, wenn ich einen Mausklick getätigt habe, dann funktioniert es. Weil wenn ich nicht geklickt habe, brauche ich auch nicht zu prüfen, ob ich einen Treffer gelandet habe.


Danke an alle nochmals  !

Für alle Intressierten hier die beiden Klassen, in denen die Änderung vorgenommen wurde:



```
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;


public class App {
	
	public static Panel p1;
	public static int mousex;
	public static int mousey;
	
	public static void main(String[] args) {
		
		
		
		Frame f1 = new Frame();
	    p1 = new Panel(f1);
		Thread1 t1 = new Thread1();
		t1.start();
		Thread2 t2 = new Thread2();
		t2.start();
		Thread3 t3 = new Thread3();
		t3.start();
		
		
		MouseListener a = new MouseListener(){

			@Override
			public void mouseClicked(MouseEvent arg0) {
				System.out.println("geklickt an Position X: "+arg0.getX()+"    Y: "+arg0.getY());
				mousex = arg0.getX();
				mousey = arg0.getY();
				
				
				
				
				for(Moorhuhn mh : Thread2.mhliste) {
				
				
				//Für alle Moorhühner prüfen, ob Mausklickposition mit Moorhuhn übereintrifft. Falls ja -> Treffer.
					if(App.mousex>mh.getX() && App.mousex<mh.getX()+80  &&  App.mousey>mh.getY()+20 && App.mousey<mh.getY()+80) {
						System.out.println("TREFFER");
						App.mousex=0;
						App.mousey=0;
						
					}else {

					}
				}
				
				
				
			}

			@Override
			public void mouseEntered(MouseEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void mouseExited(MouseEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void mousePressed(MouseEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void mouseReleased(MouseEvent arg0) {
				// TODO Auto-generated method stub
				
			}
			
			};
			f1.addMouseListener(a);
			
		
	}

}
```



```
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;

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


public class Panel extends JPanel {
	
	Image mh = Toolkit.getDefaultToolkit().getImage( "mh.gif" );
	
	public Panel(JFrame a) {
		a.add(this);
	}
	
	public void paintComponent(Graphics g) {
		g.setColor(Color.WHITE);
		g.fillRect(0, 0, 1000, 700);
		g.setColor(Color.BLACK);
				
		//Moorhühner zeichnen
		
		for(Moorhuhn mh : Thread2.mhliste) {
			g.drawImage(mh.getImage(), mh.getX(), mh.getY(), null);

		} 
		
			
	}

}
```


----------



## noobadix (5. Nov 2012)

Na Hauptsache es funktioniert! Das Problem vorher war, dass, nachdem du das erste Huhn auf Treffer geprüft hattest und in dem Fall, dass es nicht getroffen worden ist in der "else"-Anweisung die Mauskoordinaten auf Null gesetzt hast, auf die dann das nächste, zweite Huhn geprüft worden ist und das klappt freilich nicht. Oder?!

Zur Sache mit Swing und Threads:

Alle Interaktionen mit Swing-Komponenten sollen im EDT ausgelöst werden, dort laufen aber Threads nicht und somit besteht die Gefahr von Anzeigefehlern und Exceptions. Die Timer-Klasse ist für den Swingeinsatz vorgesehen, benutze sie also besser oder nimm Abstand von Swing.

javax.swing (Java Platform SE 6)
Java ist auch eine Insel – 15.33 AWT, Swing und die Threads

Gruß!


----------

