简体   繁体   中英

Trying to avoid a Force close after a bullet goes off screen

So I'm just messing around learning to create a Space invaders type game. I can get the bad guys to move, Great!!. Hero moves, Great!! Bullets move, Great!! However I try to remove my bullets once they leave the screen as to not eat up all resources and it force closes on me once it gets rid of the bullet. It goes off the screen. Hits the int of -2 and then we use the remove() and boom. Force Close.

Here is my code. I'm wondering if they access the size() at the same time and just cause a force close because of it.

//I removed everything that doesn't pertane to the bullets.
public class GameScreen{ 
    Bullet bullet = world.bullet;

    public GameScreen(Game game) {
        super(game);
        world = new World();
    }


    //Draws our bullets. 
    int bulletLength = bullet.bullets.size();
    for(int i = 0; i < bulletLength; i++) {
        Placement part = bullet.bullets.get(i);
        x = part.x * 32 + 11;
        y = part.y * 32;
        g.drawPixmap(Assets.bullet, x, y);
    }

Class that holds my bullets.

public class Bullet {
    public List<Placement> bullets = new ArrayList<Placement>();

    public Bullet() {

    }

    public void shoot(int x, int y){
        bullets.add(new Placement(x,y));
    }


    public void advance(){
    int len = bullets.size(); // gets all bullets.
    for(int i = 0; i < len; i++) {
        bullets.get(i).y --;

        if (bullets.get(i).y <= -2){//removes them once they are off the screen.
            bullets.remove(i);
        }
    }
}

This is what I use to keep track of placement.

package com.learning.planecomander;

public class Placement {
public int x, y;

public Placement(int x, int y) {
    this.x = x;
    this.y = y;
}
}

When going through your list to remove bullets, you can remove bullets from a list but that affects the list immediately instead of after your loop is done. Since you are traversing to the length of the list at the start, you are going off the end of the list since you've removed elements. An example is probably more helpful than that description.

Let's say you have a list with three bullets (which I'll call a, b, c to make the example easier). On a pass through the list, a and c are fine but b needs to be removed.

i = 0; bullets[0] = a; bullets[1] = b; bullets[2] = c;

First loop goes fine, second loop starts like this

i = 1; bullets[0] = a; bullets[1] = b; bullets[2] = c;

We remove b, but the loop keeps going

i = 2; bullets[0] = a; bullets[1] = c;

OH CRAP ARRAYINDEXOUTOFBOUNDS! PROGRAM CRASHES!

The way to solve this is to use a temp list to store the bullets that need to be removed, and then once your update loop is finished, make a call to bullets.removeAll(temp)

Doing two passes is a good answer. It makes the loops simpler and easy to understand. If you'd like to do it in one pass though, iterate through the list in reverse order, and when you remove a bullet you can go to the next one and not worry about blasting past the end of the ArrayList.

Alternatively, you can keep your bullets in a linked list, and run through the list with an Iterator, which you can also use to remove items from the list with. Removing from the beginning middle or end of an linked list is always a constant time operation. Whereas removing from the beginning of an ArrayList can be more expensive. If you need random access to the elements in the list, then they can be inefficient. Keep in mind though, if you're only dealing with a handful of objects, then it doesn't really matter.

For bonus points, you might want to put all of your objects in a list, and then have your central loop process them all and have your game objects respond polymorphically to calls like dead?, think, move, draw or whatever you think is appropriate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM