# Problem mit dem Spiele TUT



## Dagobert (19. Mrz 2008)

Ich habe mich jetzt mal oben mit dem Spiele TUT beschäftigt, nachdem ich gestern darauf hin verwiesen wurde.
Erstmal großes Lob. Es ist wirklich gut zu verstehen. Aber leider habe ich ein Problem. Meine bisherigen Zeichnungen werden nicht gelöscht. Dadruch ergeben sich schwarze Linien, die Fframzahl ist nicht mehr sichtbar usw.
Jetzt meine Frage: Wie kann ich die vorigen Objecet löschen, damit das erwünschte Ergebnis zu sehen ist?
Hier ist mal der Code meines Fensters:

```
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.Vector;

import javax.imageio.ImageIO;
import javax.swing.*;

public class GamePanel extends JPanel implements Runnable, KeyListener {
	public static void main(String[] args) {
		new GamePanel(800, 600);
	}

	boolean game_running = true;

	long delta = 0;

	long last = 0;

	long fps = 0;
	
	Sprite copter;
	Vector<Sprite> actors;
	
	boolean up = false;
	boolean down = false;
	boolean left = false;
	boolean right = false;
	int speed = 50;

	public GamePanel(int w, int h) {
		this.setPreferredSize(new Dimension(w, h));
		JFrame frame = new JFrame();
		frame.setTitle("HubschrauberDemo");
		frame.setLocation(100, 100);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.addKeyListener(this);
		frame.add(this);
		frame.pack();
		frame.setVisible(true);

		doInitializations();
	}

	public void doInitializations() {

		this.actors = new Vector<Sprite>();
		BufferedImage[] heli = loadPics("pics/heli.gif", 4);
		this.copter = new Sprite(heli, 400, 300, 100, this);
		this.actors.add(this.copter);
		
		this.last = System.nanoTime();

		Thread t = new Thread(this);
		t.start();
	}

	private void checkKeys() {
		if(this.up){
			this.copter.setVerticalSpeed(-this.speed);
		}
		if(this.down){
			this.copter.setVerticalSpeed(this.speed);
		}
		if(this.left){
			this.copter.setHorizontalSpeed(-this.speed);
		}
		if(this.right){
			this.copter.setHorizontalSpeed(this.speed);
		}
		if(!this.up&&!this.down){
			this.copter.setVerticalSpeed(0);
		}
		if(!this.left&&!this.right){
			this.copter.setHorizontalSpeed(0);
		}
	}

	private void moveObjects() {
		for(Movable mov:this.actors){
			mov.move(this.delta);
		}
		
	}

	private void doLogic() {
		for(Movable mov:this.actors){
			mov.doLogic(this.delta);
		}
	}

	public void computeDelta() {
		this.delta = System.nanoTime() - this.last;
		this.last = System.nanoTime();
		fps = ((long) 1e9) / this.delta;
	}

	public void run() {
		while (game_running) {
			computeDelta();
			checkKeys();
			doLogic();
			moveObjects();
			repaint();
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
			}
		}
	}

	public void paintComponent(Graphics g) {
		super.paintComponents(g);

		g.setColor(Color.red);
		g.drawString("FPS: " + this.fps, 20, 10);
		if(this.actors != null){
			for(Drawable draw:this.actors){
				draw.drawObjects(g);
			}
		}
	}

	private BufferedImage[] loadPics(String path, int NumberOfPics) {
		BufferedImage[] anim = new BufferedImage[NumberOfPics];
		BufferedImage source = null;

		URL pic_url = getClass().getClassLoader().getResource(path);

		try {
			source = ImageIO.read(pic_url);
		} catch (IOException e) {
		}

		for (int x = 0; x < NumberOfPics; x++) {
			anim[x] = source.getSubimage(x * source.getWidth() / NumberOfPics,
					0, source.getWidth() / NumberOfPics, source.getHeight());
		}
		return anim;
	}

	public void keyPressed(KeyEvent e) {
		if(e.getKeyCode()==KeyEvent.VK_UP){
			this.up = true;
		}
		if(e.getKeyCode()==KeyEvent.VK_DOWN){
			this.down = true;
		}
		if(e.getKeyCode()==KeyEvent.VK_LEFT){
			this.left = true;
		}
		if(e.getKeyCode()==KeyEvent.VK_RIGHT){
			this.right = true;
		}
	}

	public void keyReleased(KeyEvent e) {
		if(e.getKeyCode()==KeyEvent.VK_UP){
			this.up = false;
		}
		if(e.getKeyCode()==KeyEvent.VK_DOWN){
			this.down = false;
		}
		if(e.getKeyCode()==KeyEvent.VK_LEFT){
			this.left = false;
		}
		if(e.getKeyCode()==KeyEvent.VK_RIGHT){
			this.right = false;
		}
	}

	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub
		
	}
}
```

mfg. 
Dagobert


----------



## lohr (19. Mrz 2008)

Ist das nicht der standard code aus dem Tutorial?
Oder poste doch einfach mal die Zeilen die du verändert hast.


----------



## Quaxli (20. Mrz 2008)

Der Fehler ist vermutlich hier:


```
public void paintComponent(Graphics g) {
      super.paintComponents(g); 
      ...
```

Du überschreibst paintComponent(Graphics g) und der super-Aufruf lautet aber auf paintComponent*s*.
Diese Methode gibt es auf, aber natürlich sollte der super-Aufruf auch auf paintComponent lauten. 
Vermutlich bei der Methodenauswahl verklickt?


----------



## Dagobert (20. Mrz 2008)

Jo das könte gut sein. Aber das hab ich echt noch nicht gesehen mit dem s    
Aber jetzt gehts ganz gut. 
Vielen Dank


----------



## Dagobert (21. Mrz 2008)

So ich habe jetzt den ersten Teil durch, und mit der JavaDoc war das recht gut zu verstehen und hat viel gelernt.
Aber ich habe da noch ein Problem, das Spiel läuft recht gut. Nur stürzt es nach einer unbestimmten Zeit ab.(Desto mehr Objecte desto schneller). Mit Folgender Fehlermeldung:


> Exception in thread "Thread-4" java.util.ConcurrentModificationException
> at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
> at java.util.AbstractList$Itr.next(Unknown Source)
> at Rocket.doLogic(Rocket.java:49)
> ...


Woran könnte das liegen? Kommt die foreach Schleife nicht mit der größe des Vektor klar?
Ich gebe mal ein Beispiel:
Ich erzeuge jetzt alle 5 sek eine Rakete. Dabei ist die chance das das Spiel absürzt sehr gering. Im durchschnitt befinden sich nicht mehr als 20 Objecte im Array. Gerade ist es bei 26 abgestürzt. Jetzt bei 16 Objecten:


> Exception in thread "Thread-4" java.util.ConcurrentModificationException
> at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
> at java.util.AbstractList$Itr.next(Unknown Source)
> at Rocket.doLogic(Rocket.java:55)
> ...


Wenn ich jetzt alle 3 sek eine Raktete erzeuge:
Ist es gerade bei 22 Objekten abgestrzüt.
Ich weis zu diesem Verhalten leider keinen Rat. Kann mir hier jemand weite helfen?

Hier nochmal mein Code zur Hauptkalsse:

```
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.Vector;
import javax.imageio.ImageIO;
import javax.swing.*;

public class GamePanel extends JPanel implements Runnable, KeyListener, ActionListener {
	public static void main(String[] args) {
		new GamePanel(800, 600);
	}

	boolean game_running = true;
	boolean started = false;
	boolean once = false;
	long gameover = 0;
	int level;
	int punkte;
	
	long delta = 0;
	long last = 0;
	long fps = 0;
	
	Heli copter;
	BufferedImage[] rocket;
	BufferedImage[] explosion;
	BufferedImage background;
	Timer timerRocket;
	Vector<Sprite> actors;
	
	SoundLib slib;
	
	boolean up = false;
	boolean down = false;
	boolean left = false;
	boolean right = false;
	int helispeed = 50;

	public GamePanel(int w, int h) {
		this.setPreferredSize(new Dimension(w, h));
		this.setBackground(Color.cyan);
		JFrame frame = new JFrame();
		frame.setTitle("HubschrauberDemo");
		frame.setLocation(100, 100);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.addKeyListener(this);
		frame.add(this);
		frame.pack();
		frame.setVisible(true);

		doInitializations();
	}

	public void doInitializations() {
		
		this.last = System.nanoTime();
		
		BufferedImage[] heli = loadPics("pics/heli.gif", 4);
		rocket = loadPics("pics/rocket.gif", 8);
		explosion = loadPics("pics/explosion.gif", 5);
		background = loadPics("pics/background.jpg", 1)[0];

		this.actors = new Vector<Sprite>();
		
		slib = new SoundLib();
		slib.loadSound("bumm", "sound/boom.wav");
		slib.loadSound("rocket", "sound/rocket_start.wav");
		slib.loadSound("heli", "sound/heli.wav");
		
		this.gameover = 0;
		this.level = 1;
		this.punkte = 0;  
		
		this.copter = new Heli(heli, this.getWidth()/2, this.getHeight()/2, 100, this);
		actors.add(this.copter);
		if(isStarted()){
			slib.loopSound("heli");
		}
	
		createClouds();
		
		timerRocket = new Timer(3000, this);
		timerRocket.start();

		if(!this.once){		
			Thread t = new Thread(this);
			t.start();
			this.once = true;
		}
	}

	private void createClouds() {
		BufferedImage[] ci = loadPics("pics/cloud.gif", 1);
		for(int y = 10; y < getWidth(); y += 100){
			int x = (int)(Math.random()*getWidth());
			Cloud cloud = new Cloud(ci, x, y, 1000, this);
			actors.add(cloud);
		}
	}

	private void checkKeys() {
		if(this.up){
			copter.setVerticalSpeed(-this.helispeed);
		}
		if(this.down){
			copter.setVerticalSpeed(this.helispeed);
		}
		if(this.left){
			copter.setHorizontalSpeed(-this.helispeed);
		}
		if(this.right){
			copter.setHorizontalSpeed(this.helispeed);
		}
		if(!this.up&&!this.down){
			this.copter.setVerticalSpeed(0);
		}
		if(!this.left&&!this.right){
			copter.setHorizontalSpeed(0);
		}
	}

	private void moveObjects() {
		for(Movable mov:this.actors){
			mov.move(this.delta);
		}
		
	}

	private void doLogic() {
		
		Vector<Sprite> trash = new Vector<Sprite>();
		System.out.println("Objecte : " + actors.size());
		for(Movable mov:this.actors){
			mov.doLogic(this.delta);
			Sprite check = (Sprite) mov;
			if(check.remove){
				trash.add(check);
			}
		}
		for(int i = 0; i < this.actors.size(); i++){
			for (int n = i+1; n < this.actors.size(); n++){
				Sprite s1 = actors.elementAt(i);
				Sprite s2 = actors.elementAt(n);
				s1.collidedWith(s2);
			}
		}
		if(trash.size() > 0){
			for(Sprite s: trash){
				actors.remove(s);
			}
		}
		if(gameover>0){
			if(System.currentTimeMillis()-gameover>3000){
				stopGame();
			}
		}
	}

	private void stopGame() {
		timerRocket.stop();
		setStarted(false);
		slib.stopLoopingSound();
	}

	public void computeDelta() {
		this.delta = System.nanoTime() - this.last;
		this.last = System.nanoTime();
		this.fps = ((long) 1e9) / this.delta;
	}

	public void run() {
		while (game_running) {
			computeDelta();
			if(started){
				checkKeys();
				doLogic();
				moveObjects();
			}
			
			repaint();
			
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
			}
		}
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		g.drawImage(this.background, 0, 0, this);
		g.setColor(Color.red);
		g.drawString("FPS: " + this.fps, 20, 10);
		
		if(!isStarted()){
			return;
		}
		
		if(this.actors != null){
			for(Drawable draw:this.actors){
				draw.drawObjects(g);
			}
		}
	}

	private BufferedImage[] loadPics(String path, int NumberOfPics) {
		BufferedImage[] anim = new BufferedImage[NumberOfPics];
		BufferedImage source = null;

		URL pic_url = getClass().getClassLoader().getResource(path);

		try {
			source = ImageIO.read(pic_url);
		} catch (IOException e) {
		}

		for (int x = 0; x < NumberOfPics; x++) {
			anim[x] = source.getSubimage(x * source.getWidth() / NumberOfPics,
					0, source.getWidth() / NumberOfPics, source.getHeight());
		}
		return anim;
	}

	public void keyPressed(KeyEvent e) {
		if(e.getKeyCode()==KeyEvent.VK_UP){
			this.up = true;
		}
		if(e.getKeyCode()==KeyEvent.VK_DOWN){
			this.down = true;
		}
		if(e.getKeyCode()==KeyEvent.VK_LEFT){
			this.left = true;
		}
		if(e.getKeyCode()==KeyEvent.VK_RIGHT){
			this.right = true;
		}
		if(e.getKeyCode()==KeyEvent.VK_ENTER){
			if(!isStarted()){
				setStarted(true);
				doInitializations();
			}
		}
		if(e.getKeyCode()==KeyEvent.VK_ESCAPE){
			if(isStarted()){
				stopGame();
			} else {
				System.exit(0);
			}
		}
	}

	public void keyReleased(KeyEvent e) {
		if(e.getKeyCode()==KeyEvent.VK_UP){
			this.up = false;
		}
		if(e.getKeyCode()==KeyEvent.VK_DOWN){
			this.down = false;
		}
		if(e.getKeyCode()==KeyEvent.VK_LEFT){
			this.left = false;
		}
		if(e.getKeyCode()==KeyEvent.VK_RIGHT){
			this.right = false;
		}
	}

	public void keyTyped(KeyEvent e) {
		
	}
	
	public void setStarted(boolean startetd){
		this.started = startetd;
	}
	public boolean isStarted(){
		return this.started;
	}

	public void actionPerformed(ActionEvent e) {
		if(isStarted()&&e.getSource().equals(timerRocket)){
			createRocket();
		}
		
	}

	private void createRocket() {
		int x = 0;
		int y = (int) (Math.random()*getHeight());
		int hori = (int) (Math.random()*2);
		int speed = (int) (Math.random()*50);
		if(speed == 0){
			speed = 10;
		}
		if(hori==0){
			x = -30;
		}else{
			x = getWidth()+ 30;
		}
		
		Rocket rocket = new Rocket(this.rocket, x, y, 100, this, speed);
		if(x<0){
			rocket.setHorizontalSpeed(speed);
		}else{
			rocket.setHorizontalSpeed(-speed);
		}
		this.actors.add(rocket);
		//slib.playSound("rocket");
	}
	
	public void creatExplosion(int x, int y){
		Explosion ex = new Explosion(explosion, x, y, 100, this);
		actors.add(ex);
		slib.playSound("bumm");
	}
}
```

mfg. Dagobert


----------



## Dagobert (21. Mrz 2008)

So ich hab das ganze jetzt mal auf einem zweiten Rechner ausprobiert.
Dort scheint es ohne Probleme zu funktionieren. Ist meine Javamaschine irgendwie falsch eingestellt?
Auch getäuscht! Der große Rechner bekommt bei ca 75 Objecten auach Probleme


----------



## Dagobert (21. Mrz 2008)

So ich hab weiter Rechachirt. Ich habe ein Punkte Zähler eingebaut. Bei jeder Rakete die entfernt wird gibt es x Punkte. Hier mal der Code meiner doLogic
	
	
	
	





```
private void doLogic() {
		
		Vector<Sprite> trash = new Vector<Sprite>();
		System.out.println("Objecte : " + actors.size());
		for(Movable mov:this.actors){
			mov.doLogic(this.delta);
			Sprite check = (Sprite) mov;
			if(check.remove){
				this.punkte += check.punkte;
				trash.add(check);
			}
		}
		for(int i = 0; i < this.actors.size(); i++){
			for (int n = i+1; n < this.actors.size(); n++){
				Sprite s1 = actors.elementAt(i);
				Sprite s2 = actors.elementAt(n);
				s1.collidedWith(s2);
			}
		}
		if(trash.size() > 0){
			for(Sprite s: trash){
				actors.remove(s);
			}
		}
		if(gameover>0){
			if(System.currentTimeMillis()-gameover>3000){
				stopGame();
			}
		}
```
Mir ist da gerade etwas aufgefallen. Das Ausgeben der actor.size() findet nicht mehr statt. Aber es werden immer weiter Raketen erzeugt. Also friert die Run oder doLogic Methode ein ! aber warum?
Oder kommt das daher, das er versucht auf ein Element zur gleichen Zeit mehrmals zuzugreifen? bzw. Werte ändern?
Ich habe jetzt auch mal die Wolken entfernt. Der Fehler taucht immer noch auf... also muss das doch was mit den Racketen zu tun haben oder?
So hab jetzt mal alles gepackt und hier hochgeladen.
Es liegt auch ein Screen vom absturz dadbei, ich weis nicht ob das weiter hilft. Die blauen Kästchen stammen von meiner erweiterten Raketenlogik, da ich das doof fand, dass sie sich immer gegenseitig mitgenommen haben. =) 
Vllt. liegt da auch iwo der Fehler^^
Oder kann es sein das die "paintComponent" bei einer größeren Anzahl von zu zeichenden gegenständen einfach streigt?
mfg. Dagobert


----------



## Peterr (22. Mrz 2008)

ich habe, dasselbe Problem mit den Raketen! und ich habe den qc vom dem spieltut benutzt !


----------



## Dagobert (22. Mrz 2008)

So ich habe gerade weiter experimentiert. Es scheint ein Probelm mit der Zeichenmethode zu sein. 
Die Zeichenmethode ist ungeigenet für so eine große anzahl an Informationen und neuzeichnungen.
Aber welche ist besser geeignet?
Ich hab mal kurz folgendes Programm geschrieben:

```
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import java.util.Vector;
import javax.swing.*;

public class zeichnen extends JPanel implements Runnable, ActionListener{

	Timer objekt_erstellen;
	Vector<Rectangle2D>objecte;
	public zeichnen(int h, int w){
		setPreferredSize(new Dimension(h , w));
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.add(this);
		frame.pack();
		frame.setVisible(true);
		objekt_erstellen = new Timer(5, this);
		objekt_erstellen.start();
		objecte = new Vector<Rectangle2D>();
		Thread t = new Thread(this);
		t.start();
	}
	
	public void run(){
		System.out.println("Thread Gestartet!");
		while(true){
			System.out.println("Objekte: " + this.objecte.size());
			for(Rectangle2D re:this.objecte){
				re.setRect(re.getX()+Math.random(), re.getY()+Math.random(), getWidth(), getHeight());
			}
			this.repaint();
			try{
				Thread.sleep(100);
			}catch (InterruptedException e) {
				// TODO: handle exception
			}
		}
	}
	
	public static void main(String[] args) {
		zeichnen z = new zeichnen(800, 600);
	}

	public void actionPerformed(ActionEvent e) {
		if(e.getSource().equals(objekt_erstellen)){
			createRechteck();
		}
	}

	private void createRechteck() {
		int x = (int) (Math.random()*this.getWidth());
		int y = (int) (Math.random()*this.getHeight());
		int height = (int) (Math.random()*10);
		int width = (int) (Math.random()*10);
		Rectangle2D.Double rechteck = new Rectangle2D.Double(x,y,height,width);
		objecte.add(rechteck);
		System.out.println("Object erstellt!");
	}
	
	public void paintComponent(Graphics g) {
		System.out.println("Grafik gestartet");
		Graphics2D g2d = (Graphics2D) g;
		
		g2d.setColor(Color.red);
		g2d.drawString("test", 10, 10);
		
		if (this.objecte != null) {
			for (Rectangle2D re : this.objecte) {
				g2d.draw(re);
			}
		}
	}
}
```
Dieses Programm stürzt irgendwann auch einfach ab mit der selben Fehlermeldung
mfg. 
Dagobert


----------



## Quaxli (25. Mrz 2008)

Wie schon per PN geschrieben, kommt bei mir der Fehler (noch) nicht. Ich habe auch den Timer runter gesetzt, damit mehr Objekte kommen, aber der Fehler wird bei mir nicht geworfen.

Was die Zeichenmethode betrifft: Lies mal den 2. Teil vom Tut und dort besonders den Teil mit aktivem Rendern und volatile Images vielleicht löst das Dein Problem?


----------



## Quaxli (25. Mrz 2008)

Ich habe den Fehler jetzt gefunden, denke ich. Ich schreibe es mal hier, da es evtl. auch andere interessiert:

Du hast in der doLogic-Methode Deiner Rakete noch 2 weitere Loops über den Vector actors, der ja alle Sprites enthält. Dadurch kann es dann vorkommen, daß ein Sprite modifiziert werden soll, daß schon entfernt wurde oder anderweitig in Beschlag ist und die Exception wird geworfen.


----------



## tuxedo (26. Mrz 2008)

Eine "ConcurrentModificationException" ist AFAIK immer auf sowas wie ein Vector, Map oder sonstiges in der Art zurückzuführen,welcher an mehreren Stellen "bearbeitet und gelesen" werden darf. Der Zugriff ist also nicht wirklich Thread-Sicher. Man sollte sicher stellen, dass, wenn einer den Vector liest, ein anderer den Vector nicht verändert und umgekehrt. 

Man schnellsten kommt man da drauf, wenn man mal google mit der Exception füttert und nicht "wahllos" herumspekuliert und es auf die Anzahl der Objekte und/oder das Zeichnen schiebt ;-)


----------



## manuche (26. Mrz 2008)

Ich hatte das Problem mit meinem Spiel auch...
Exaktes Problem:

In der doLogic-Methode rauscht du mittels Iterator über alle Objekte im Vector... Dabei wirst du vermutlich irgendwo implementiert haben, dass du bei einer Aktion deinem Vektor ein Objekt hinzufügst (oder entfernst)... Dadurch wird der Iterator ungültig und wirft die ConcurrentModificationException!
Probiere einmal folgendes:
Erstelle dir einen zweiten Vector vom Typ Sprite...
Vor jedem Schleifendurchlauf deines GameLoops kopierst du mit der clone()-Methode deinen "Standard"-Vector  in den neuen Vektor... Im Gameloop arbeitest du nur den neuen Vektor ab, jedoch fügst du deine neuen Objekte in den alten ein...
So verhinderst du, dass der Iterator ungültig wird und eine Exception wirft!!!


```
Vector<Sprite> actors;
Vector<Sprite> actorsCopy;

public void run(){
  while (true){
    actorsCopy = actors.clone();
    doLogic;
    paintComponents();
  }
}

private void doLogic(){
for (Movable actObject : actorsCopy){
  ...
  createNewObject();
}

private void createNewObject(){
  actors.add (new Object());
}
```

gleiches gilt für die paint-Mehtode... Die Schleife immer über die Kopie laufen lassen während du zum Original hinzufügst!!!


----------



## Dagobert (26. Mrz 2008)

Danke für den Tipp. Ich habs versucht. Leide Funktioniert das auch nicht ganz.
Ich erhalte immer noch folgende Fehlermeldung:


> Exception in thread "Thread-4" java.util.ConcurrentModificationException
> at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
> at java.util.AbstractList$Itr.next(Unknown Source)
> at Flak.doLogic(Flak.java:101)
> ...


Hier nochmal meine 2 Klassen Gamepanel und Rocket:

