ConcurrentModificationException al eliminar la viñeta del juego
Frecuentes
Visto 223 veces
1
I have to create Space Invaders for my programming course in college which would be fine but I have a problem with removing a bullet from the game.
I'm storing all my enemies and bullets in separate ArrayLists.
This is my main class.
package uk.ac.wnc.pot13000765.space_invaders;
import java.util.ArrayList;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
public class SpaceInvaders {
private ArrayList<Enemy> enemies = new ArrayList<Enemy>();
private static ArrayList<Bullet> bullets = new ArrayList<Bullet>();
private Player player;
public SpaceInvaders() {
//Setup and create the OpenGL Context + Window
try {
Display.setDisplayMode(new DisplayMode(800, 600));
Display.setTitle("Unit 14 Space Invaders in Java by Liam Potter - POT13000765");
Display.create();
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, 800, 0, 600, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glClearColor(0f, 0f, 0f, 1f);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
} catch(LWJGLException e) {
System.err.print(e);
System.exit(1);
}
Time.getDelta();
Time.setLastFps(Time.getTime());
//Setup
player = new Player(40, 40, 50, 50);
//Enemies
enemies.add(new Enemy(40, 540, 25, 25));
while(!Display.isCloseRequested()) {
gameLoop(Time.getDelta());
}
Display.destroy();
}
private void gameLoop(int delta) {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
//Update
player.update(delta);
if(enemies.size() > 0) for(Enemy e: enemies) e.update(delta);
if(bullets.size() > 0) for(Bullet b: bullets) b.update(delta);
//Render
player.draw();
if(enemies.size() > 0) for(Enemy e: enemies) e.draw();
if(bullets.size() > 0) for(Bullet b: bullets) b.draw();
Display.sync(60);
Display.update();
Time.updateFps();
}
public int getWindowWidth() {
return Display.getWidth();
}
public int getWindowHeight() {
return Display.getHeight();
}
public static void spawnBullet(Bullet b) {
bullets.add(b);
}
public static void destroyBullet(Bullet b) {
bullets.remove(b);
}
public static void main(String[] args) {
new SpaceInvaders();
}
}
And this is my Bullet class:
package uk.ac.wnc.pot13000765.space_invaders;
import org.lwjgl.opengl.GL11;
public class Bullet extends Entity {
public Bullet(int x, int y, int width, int height) {
super(x, y, width, height);
}
@Override
public void update(int delta) {
if(!(getY() > 600)) setY(getY() + 1);
else dispose();
System.out.println(getY());
}
@Override
public void draw() {
GL11.glColor3f(1.0f, 0.5f, 0.5f);
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex2i(getX(), getY());
GL11.glVertex2i(getX() + getWidth(), getY());
GL11.glVertex2i(getX() + getWidth(), getY() + getHeight());
GL11.glVertex2i(getX(), getY() + getHeight());
GL11.glEnd();
}
@Override
public void dispose() {
SpaceInvaders.destroyBullet(this);
}
}
This is the exact error I am getting:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at uk.ac.wnc.pot13000765.space_invaders.SpaceInvaders.gameLoop(SpaceInvaders.java:62)
at uk.ac.wnc.pot13000765.space_invaders.SpaceInvaders.<init>(SpaceInvaders.java:50)
at uk.ac.wnc.pot13000765.space_invaders.SpaceInvaders.main(SpaceInvaders.java:91)
I understand that I can use ListIterators to fix this but I can't figure out how to implement them in my main class.
2 Respuestas
3
Este bucle:
if(bullets.size() > 0) for(Bullet b: bullets) b.update(delta);
calls Bullet.update which can call dispose() in which you're doing
SpaceInvaders.destroyBullet(this);
que invoca
bullets.remove(b);
So essentially, there is a situation in which you're looping over an ArrayList and remove objects from it while looping. That is not allowed. You could use a CopyOnWriteArrayList instead, the operation is allowed there. This is rather expensive, though, as it copies the whole array when doing a modification. Another possible solution would be collecting the Bullets to be removed in dispose() and removing them after the update loop.
respondido 27 nov., 13:00
0
This happens because you cannot iterate through the ArrayList and modify the elements in the same time. What you can do is
1)
Iterator< Bullet > it = bullets.iterator();
while (it.hasNext() )
{
Bullet b = it.next();
bullets.update(b)
}
2) Also (though I believe you should do the first thing) you can use a java.util.concurrent.CopyOnWriteArrayList and not change your code.
respondido 27 nov., 13:00
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas java arraylist concurrentmodification or haz tu propia pregunta.
Thanks, I'm using the CopyOnWriteArrayList now. At the moment it doesn't matter how resource intensive it is as I'm only going to be running it on two machines maximum. - alfarero liam