1

I tested myself on a little "project". It's basically a survival game. You move by using W,A,S,D and you shoot in different directions by using the arrow keys. Your goal is to survive for as long as possible. The enemies follow you and they freeze on hit. They start moving again after 3 seconds.

The code is the following (execute the "window" class)

Window-class

package TestGame;
    import java.awt.Graphics;



public class Window extends GameIntern{

public void init(){
    setSize(windowX,windowY);   
    Thread th = new Thread(this);
    th.start();
    offscreen = createImage(windowX,windowY);
    d = offscreen.getGraphics();
    addKeyListener(this);
}


public void paint(Graphics g){
    d.clearRect(0,0,windowX,windowY);//clear window
    d.drawString(numberEnemies.toString(), 10, 10);//"Score" number of enemies displayed
    d.drawRect(x, y, playerWidth, playerHeight);//draw player
    for(Enemy e : enemies){//draw all enemies
        d.drawRect(e.getx(), e.gety(), playerWidth, playerHeight);
    }
    for(Bullet b : bullets){//draw all bullets
        d.drawOval(b.getx(), b.gety(), bulletSize, bulletSize);
    }
    g.drawImage(offscreen,0,0,this);
}


public void update(Graphics g){
    paint(g);
}
}

GameIntern-class

    package TestGame;


import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;

public class GameIntern extends Applet implements Runnable , KeyListener {

    public int windowX = 854;//size of the window in x direction
    public int windowY = 460;//size of the window in y direction
    public static int x;//x-coordinate of player
    public static int y;//y-coordinate of player
    public int playerpositionX = x;
    public int playerpositionY = y;
    public int playerHeight = 20;//player height
    public int playerWidth = 20;//player width
    public int playerSpeed = 3;//pixel per frame
    public int bulletSize = 5;//diameter of bullets
    public int spawnTime = 4;//time for new enemies to spawn in seconds
    public int enemySleepTime = 180;//Time an enemy does nothing in Frames per second (180 in 60fps = 3sec)
    public boolean alive = true;
    public Image offscreen;
    public Graphics d;
    public boolean up,down,left,right;
    private int delay;
    private Random random= new Random();
    public Integer numberEnemies = new Integer(enemies.size());
    protected static List<Enemy> enemies = Collections.synchronizedList(new ArrayList<Enemy>()); //List of all enemies
    protected static List<Bullet> bullets = Collections.synchronizedList(new ArrayList<Bullet>());//List of all bullets
    protected static List<PowerUps> powerups = Collections.synchronizedList(new ArrayList<PowerUps>());//List of all powerups



    public void run() {
        this.x = 400;//startingposition x
        this.y = 240;//startingposition y

        double ns = 1000000000.0 / 60.0;    //60 "frames" 
        double delta = 0;
        long lastTime = System.nanoTime();
        while (alive) {
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            lastTime = now;
            while (delta >= 1) {
                repaint();
                tick();   //Line 53
                collisionEnemy();
//              collisionPowerUp();
                delta--;
            }
        }
    }

    /**
     * Method to calculate all objects and their positions per frame 
     */
    private void tick() {
        if(left == true){
            if(x>=0 + playerSpeed){
                x-=playerSpeed;
            }else{ x=0;}//Farthest left x-coordinate
            repaint();
        }
        if(right == true){
            if(x<=windowX - playerWidth - playerSpeed){
                x+=playerSpeed;
            }else{ x=windowX - playerWidth;}//Farthest right x-coordinate
            repaint();
        }
        if(up == true){
            if(y>=0 + playerSpeed){
                y-=playerSpeed;
            }else{ y=0;}//Highest y-coordinate
            repaint();
        }
        if(down == true){
            if(y<=windowY - playerHeight - playerSpeed){
                y+=playerSpeed;
            }else{y=windowY - playerHeight;}//Lowest y-coordinate
            repaint();
        }
        for (Enemy e : enemies) {   //Tick every enemy
            e.tick();
        }
        for (Bullet b : bullets){   //Tick every bullet  (LINE 92 !)
            b.tick();
        }
        if(delay % (60 * spawnTime) == 0){  //Spawn enemy 
            enemies.add(new Enemy(random.nextInt(windowX), random.nextInt(windowY)));
            numberEnemies++;
        }
        delay++;
    //Remove bullets, in contact with enemy
    LinkedList<Bullet> bulletsToRemove = new LinkedList<>();
    for(Enemy e : enemies){         //collision : enemy & bullet
        for(Bullet b : bullets){
            if(b.getx()+bulletSize >= e.getx() && b.getx() <= e.getx()+20){
                if(b.gety()+bulletSize >= e.gety() && b.gety() <= e.gety()+20){
                    e.setHit();
                    bulletsToRemove.add(b);
                }
            }
        }
    }
    for(Bullet b : bulletsToRemove){ //Remove bullets from ArrayList 
        bullets.remove(b);
    }

    }

    public void keyPressed(KeyEvent e) {

        if(e.getKeyCode() == 65){//W
            left=true;
        }
        if(e.getKeyCode() == 87){//A
            up=true;
        }
        if(e.getKeyCode() == 68){//S
            right=true;
        }
        if(e.getKeyCode() == 83){//D
            down=true;
        }
    }


    public void keyReleased(KeyEvent e) {

        if(e.getKeyCode() == 65){//Arrowkey left
            left=false;
        }
        if(e.getKeyCode() == 87){//Arrowkey up
            up=false;
        }
        if(e.getKeyCode() == 68){//Arrowkey right
            right=false;
        }
        if(e.getKeyCode() == 83){//Arrowkey dowm
            down=false;
        }
        if(e.getKeyCode() == 37){//Arrowkey left
            bullets.add(new Bullet(x,y,false,false,true,false)); //Direction the bullet has to go 
        }
        if(e.getKeyCode() == 38){//Arrowkey up
            bullets.add(new Bullet(x,y,true,false,false,false));//Direction the bullet has to go
        }
        if(e.getKeyCode() == 39){//Arrowkey right
            bullets.add(new Bullet(x,y,false,false,false,true));//Direction the bullet has to go
        }
        if(e.getKeyCode() == 40){//Arrowkey down
            bullets.add(new Bullet(x,y,false,true,false,false));//Direction the bullet has to go
        }
    }

    public void keyTyped(KeyEvent e){}

    /**
     * Method to see if the player collided with an enemy
     */
    public void collisionEnemy(){
        for(Enemy e : enemies){ 
            for(int i = 0;i <= playerWidth; i++){
                if(GameIntern.x+i >= e.getx() && GameIntern.x+i <= e.getx()+playerWidth){
                    if(GameIntern.y+i >= e.gety() && GameIntern.y+i <= e.gety()+playerHeight){
                        alive = false;
                    }
                }
            }
        }
    }

//  public void addEnemy(){
//      enemies.add(new Enemy(random.nextInt(windowX), random.nextInt(windowY)));
//      
//      //Spawn enemies inside the filed, not outside the boarder
//      if (playerpositionX < playerWidth * 2 || playerpositionX * 2 > windowX - 2*playerWidth || playerpositionY * 2 > windowY - 2*playerHeight || playerpositionY < playerHeight * 2){
//              enemies.add(new Enemy(random.nextInt(windowX - 3*playerWidth), random.nextInt(windowY - 3*playerHeight)+3*playerHeight));   
//      }else {
//          int temp1 = random.nextInt(windowX-3*playerWidth);
//          if (temp < playerpositionX){
//              
//          }
//          enemies.add(new Enemy(random.nextInt(windowX), random.nextInt(windowY)));
//      }
//  
//  }
}

Bullet-class

package TestGame;

public class Bullet extends GameIntern{
    public int x,y;
    public boolean up,down,left,right;
    public boolean remove;

    public Bullet(int x, int y,boolean up,boolean down, boolean left, boolean right){
        this.x = x + 8;
        this.y = y + 8;
        this.up = up;
        this.down = down;
        this.left = left;
        this.right = right;
    }

    public int getx(){
        return this.x;
    }
    public int gety(){
        return this.y;
    }
    public void setRemove(){
        remove=true;
    }

    public void tick() {

        if (up == true) y-=2;
        if (down == true) y+=2;
        if (left == true) x-=2;
        if (right == true) x+=2;
        if(x < 0){
            remove = true;
        }
        if(x > 840){
            remove = true;
        }
        if(y < 0){
            remove = true;
        }
        if(y > 470){
            remove = true;
        }
    }
}

Enemy-class

package TestGame;

public class Enemy extends GameIntern {

    public int x,y;
    public boolean hit = false;
    public int counter = 0;

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

    public int getx(){
        return this.x;
    }
    public int gety(){
        return this.y;
    }
    public void setHit(){
        hit = true;
        counter = enemySleepTime;
    }

    public void tick() {
        if(counter == 0){
            if(hit == true){
                hit=false;
            }
            if (x < GameIntern.x) x++;
            if (x > GameIntern.x) x--;
            if (y < GameIntern.y) y++;
            if (y > GameIntern.y) y--;
        }else {counter--;}
    }
}

After playing for a while i get

Expeption

I don't understand this exception. Can someone explain to me what am I doing wrong?

How can I solve this problem?

Aventinus
  • 1,322
  • 2
  • 15
  • 33
ViktorG
  • 505
  • 1
  • 7
  • 30
  • Please can you indicate (with a comment like `// THIS IS LINE 92`) where line 92 of `GameIntern.java` is? – Andy Turner Feb 01 '16 at 17:17
  • Sure, edited the question – ViktorG Feb 01 '16 at 17:20
  • 1
    This means that you are looping over an `ArrayList` and **modifying it at the same time**. This is not allowed. You must use an `Iterator` and the `remove()` or `add()` methods to modify a `Collection` during iteration. – Boris the Spider Feb 01 '16 at 17:21
  • You are also violating Swing thread safety in multiple place. No component of the GUI can be updated from any thread other then the EDT. – Boris the Spider Feb 01 '16 at 17:22
  • I don't really know what Swing thread safety is. I'm teaching myself and I`ve never heard of that. Can you explain it? Also, do you mean that i try to redraw the enemies but at the same time one of them is deleted? how can that be? – ViktorG Feb 01 '16 at 17:24
  • 2
    Simple, your `keyReleased` method called `bullets.add` and your `tick` method loops over `bullets`. Release a button during a tick and **bang**. A `Collection` cannot be modified during iteration. – Boris the Spider Feb 01 '16 at 17:43
  • 1
    As for Swing's threading model - why not start with [the tutorial](https://docs.oracle.com/javase/tutorial/uiswing/concurrency/). Suffice it to say you have a large number of issues here, and I don't think any of them have a quick fix. – Boris the Spider Feb 01 '16 at 17:44
  • 1) Why code an applet? If it is due to the teacher specifying it, please refer them to [Why CS teachers should **stop** teaching Java applets](http://programmers.blogoverflow.com/2013/05/why-cs-teachers-should-stop-teaching-java-applets/). 2) Why use AWT? See [this answer](http://stackoverflow.com/questions/6255106/java-gui-listeners-without-awt/6255978#6255978) for many good reasons to abandon AWT using components in favor of Swing. – Andrew Thompson Feb 03 '16 at 03:12

0 Answers0