错误解决方案和帮助改进敌人生成方法

Error solution and help improving enemie spawn methode

我试了一下 "project" 。它基本上是一个生存游戏。您可以使用 W、A、S、D 移动,并使用箭头键向不同方向射击。你基本上必须尽可能长时间地生存。敌人跟着你,他们被击中时冻结并在大约 3 秒后再次开始移动。

代码如下(执行"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 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)));
//      }
//  
//  }
}

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

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

玩了一段时间后得到了

java.util.ConcurrentModificationException

这是什么意思?

此外,我也在努力改善敌人的生成过程。现在有时会发生,敌人会在玩家体内生成。我想在玩家周围有一个假想的盒子,敌人不会在里面生成,敌人应该总是在 window 里面生成。

如有任何问题,欢迎随时提问:)

真诚的 维克托

来自 JavaDocs:

The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a 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,则选择一个新的随机位置。只要玩家和敌方精灵与屏幕区域相比​​相对较小,这种方法应该很有效。