Nochmal Quaxli Spieletutorial ;)

Ruderer1993

Aktives Mitglied
Hey, hatte heute Mittag schon mal eine Frage zu Quaxlis Spieletutorial und dort konntet ihr mir schon super helfen, daher hoffe ich das ihr mir auch dieses mal so toll helfen könnt 😉

Ich bekomme immer die folgende Excpetion nach kurzer Spieldauer:
Java:
Exception in thread "Thread-3" java.util.ConcurrentModificationException
	at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
	at java.util.AbstractList$Itr.next(AbstractList.java:343)
	at GamePanel.doLogic(GamePanel.java:198)
	at GamePanel.run(GamePanel.java:252)
	at java.lang.Thread.run(Thread.java:680)

Wieso ? Ich verstehe das nicht, das muss irgendwann mit dem ListIterator bzw der for each Schleife zu tun haben, glaube ich.

Hier mal die GamePanel Klasse (wenn ihr mehr braucht sagt bescheid, steht ja aber quasi auch alles im Tutorial:
Java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ListIterator;
import java.util.Vector;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;


public class GamePanel extends JPanel implements Runnable, KeyListener,ActionListener {
	private static final long serialVersionUID = 1L;
	JFrame f;
	
	long delta; //Zeit des letzten Durchgangs
	long fps;   //Bildrate
	long last;  //letzte Systemzeit
	int time;
	long gameover = 0;
	
	Heli heroObject;
	Vector <Sprite> actors;
	Vector <Sprite> painter;
	
	boolean up;
	boolean down;
	boolean left;
	boolean right;
	boolean started;
	int speed = 75;
	
	SoundLib soundLib;
	
	
	BufferedImage[] rocket;
	BufferedImage[] explosion;
	Timer timer;
	Timer timeScore;
	BufferedImage background;
	
	public static void main(String[] args) {
		new GamePanel(800,600);
	}
	
	public GamePanel(int w, int h) {
		this.setPreferredSize(new Dimension(w,h));
		this.setBackground(Color.blue);
		
		f = new JFrame("JEscape");
		f.setLocation(100,100);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.add(this);
		f.addKeyListener(this);
		f.pack();
		f.setVisible(true);
				
		Thread th = new Thread(this); //Spielschleife in eigenem Thread
		th.start();
	}
	
	private void doInitializations() { //Methode für "einmalige Aktionen" - Laden von Images etc..
		last = System.nanoTime();
		gameover = 0;
		
		BufferedImage[] hero = loadPics("pics/hero.gif",4);
		rocket = loadPics("pics/rocket.gif",8);
	    background = loadPics("pics/background.jpg",1)[0];
	    explosion = loadPics("pics/explosion.gif",5);
	    
	    soundLib = new SoundLib();
	    soundLib.loadSound("bumm", "sound/boom.wav");
	    soundLib.loadSound("background", "sound/background.wav");
	    soundLib.loadSound("gameover", "sound/gameover.wav");
		
		actors = new Vector<Sprite> ();
		painter = new Vector<Sprite> ();
		heroObject = new Heli(hero,400,300,100,this);
		actors.add(heroObject);
		
		createClouds();
		
		timer = new Timer(1000,this);
		timer.start();
		
		timeScore = new Timer(1000,this);
		timeScore.start();
		started = true;
	}
	
	private void computeDelta() { //Errechnung des Schleifendurchlaufes
		delta = System.nanoTime()-last;
		last = System.nanoTime();
		fps = ((long) 1e9)/delta;
	}
	
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		g.drawImage(background, 0, 0,this);
		g.setColor(Color.white);
		g.drawString("FPS: "+Long.toString(fps), 20, 10);
	    g.drawString("Zeit: "+time,730,10);
		if(!started) {
			return;
			}
		
		for(ListIterator<Sprite> it = painter.listIterator();it.hasNext();) {
			Sprite r = it.next();
			r.drawObjects(g);
		}
	}
	
	public void createClouds() {
		BufferedImage[] bi = loadPics("pics/cloud.gif",1);
		
		for(int y=10;y<getHeight();y+=50) {
			int x = (int)(Math.random()*getWidth());
			Cloud cloud = new Cloud(bi,x,y,1000,this);
			actors.add(cloud);
		}
	}
	
	public void createExplosion(int x, int y) {
		ListIterator<Sprite> it = actors.listIterator();
		it.add(new Explosion(explosion,x,y,100,this));
		soundLib.playSound("bumm");
	}
	
	
	private void createRocket() {
		int x = 0;
		int y = (int) (Math.random()*getHeight());
		int hori = (int)(Math.random()*2);
		
		if(hori== 0) {
			x = -30;
		} else {
			x = getWidth()+30;
		}
		
		Rocket rock = new Rocket(rocket,x,y,100,this);
		if(x<0) {
			rock.setHorizontalSpeed(100);
		} else {
			rock.setHorizontalSpeed(-100);
		}
		
		ListIterator<Sprite> it = actors.listIterator();
		it.add(rock);
	
	
		
		
	}
	
	
	private void checkKeys() {
		if(up) {
			heroObject.setVerticalSpeed(-speed);
		}
		
		if(down) {
			heroObject.setVerticalSpeed(speed);
		}
		
		if(left) {
			heroObject.setHorizontalSpeed(-speed);
		}
		
		if(right) {
			heroObject.setHorizontalSpeed(speed);
		}
		
		if(!up&&!down) {
			heroObject.setVerticalSpeed(0);
		}
		
		if(!left&&!right) {
			heroObject.setHorizontalSpeed(0);
		}
	}
	
	private void doLogic() {
		for(ListIterator<Sprite> it = actors.listIterator(); it.hasNext();) {
			Sprite r = it.next();
			r.doLogic(delta);
			
			if(r.remove) {
				it.remove();
			}
		}
		for(int i=0;i< actors.size();i++) {
			for(int n = i+1;n<actors.size();n++) {
				Sprite s1 = actors.elementAt(i);
				Sprite s2 = actors.elementAt(n);
				s1.collidedWith(s2);
			}
		}
		
		if (heroObject.remove && gameover == 0) {
			gameover = System.currentTimeMillis();
		}
		
		if(gameover > 0) {
			if(System.currentTimeMillis()-gameover>3000) {
				stopGame();
			}
		}
	}
	
	private void stopGame() {
		timer.stop();
		setStarted(false);
		soundLib.playSound("gameover");
		soundLib.stopLoopingSound();
	}
	
	private void startGame() {
		doInitializations();
		setStarted(true);
		soundLib.loopSound("background");
	}
	
	private void moveObjects() {
		for(ListIterator<Sprite> it = actors.listIterator(); it.hasNext();) {
			Sprite r = it.next();
			r.move(delta);
		}
	}
	
	
	@Override
	public void run() {
		while(f.isVisible()) {
			computeDelta(); 
			
		if(isStarted()) {
			checkKeys();
			doLogic();
			moveObjects();
			cloneVectors();
		}
			repaint();
			
			try {
				Thread.sleep(10);
			} catch(InterruptedException e) {}
		}
		
	}
	@SuppressWarnings("unchecked")
	private void cloneVectors() {
		painter = (Vector<Sprite>) actors.clone();
	}
	
     private BufferedImage[] loadPics(String path, int pics) {
		
		BufferedImage[] anim = new BufferedImage[pics];
		BufferedImage source = null;
		
		URL pic_url = getClass().getClassLoader().getResource(path);
		
		try {
			source = ImageIO.read(pic_url);
		} catch(IOException e) {System.out.println("Argh..."); e.printStackTrace();}
		
		for(int x=0; x<pics;x++) {
			anim[x] = source.getSubimage(x*source.getWidth()/pics, 0, source.getWidth()/pics, source.getHeight());
		
		}
		
		return anim;
	}
     
     public boolean isStarted() {
    	 return started;
     }
     
     public void setStarted(boolean started) {
    	 this.started = started;
     }
     
    @Override
    public void actionPerformed(ActionEvent e)
    {
    	if(isStarted() && e.getSource().equals(timer)) {
    		createRocket();
    	}
    	
    	if(isStarted() && e.getSource().equals(timeScore)) {
    		time = time +1;
    	}
    }
	@Override
	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;
		}
		
		
	}

	@Override
	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;
		}
		
		if(e.getKeyCode() == KeyEvent.VK_ENTER) {
			if(!isStarted()) {
                startGame();				
			}
		}
		
		if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
			if(isStarted()) {
				setStarted(false);
				timer.stop();
				stopGame();
			} else {
				
			   // f.dispose();
			}
		}
	}

	@Override
	public void keyTyped(KeyEvent e) {
		
	}
     
     

}

Vielen Vielen Dank !
 
Irgendwo wird während des Durchlaufs in der Schleife die Liste abgeändert. Dann knallt es.

Vom Code her würde ich folgenden Ablauf vermuten:

Thread A führt Spiellogik aus, entfernt ein Objekt während Thread B, der EDT, die Spielobjekte durchläuft um diese zu zeichnen.
Die einfachste Lösung wäre es den Zugriff auf die Liste zu synchronisieren.
 
Ohne den Code angesehen zu haben, d.h. Pseudo-Code:

Java:
// Thread A:
synchronized(liste){
     // manipulieren
}

// Thread B: (vermutlich EDT, also zB in der paint-Component)
synchronized(liste){
    // zugriff
}
 
PS:

Danke gerade hinzugefügt und es scheint zu funktionieren, nochmals danke
Spar dir den Text, klick statt dessen auf den "Danke" Button unter meinem Beitrag, darüber freu ich mich mehr 😀 (Aber bitte 🙂)

PPS: Bitte klicke oben im Topic auf "Thema als erledigt markieren" wenn du keine weiteren Fragen hast.
 

Zurück
Oben