错误解决方案并帮助改进enemie spawn方法

时间:2016-01-30 10:13:43

标签: java exception graphics applet

我尝试了一个小项目" 。它基本上是一种生存游戏。使用W,A,S,D移动,使用箭头键向不同方向拍摄。你基本上必须尽可能长久地生存。敌人跟着你,他们会在命中时冻结并在大约3秒后再次开始移动。

代码如下(执行"窗口"类)

窗口级

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级

    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 ArrayList<Enemy> enemies = new ArrayList<Enemy>(); //List of all enemies
    protected static ArrayList<Bullet> bullets = new ArrayList<Bullet>();//List of all bullets
    protected static ArrayList<PowerUps> pUps = 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();
                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
            b.tick();
        }
        if(delay % (60 * spawnTime) == 0){  //Spawn enemy 
            enemies.add(new Enemy(random.nextInt(windowX), random.nextInt(windowY)));
            numberEnemies++;
        }
        delay++;

        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();
                        b.setRemove();
                    }
                }
            }
        }
        for(int i = 0; i< bullets.size(); i++){ //Remove bullets from ArrayList 
            if(bullets.get(i).remove){
                bullets.remove(i);
            }
        }

    }

    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)));
//      }
//  
//  }
}

子弹级

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;
        }
    }
}

敌人级

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--;}
    }
}

玩了一会儿后我得到了

  

java.util.ConcurrentModificationException

这是什么意思?

另外,我努力改善敌人的产卵进程。现在它有时会发生,敌人在玩家内部产生。我希望在玩家周围有一个假想的盒子,敌人不会在里面产生,敌人应该总是在窗口内产卵。

如果您有任何疑问,请随时问:)

真诚 尤

1 个答案:

答案 0 :(得分:1)

来自JavaDocs:

  

此类的iterator和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除非通过迭代器自己的删除或者添加方法,迭代器将抛出一个ConcurrentModificationException。

问题可能是因为您在尝试在单独的线程中绘制项目时从ArrayList删除项目符号。问题是两个线程同时在bullets列表上进行迭代。

    //The following for loop is likely the cause
    for(int i = 0; i< bullets.size(); i++){ 
        if(bullets.get(i).remove){
            bullets.remove(i); // <-- this is the problem 
        }
    }

相反,请尝试使用线程安全的实现,例如

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

此外,您应该更改删除代码以避免IndexOutOfBoundsException

    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);
    }

关于产生过程,一个简单的方法是定义与玩家​​的最小距离,称之为minDist。现在只需在屏幕上的任意位置选择一个随机位置,将其称为p1。如果p1距离播放器小于minDist,请选择一个新的随机位置。只要玩家和敌人的精灵与屏幕区域相比​​相对较小,这种方法应该可以很好地运作。