```
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.Vector;
import javax.imageio.ImageIO;
import javax.swing.*;

public class GamePanel extends JPanel implements Runnable, KeyListener,
		ActionListener {
	public static void main(String[] args) {
		new GamePanel(800, 600);
	}

	boolean game_running = true;

	boolean started = false;

	boolean once = false;

	long gameover = 0;

	int level = 0;

	int points = 0;

	int pointsForLevel = 1500;

	String tip = "";

	long delta = 0;

	long last = 0;

	long fps = 0;

	Heli copter;

	BufferedImage[] imgRocket;

	BufferedImage[] imgExplosion;

	BufferedImage[] imgFlare;

	BufferedImage[] imgFlak;

	BufferedImage[] imgBullet;

	BufferedImage background;

	Timer timerRocket;

	Timer timerFlare;

	Timer sek;

	long playtime;

	Vector<Sprite> actors;

	Vector<Sprite> actorscopy;
	
	SoundLib slib;

	boolean up = false;

	boolean down = false;

	boolean left = false;

	boolean right = false;

	boolean flare = false;

	Thread pointcounter;

	int maxAnzahlFlare = 2;

	int ramFlare = 0;

	int helispeed = 100;

	int realoadFlaretime = 30;

	int maxRocketSpeed;

	JProgressBar flarebar;

	public GamePanel(int w, int h) {
		this.setPreferredSize(new Dimension(w, h));
		this.setBackground(Color.cyan);
		JFrame frame = new JFrame();
		frame.setTitle("HubschrauberDemo");
		frame.setLocation(100, 100);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.addKeyListener(this);
		frame.setLayout(new BorderLayout());
		frame.add(this, BorderLayout.CENTER);
		flarebar = new JProgressBar(0, this.realoadFlaretime);
		flarebar.setStringPainted(true);
		frame.add(flarebar, BorderLayout.NORTH);
		frame.setResizable(false);
		BufferedImage icon = loadPics("pics/heli.gif", 4)[0];
		frame.setIconImage(icon);
		frame.setCursor(Cursor.CROSSHAIR_CURSOR);
		frame.pack();
		frame.setVisible(true);

		doInitializations();
	}

	public void doInitializations() {

		this.last = System.nanoTime();

		if (!this.once) {
			// Laden der Bilddateien
			imgRocket = loadPics("pics/rocket.gif", 8);
			imgExplosion = loadPics("pics/explosion.gif", 5);
			// imgFlare = loadPics("pics/flare.gif", 1);
			imgFlak = loadPics("pics/flak.gif", 2);
			imgBullet = loadPics("pics/bullet.gif", 1);
			background = loadPics("pics/background.jpg", 1)[0];
			// Laden der Sounddateien
			slib = new SoundLib();
			slib.loadSound("bumm", "sound/boom.wav");
			slib.loadSound("rocket", "sound/rocket_start.wav");
			slib.loadSound("heli", "sound/heli.wav");
			Thread t = new Thread(this);
			t.start();
			this.once = true;
		}

		BufferedImage[] heli = loadPics("pics/heli.gif", 4);

		this.actors = new Vector<Sprite>();
		this.actorscopy = new Vector<Sprite>();

		this.gameover = 0;
		this.level = 1;
		this.points = 0;
		this.tip = "Drücke Enter zum Starten";

		this.copter = new Heli(heli, 100, 100, 100, this);
		actors.add(this.copter);

		Points points = new Points(this);
		pointcounter = new Thread(points);

		flarebar.setValue(0);

		if (isStarted()) {
			slib.loopSound("heli");
			timerFlare = new Timer(1000, this);
			pointcounter.start();
			this.maxRocketSpeed = 40;
			timerRocket = new Timer(50, this);
			timerRocket.start();
			creatClouds();
			creatFlak(0, getX(), getWidth() / 2, 50);
			creatFlak(getWidth(), getWidth(), getWidth() / 2, 50);
			playtime = 0;
			sek = new Timer(1000, this);
			sek.start();
			this.actorscopy = (Vector<Sprite>) this.actors.clone();
		}
	}

	public void computeDelta() {
		this.delta = System.nanoTime() - this.last;
		this.last = System.nanoTime();
		this.fps = ((long) 1e9) / this.delta;
	}

	public void run() {
		while (game_running) {
			computeDelta();
			if (started) {
				// System.out.println(actors.size());
				this.actorscopy = (Vector<Sprite>) this.actors.clone();
				checkKeys();
				doLogic();
				moveObjects();
			}
			repaint();

			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
			}
		}
	}

	private void doLogic() {
		/*
		 * Ein Vektor indem die zu löschenden Objekte hineinkopiert werden, und
		 * nach dem beenden dieser Methode plat gemacht //werden. Dies soll
		 * verhindern das Objete sofort gelöscht werden, da vllt. noch auf sie
		 * zugegriffen wird
		 */
		Vector<Sprite> trash = new Vector<Sprite>();

		for (Movable mov : this.actorscopy) {
			mov.doLogic(this.delta);
			Sprite check = (Sprite) mov;
			if (check.isRemove()) {
				trash.add(check);
			}
		}

		for (int i = 0; i < actorscopy.size(); i++) {
			for (int n = i + 1; n < actorscopy.size(); n++) {
				Sprite s1 = actorscopy.elementAt(i);
				Sprite s2 = actorscopy.elementAt(n);
				s1.collidedWith(s2);
			}
		}

		if (trash.size() > 0) {
			for (Sprite s : trash) {
				this.points += s.getPoints();
				actors.remove(s);
			}
		}

		if (gameover > 0) {
			if (System.currentTimeMillis() - gameover > 3000) {
				stopGame();
			}
		}
	}

	private void moveObjects() {
		for (Movable mov : this.actorscopy) {
			mov.move(this.delta);
		}

	}

	private void checkKeys() {
		if (this.up) {
			copter.setVerticalSpeed(-this.helispeed);
		}
		if (this.down) {
			copter.setVerticalSpeed(this.helispeed);
		}
		if (this.left) {
			copter.setHorizontalSpeed(-this.helispeed);
		}
		if (this.right) {
			copter.setHorizontalSpeed(this.helispeed);
		}
		if (!this.up && !this.down) {
			this.copter.setVerticalSpeed(0);
		}
		if (!this.left && !this.right) {
			copter.setHorizontalSpeed(0);
		}
		if (this.flare) {
			// if (this.level >= 2) {
			if (this.flarebar.getValue() == realoadFlaretime) {
				if (!timerFlare.isRunning()) {
					timerFlare.start();
				}
			}
		}
		// }
	}

	public void keyPressed(KeyEvent e) {
		if (e.getKeyCode() == KeyEvent.VK_UP) {
			this.up = true;
		}
		if (e.getKeyCode() == KeyEvent.VK_DOWN) {
			this.down = true;
		}
		if (e.getKeyCode() == KeyEvent.VK_LEFT) {
			this.left = true;
		}
		if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
			this.right = true;
		}
		if (e.getKeyCode() == KeyEvent.VK_SPACE) {
			this.flare = true;
		}
		if (e.getKeyCode() == KeyEvent.VK_ENTER) {
			if (!isStarted()) {
				setStarted(true);
				doInitializations();
			}
		}
		if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
			if (isStarted()) {
				stopGame();
			} else {
				System.exit(0);
			}
		}
	}

	public void keyReleased(KeyEvent e) {
		if (e.getKeyCode() == KeyEvent.VK_UP) {
			this.up = false;
		}
		if (e.getKeyCode() == KeyEvent.VK_DOWN) {
			this.down = false;
		}
		if (e.getKeyCode() == KeyEvent.VK_LEFT) {
			this.left = false;
		}
		if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
			this.right = false;
		}
		if (e.getKeyCode() == KeyEvent.VK_SPACE) {
			this.flare = false;
		}
	}

	public void keyTyped(KeyEvent e) {

	}

	public void setStarted(boolean startetd) {
		this.started = startetd;
	}

	public boolean isStarted() {
		return this.started;
	}

	public void actionPerformed(ActionEvent e) {
		if (isStarted() && e.getSource().equals(timerRocket)) {
			creatRocket();
		}
		if (isStarted() && e.getSource().equals(timerFlare)) {
			creatFlare();
			this.ramFlare++;
			if (this.ramFlare == this.maxAnzahlFlare) {
				this.ramFlare = 0;
				this.timerFlare.stop();
			}
		}
		if (isStarted() && e.getSource().equals(sek)) {
			this.playtime++;
			if (this.realoadFlaretime > flarebar.getValue()) {
				flarebar.setValue(flarebar.getValue() + 1);
				flarebar.setString("Flear Ready in "
						+ (this.realoadFlaretime - flarebar.getValue()));
				if (this.realoadFlaretime == flarebar.getValue()) {
					flarebar.setString("Flare Ready");
				}
			}
		}
	}

	private void creatClouds() {
		BufferedImage[] ci = loadPics("pics/cloud.gif", 1);
		for (int y = 10; y < getWidth() / 3; y += 100) {
			int x = (int) (Math.random() * getWidth());
			Cloud cloud = new Cloud(ci, x, y, 1000, this);
			actors.add(cloud);
		}
	}

	private void creatRocket() {
		int x = 0;
		int y = (int) (Math.random() * getHeight());
		int hori = (int) (Math.random() * 2);
		int speed = (int) (Math.random() * this.maxRocketSpeed);
		if (hori == 0) {
			x = -30;
		} else {
			x = getWidth() + 30;
		}

		Rocket rocket = new Rocket(this.imgRocket, x, y, 100, this, speed);
		if (x < 0) {
			rocket.setHorizontalSpeed(speed);
		} else {
			rocket.setHorizontalSpeed(-speed);
		}
		this.actors.add(rocket);
		// slib.playSound("rocket");
	}

	public void creatExplosion(int x, int y) {
		Explosion ex = new Explosion(this.imgExplosion, x, y, 100, this);
		actors.add(ex);
		slib.playSound("bumm");
	}

	public void creatFlare() {
		Flare flare1 = new Flare(this.imgExplosion, copter.x, copter.y
				+ copter.getHeight(), 100, this);
		Flare flare2 = new Flare(this.imgExplosion, copter.x
				+ copter.getWidth(), copter.y + copter.getHeight(), 100, this);
		actors.add(flare1);
		actors.add(flare2);
		if (flarebar.getValue() == this.realoadFlaretime) {
			flarebar.setValue(0);
			flarebar.setString("Flear Reloading");
		}
	}

	private void creatFlak(double startposition, double movefrom,
			double moveto, int speed) {
		Flak flak = new Flak(imgFlak, startposition, this.getHeight() - 30,
				1000, this, speed, movefrom, moveto);
		actors.add(flak);
	}

	private BufferedImage[] loadPics(String path, int NumberOfPics) {
		BufferedImage[] anim = new BufferedImage[NumberOfPics];
		BufferedImage source = null;

		URL pic_url = getClass().getClassLoader().getResource(path);

		try {
			source = ImageIO.read(pic_url);
		} catch (IOException e) {
		}

		for (int x = 0; x < NumberOfPics; x++) {
			anim[x] = source.getSubimage(x * source.getWidth() / NumberOfPics,
					0, source.getWidth() / NumberOfPics, source.getHeight());
		}
		return anim;
	}

	public void paintComponent(Graphics g) {
		Graphics2D g2d = (Graphics2D) g;
		super.paintComponent(g2d);
		g2d.drawImage(this.background, 0, 0, this);
		g2d.setColor(Color.red);
		g2d.drawString("FPS: " + this.fps, 20, 10);
		g2d.drawString("Punkte: " + this.points, 100, 10);
		g2d.drawString("Level: " + this.level, 200, 10);
		g2d.drawString(this.tip, 250, 10);
		g2d.drawString(String.valueOf(this.playtime), 600, 10);
		if (!isStarted()) {
			return;
		}

		if (this.actorscopy != null) {
			for (Drawable draw : this.actorscopy) {
				draw.drawObjects(g2d);
			}
		}
	}

	private void stopGame() {
		this.tip = "Zum neustarten Enter drücken";
		timerRocket.stop();
		pointcounter.stop();
		sek.stop();
		setStarted(false);
		slib.stopLoopingSound();
	}
}
```


