I was creating an sscce, but there was just way too much code to post it here, so I will post sections and hopefully you can follow!
So, I have this class called Ship, within the class there is this:
Chunk 1:
keyboard.keyPress("SPACE", new Runnable(){
@Override
public void run(){
Laser laser = new Laser(
new Sprite("/media/images/laser.png"),
sscce.Ship.this.room);
sscce.Ship.this.room.addGameObjectAt(
laser,
sscce.Ship.this.getX() + (sscce.Ship.this.getWidth() / 2) - 3,
sscce.Ship.this.getY());
}
});
When the Space key is press it creates a Laser object and then we add it to the game where this object is stored within an ArrayList then draw to the screen in my main game loop, which loops through the ArrayList.
Laser is a very simple class, it looks like this:
Chunk 2:
package JGame.GameObject;
import JGame.Room.Room;
public class Laser extends GameObject{
public Laser(Sprite sprite, Room room){
super(sprite, room);
move.moveToY(0 - this.getHeight(), 5, new Runnable(){
@Override
public void run(){
Laser.this.destroy.destroyGameObject();
}
});
}
}
So Chunk 1 create Chunk 2 then adds it to the array list. This all works fine and dandy!
Chunk 3:
public void moveToY(int y, int speed, Runnable complete){
this.obj.moveEndY = y;
this.obj.moveAmountY = speed;
this.complete = complete;
this.obj.needsToMoveY = true;
}
This adds a move action to the newly created Laser. And then we move the object vertically (defined by chunk 2 and performed within the main game loop).
This next part is breaking the game, and by break I mean every thing stops (eventlisteners, movement, etc).
From Chunk 2 I say “When moveToY gets to its destination run the Runnable code” and the runnable code says to destroy the laser using destroyGameObject(). and the destory looks like this and is initialized in all of the Game Objects Constructors (Laser, Ship etc).
Chunk 4:
package JGame.Actions;
import JGame.GameObject.GameObject;
import JGame.Room.Room;
public class DestroyAction extends Action{
GameObject obj;
Room room;
public DestroyAction(Room room, GameObject obj){
this.room = room;
this.obj = obj;
}
public void destroyGameObject(){
room.removeGameObject(this.obj);
}
}
Chunk 4 just tells the room “Hey we need to remove this object from the list”
Chunk 5:
public class Room extends JPanel implements Runnable{
ArrayList<GameObject> gameObjects = new ArrayList<>();
public void run(){
try{
while(true){
// Do Event Listeners
// Move objects along Y axis
for(GameObject go : gameObjects){
if(go.needsToMoveY){
int objY = go.getY();
if(objY > go.moveEndY){
go.setY(objY - go.moveAmountY);
}else if(objY < go.moveEndY){
go.setY(objY + go.moveAmountY);
}else{
go.needsToMoveY = false;
// Executes Runnable parameter from moveToY()
go.move.actionComplete();
}
}
}
this.repaint();
Thread.sleep(roomSpeed);
}
}catch(Exception e){
}
}
public void removeGameObject(GameObject go){
gameObjects.remove(go);
System.gc();
}
}
So, finally here in Chunk 5, this is the main loop a lot of code has been striped out but this tests if it should be moving, if it is done, run actionComplete() which was passed in via moveToY() as the Runnable. Well, this Runnable says delete the object when it gets to it’s location. And when it runs the code within the Runnable 1 time, EVERYTHING stops. Movements stop; so if 2+ lasers were fired they should move upwards but they stop at their position and don’t move. Keyboard buttons stop working, so the arrows to move the Ship no longer respond so you can navigate the ship up/down/left/right it just sits at it’s last position of at the point where the Runnable was triggered for the first time.
So… Why is everything stopping? I just want to remove the object that was in the Runnable.
You have a serious problem with your code organization: you are modifying the
gameObjectslist inRoomdirectly (in methodremoveGameObject) while at the same time going through the list with an iterator (in methodrun). This will cause the iterator to complain (as in throw an exception). Note that you are catching—and silently ignoring!—exceptions in your mainrunmethod. Never throw away exceptions like that—they will tell you when something goes wrong.You need to organize your code so that you remove objects from the list only when there is no iterator traversing the list. You can do this by creating a way to mark objects for removal and then remove them in a separate step of your game loop.