Search code examples
javaarraylistslick2d

Using an ArrayLIst to create bullet objects in space invaders style game


I am currently working on a space invaders style game but I have run into a bit of trouble with multiple instances of bullets. At the moment I can only fire one. I have been trying to get it to work with an Array List but I just can't seem to get it to work. The closest I got I got it to working was, it fired multiple bullets but they all spawned from the same location as in the bullets didn't spawn in relation to the ships position. The game also crashed when I removed an object after it exceeded it's boundary. Can anyone help me to see where I am going wrong. Here is some code that I have so far the parts commented out are my attempts at getting the array list to work

    import java.util.ArrayList;
    import org.newdawn.slick.Input;
    import org.newdawn.slick.Graphics;
    import org.newdawn.slick.GameContainer;

    public class Player extends Entity 
    {
 private int speed = 5;
 private ArrayList<Bullet> bulletList;
 private boolean firing;
 private Bullet bullet;

public Player()
{   
    bullet = new Bullet();
    //bulletList = new ArrayList<Bullet>();
    this.setImage("ship");
    this.setPosition(350,450);
    this.setDimenseions(100, 100);
    this.createRectangle();
}

@Override
public void entityLogic(GameContainer gc, int deltaTime) 
{
    Input input = gc.getInput();

    if(input.isKeyDown(Input.KEY_A))
    {
        this.x -= speed;
    }

    if(input.isKeyDown(Input.KEY_D))
    {
        this.x += speed; 
    }

    if(input.isKeyDown(Input.KEY_W))
    {
        this.y -= speed;
    }

    if(input.isKeyDown(Input.KEY_S))
    {
        this.y += speed;
    }

    if(input.isKeyPressed(Input.KEY_SPACE))
    {
        firing = true;
        bullet.x = this.getX()+40;

        //BulletList.add(new Bullet());
    }

    if(firing)
    {
        /*Carries out the logic for the bullet*/

        //for(Bullet b : bulletList)
        //{
            //b.entityLogic(gc, deltaTime);
        //}

        //Moves the bullet negativly along the y axis
        bullet.entityLogic(gc, deltaTime);
    }
}

@Override
public void entityRendering(Graphics g) 
{
    g.drawImage(this.getImage(), this.getX(), this.getY());

    if(firing)
    {
        /*Draws each bullet object in the list*/

        //for(Bullet b : bulletList)
        //{
            //b.entityRendering(g);
        //}

        bullet.entityRendering(g);
    }
}

}

Solution

  • First of all forget about your Bullet bullet instance variable. You don't need it, the list is enough.

    Another thing is that you could use a LinkedList instead that an ArrayList because you don't need random access and you have to add and remove items frequently, when you iterate over bullets to check for collision use a ListIterator<T> and remove them on the fly.

    Finally it should be something like:

    List<Bullet> bullets = new ArrayList<Bullet>();
    
    public void entityLogic(GameContainer gc, int deltaTime) {
      // since this method is called many times you should shoot a bullet just every X msec
      if (spacebar pressed) {
        // you spawn a new bullet according to player position
        Bullet bullet = new Bullet(player.x,player.y);
        // you add it to the list
        bullets.add(bullet);
      }
    
      // destroy bullets which are outside the viewport
      for (int i = 0; i < bullets.size(); ++i) {
        Bullet bullet = bullets.get(i);
        if (bullet.isOutsideBounds()) {
          bullets.remove(i);
          i--;      
        }
    }
    
    public void entityRendering(Graphics g) {
      for (Bullet bullet : bullets)
        bullets.entityRenering(g);
    }
      }
    

    This is just to give you the basic idea.

    I don't know slick2d and how it manages the rendering and logic threads, if they are two different threads then you should use a syncronized list, eg:

    List<Bullet> bullets = Collections.synchronizedList(new ArrayList<Bullet>());