```
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;

import javax.swing.text.StyledEditorKit.BoldAction;

public class Rocket extends Sprite {

	Rectangle2D target;

	Rectangle2D collision_risk;

	private Sprite locked = null;

	private int speed;

	private int minSpeed = 20;

	public Rocket(BufferedImage[] i, double x, double y, long delay,
			GamePanel p, int speed) {
		super(i, x, y, delay, p);
		if (speed < minSpeed) {
			setSpeed(minSpeed);
		} else {
			setSpeed(speed);
		}
		setPoints(speed);
		if (getY() < parent.getHeight() / 2) {
			setVerticalSpeed(speed);
		} else {
			setVerticalSpeed(-speed);
		}
	}

	public void doLogic(long delta) {
		if (isRemove()) {
			return;
		}
		super.doLogic(delta);
		if (getHorizontalSpeed() > 0) {
			target = new Rectangle2D.Double(getX() + getWidth(), getY(), parent
					.getWidth()
					- getX(), getHeight());
			collision_risk = new Rectangle2D.Double(getX(), getY() - 5,
					getWidth() + 50, getHeight() + 10);
		} else {
			target = new Rectangle2D.Double(0, getY(), getX(), getHeight());
			collision_risk = new Rectangle2D.Double(getX() - 50, getY() - 5,
					getWidth() + 50, getHeight() + 10);
		}

		for (Sprite s : parent.actorscopy) {
			if (!s.isRemove()) {
				if (this.locked == null && s.intersects(target)
						&& !(s instanceof Rocket) && !(s instanceof Cloud)
						&& !(s instanceof Flak)) {
					setVerticalSpeed(0);
					locked = s;
				}
			}
		}

		if (this.locked != null) {
			if (getY() < locked.getY() + (locked.getHeight() / 2)) {
				setVerticalSpeed(speed);
			}
			if (getY() > locked.getY() + (locked.getHeight() / 2)) {
				setVerticalSpeed(-speed);
			}
		}

		for (Sprite s : parent.actorscopy) {
			if (!s.isRemove()) {
				if (s.intersects(collision_risk) && s != this) {
					if (s instanceof Rocket) {
						setVerticalSpeed(speed);
						s.setVerticalSpeed(-speed);
					}
				}
			}
		}

		if (getHorizontalSpeed() > 0 && getX() > parent.getWidth()) {
			remove = true;
		}
		if (getHorizontalSpeed() < 0 && getX() + getWidth() < 0) {
			remove = true;
		}
	}

	public void setHorizontalSpeed(double dx) {
		if (isRemove()) {
			return;
		}
		super.setHorizontalSpeed(dx);

		if (getHorizontalSpeed() > 0) {
			setLoop(4, 7);
		} else {
			setLoop(0, 3);
		}
	}

	public boolean collidedWith(Sprite s) {
		if (this.intersects(s)) {
			if (s instanceof Heli) {
				if (this.checkOpaqueColorCollision(s)) {
					parent.creatExplosion((int) getX(), (int) getY());
					parent.creatExplosion((int) s.getX(), (int) s.getY());
					setRemove(true);
					s.setRemove(true);
					return true;
				}
			}

			if (s instanceof Rocket) {
				if (this.checkOpaqueColorCollision(s)) {
					parent.creatExplosion((int) getX(), (int) getY());
					parent.creatExplosion((int) s.getX(), (int) s.getY());
					setRemove(true);
					s.setRemove(true);
					return true;
				}
			}

			if (s instanceof Flare) {
				if (this.checkOpaqueColorCollision(s)) {
					parent.creatExplosion((int) getX(), (int) getY());
					parent.creatExplosion((int) s.getX(), (int) s.getY());
					setRemove(true);
					s.setRemove(true);
					return true;
				}
			}
			if (s instanceof Flak) {
				if (this.checkOpaqueColorCollision(s)) {
					parent.creatExplosion((int) getX(), (int) getY());
					parent.creatExplosion((int) s.getX(), (int) s.getY());
					setRemove(true);
					s.setRemove(true);
					return true;
				}
			}
			return true;
		}
		return false;
	}

	public void setSpeed(int speed) {
		this.speed = speed;
	}

	public int getSpeed() {
		return this.speed;
	}

	public void setLooked(Sprite locked) {
		this.locked = locked;
	}

	public Sprite getLooked() {
		return this.locked;
	}

	// public void drawObjects(Graphics g) {
	// super.drawObjects(g);
	// g.setColor(Color.red);
	// if (getHorizontalSpeed() > 0) {
	// g.drawRect((int) (x + getWidth()), (int) y,
	// (int) parent.getWidth(), (int) getHeight());
	// } else {
	// g.drawRect((int) 0, (int) y, (int) x, (int) getHeight());
	// }
	// g.setColor(Color.blue);
	// Graphics2D g2d = (Graphics2D) g;
	// if (getHorizontalSpeed() > 0) {
	// g2d.draw(collision_risk);
	// } else {
	// g2d.draw(collision_risk);
	// }
	// }
}
```
Ich probier es jetzt nochmal mit der Methode die mir Quaxli per PM geschickt hat. Melde mich dann gleich/nachher nochmal ob es klappt oder nicht. . .
mfg. Dagobert


----------



## Dagobert (26. Mrz 2008)

Ok bin nochmal Logisch drübergegangen und noch etwas geändert.

```
for (int i = 0; i < actorscopy.size(); i++) {
			for (int n = i + 1; n < actorscopy.size(); n++) {
				Sprite s1 = actors.elementAt(i);
				Sprite s2 = actors.elementAt(n);
				s1.collidedWith(s2);
			}
		}
```
Es klappt besser.... aber es ist nicht perfekt, er raucht immer noch weg


----------



## Quaxli (26. Mrz 2008)

Mag sein, aber das mußt Du selber auskaspern. Das ist jenseits des Tutorials und ich kann nicht jedes Spiel angucken, daß auf dem Tutorial aufbaut. Es gibt keine Standard-Lösung, sondern Du mußt eine eigene Realisierung finden.
Eine mögliche Lösung habe ich Dir per PN beschrieben, wenn Du die nicht verwendest, mußt Du selber rumprobieren.


----------



## manuche (26. Mrz 2008)

Dagobert hat gesagt.:
			
		

> Ok bin nochmal Logisch drübergegangen und noch etwas geändert.
> 
> ```
> for (int i = 0; i < actorscopy.size(); i++) {
> ...



wohl eher:


```
for (int i = 0; i < actorscopy.size(); i++) {
			for (int n = i + 1; n < actorscopy.size(); n++) {
				Sprite s1 = actorscopy.elementAt(i);
				Sprite s2 = actorscopy.elementAt(n);
				s1.collidedWith(s2);
			}
		}
```


----------

