2016-01-30 1 views
0

Я пробовал себя на небольшом «проекте». Это игра на выживание. Вы перемещаетесь с помощью 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; 
     } 
    } 
} 

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

Поиграв некоторое время я получаю

java.util.ConcurrentModificationException

Что это значит?

Кроме того, я изо всех сил стараюсь улучшить вражеский икру. Прямо сейчас случается так, что враги появляются внутри игрока. Я хочу иметь воображаемую коробку вокруг игрока, где враги не появляются внутри, а враги должны всегда появляться внутри окна.

Если у вас есть какие-либо вопросы, пожалуйста, feeld спросить :)

искренне Виктора

+0

Вызывает ли какое-либо исключение какое-либо указание на то, что класс/строка вызывает проблему? –

+0

'Исключение в потоке "АВТ-EventQueue-1" java.util.ConcurrentModificationException \t в java.util.ArrayList $ Itr.checkForComodification (Unknown Source) \t в java.util.ArrayList $ Itr.next (Unknown Source) \t at TestGame.Window.paint (Window.java:24) \t at TestGame.Window.update (Window.java:32) ' – ViktorG

ответ

1

От JavaDocs:

Итераторов возвращаемого итераторы и ListIterator методов этого класса являются терпит неудачу -fast: если список структурно изменен в любое время после создания итератора, любым способом, кроме как через собственные методы удаления или добавления итератора, итератор будет вызывать исключение 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 в стороне от игрока, выберите новое случайное местоположение. Пока игровые и вражеские спрайты относительно малы по сравнению с площадью экрана, этот подход должен работать хорошо.

+0

Здравствуйте, не могли бы вы объяснить мне, где мой код точно создает исключение и почему ваш код предположительно решает? :) – ViktorG

+0

Спасибо за идею моей проблемы с нерестилищем врага :) – ViktorG