太空入侵者生成初始的小行星 Java 失败

10 浏览
0 Comments

太空入侵者生成初始的小行星 Java 失败

我写了一个类似于太空侵略者的游戏,其中有一个火箭飞船和一些陨石对象会下落,游戏的目标是存活下来并射击尽可能多的陨石。\n我在游戏开始时生成陨石遇到了一些问题。\n我的思路是,在 GamePanel 构造函数中,在启动 ActionListener Timer 之前,我生成了一个固定数量为 Globals.NUM_OF_ASTEROIDS 的陨石,并且每当一个陨石在 updateGameState 方法中被销毁时,一个新的陨石会被添加到 asteroids ArrayList 中。\n我尝试了一个简单的 for 循环来生成所有陨石,然后启动一个计时器。我还尝试在计时器中生成陨石。这两种解决方案都会产生一堆错误:\n

Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
    at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
    at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
    at GamePanel.updateGameState(GamePanel.java:65)
    at GamePanel$1.actionPerformed(GamePanel.java:42)
    at java.desktop/javax.swing.Timer.fireActionPerformed(Timer.java:311)
    at java.desktop/javax.swing.Timer$DoPostEvent.run(Timer.java:243)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

\n我还将我的 GamePanel 类的源代码附上。请注意,这还是一个未完成的项目。\n我在构造函数中标记了有问题的部分。\n

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
import javax.swing.Timer;
public class GamePanel extends JPanel implements KeyListener {
    private static final long serialVersionUID = -1036125108881682872L;
    private List asteroids;
    private List projectiles;
    private RocketShip rocketShip;
    private Timer timer;
    private int end;    //0 - the game is still in progress
                        //1 - the game has ended
    public GamePanel() {
        setBackground(Color.BLACK);
        asteroids = new ArrayList<>();
        projectiles = new ArrayList<>();
        rocketShip = new RocketShip(Globals.WINDOW_WIDTH / 2, Globals.SHIP_HEIGHT);
        this.end = 0;
        addKeyListener(this);
        setFocusable(true);
        /////////////////////////////////////////////////////////
        //这个循环引起了错误。                  /////
        for(int i = 0; i < Globals.NUM_OF_ASTEROIDS; i++) { /////
            asteroids.add(new Asteroid());                  /////
        }                                                   /////
        /////////////////////////////////////////////////////////
        timer = new Timer(10, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                updateGameState("");
                repaint();
            }
        });
        timer.start();
    }
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        rocketShip.paintComponent(g);
        for (Asteroid asteroid : asteroids) {
            asteroid.paintComponent(g);
        }
        for (Projectile projectile : projectiles) {
            projectile.paintComponent(g);
        }
    }
    public void updateGameState(String direction) {
        rocketShip.move(direction);
        for (Asteroid asteroid : asteroids) {
            asteroid.move();
            if (asteroid.isOutOfBounds()) {
                asteroids.remove(asteroid);
                asteroids.add(new Asteroid());
            }
        }
        for (Projectile projectile : projectiles) {
            projectile.move();
            // projectile is out of bounds
            if (projectile.getX() - (projectile.getHeight() / 2) > Globals.WINDOW_HEIGHT) {
                projectiles.remove(projectile);
            }
        }
        // check for collisions
        //asteoids with projectiles
        for (Asteroid asteroid : asteroids) {
            for (Projectile projectile : projectiles) {
                if (projectile.getX() + projectile.getWidth() > asteroid.getX()
                        && projectile.getX() < asteroid.getX() + asteroid.getWidth()
                        && projectile.getY() + projectile.getHeight() > asteroid.getY()
                        && projectile.getY() < asteroid.getY() + asteroid.getHeight()) {
                    asteroids.remove(asteroid);
                    projectiles.remove(projectile);
                    //add a new asteroid
                    asteroids.add(new Asteroid());
                    //score increase
                }
            }
        }
        // asteroids with rocketship
        for (Asteroid asteroid : asteroids) {
            if (rocketShip.getX() + rocketShip.getWidth() > asteroid.getX()
                    && rocketShip.getX() < asteroid.getX() + asteroid.getWidth()
                    && rocketShip.getY() + rocketShip.getHeight() > asteroid.getY()
                    && rocketShip.getY() < asteroid.getY() + asteroid.getHeight()) {
                // rocketShip and asteroid have collided
                asteroids.remove(asteroid);
                // game over logic
                this.end = 1;
                timer.stop();
            }
        }
    }
    @Override
    public void keyTyped(KeyEvent e) {
        if (e.getKeyChar() == ' ') {
            Projectile projectile = new Projectile(rocketShip.getX() + rocketShip.getWidth() / 2, rocketShip.getY());
            projectiles.add(projectile);
        }
    }
    @Override
    public void keyPressed(KeyEvent e) {
        // TODO Auto-generated method stub
        int keyCode = e.getKeyCode();
        if(keyCode == KeyEvent.VK_RIGHT) {
            updateGameState("right");
        }
        if(keyCode == KeyEvent.VK_LEFT) {
            updateGameState("left");
        }
    }
    @Override
    public void keyReleased(KeyEvent e) {
    }
}

\n编辑:如果我删除上述部分,游戏将正常运行,移动和射击机制正常工作,但是没有生成陨石。\n非常感谢您的帮助!感谢您花时间阅读我的问题。 <3

0
0 Comments

Space Invaders生成初始的Asteroids时出现了Java失败。问题的原因是在Asteroid检查的for循环中,将其更改为默认的for(int i = 0; i < asteroids.size(); i++)。解决方法是将新Asteroids的生成移到updateGameState方法中。

以下是整理的文章:

Space Invaders生成初始的Asteroids时出现了Java失败。问题的原因是在Asteroid检查的for循环中,将其更改为默认的for(int i = 0; i < asteroids.size(); i++)。解决方法是将新Asteroids的生成移到updateGameState方法中。

import java.awt.Color;
import java.io.*;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JPanel;
import javax.swing.Timer;
public class GamePanel extends JPanel implements KeyListener {
    private static final long serialVersionUID = -1036125108881682872L;
    private List<Asteroid> asteroids;
    private List<Projectile> projectiles;
    private RocketShip rocketShip;
    private Timer timer;
    private int end; // 0 - the game is still in progress
                        // 1 - the game has ended
    public GamePanel() {
        setBackground(Color.BLACK);
        asteroids = new ArrayList<>();
        projectiles = new ArrayList<>();
        rocketShip = new RocketShip(Globals.WINDOW_WIDTH / 2, Globals.SHIP_HEIGHT);
        this.end = 0;
        addKeyListener(this);
        setFocusable(true);
        timer = new Timer(10, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                updateGameState("");
                repaint();
            }
        });
        timer.start();
    }
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        rocketShip.paintComponent(g);
        for (Asteroid asteroid : asteroids) {
            asteroid.paintComponent(g);
        }
        for (Projectile projectile : projectiles) {
            projectile.paintComponent(g);
        }
        // start and end screen, also score
    }
    public void updateGameState(String direction) {
        rocketShip.move(direction);
        rocketShip.move(direction);
        while (asteroids.size() < Globals.NUM_OF_ASTEROIDS) {
            asteroids.add(new Asteroid());
            //System.out.println("asteroid added\n");
        }
        for (int i = 0; i < asteroids.size(); i++) {
            Asteroid asteroid = asteroids.get(i);
            asteroid.move();
            if (asteroid.isOutOfBounds()) {
                asteroids.remove(i);
                asteroids.add(new Asteroid());
                i--;
            }
        }
        for (Projectile projectile : projectiles) {
            projectile.move();
            // projectile is out of bounds
            if (projectile.getX() - (projectile.getHeight() / 2) > Globals.WINDOW_HEIGHT) {
                projectiles.remove(projectile);
            }
        }
        // check for collisions
        // asteoids with projectiles
        for (Asteroid asteroid : asteroids) {
            for (Projectile projectile : projectiles) {
                if (projectile.getX() + projectile.getWidth() > asteroid.getX()
                        && projectile.getX() < asteroid.getX() + asteroid.getWidth()
                        && projectile.getY() + projectile.getHeight() > asteroid.getY()
                        && projectile.getY() < asteroid.getY() + asteroid.getHeight()) {
                    playAsteroidDestroyedSound();
                    asteroids.remove(asteroid);
                    projectiles.remove(projectile);
                    // add a new asteroid
                    asteroids.add(new Asteroid());
                    // score increase
                }
            }
        }
        // asteroids with rocketship
        for (Asteroid asteroid : asteroids) {
            if (rocketShip.getX() + rocketShip.getWidth() > asteroid.getX()
                    && rocketShip.getX() < asteroid.getX() + asteroid.getWidth()
                    && rocketShip.getY() + rocketShip.getHeight() > asteroid.getY()
                    && rocketShip.getY() < asteroid.getY() + asteroid.getHeight()) {
                // rocketShip and asteroid have collided
                asteroids.remove(asteroid);
                // game over logic
                this.end = 1;
                timer.stop();
            }
        }
    }
    public void playShootingSound() {
        try {
            AudioInputStream in = AudioSystem.getAudioInputStream(new File("audio/shooting.wav"));
            Clip clip = AudioSystem.getClip();
            clip.open(in);
            clip.start();
        } catch (UnsupportedAudioFileException | LineUnavailableException | IOException e) {
            System.out.println("ERROR: playShootingSound");
        }
    }
    public void playAsteroidDestroyedSound() {
        try {
            AudioInputStream in = AudioSystem.getAudioInputStream(new File("audio/asterDestroid.wav"));
            Clip clip = AudioSystem.getClip();
            clip.open(in);
            clip.start();
        } catch (UnsupportedAudioFileException | LineUnavailableException | IOException e) {
            System.out.println("ERROR: playAsterDestroSound");
        }
    }
    public void keyTyped(KeyEvent e) {
        if (e.getKeyChar() == ' ') {
            playShootingSound();
            Projectile projectile = new Projectile(rocketShip.getX() + rocketShip.getWidth() / 2, rocketShip.getY());
            projectiles.add(projectile);
        }
    }
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        if (keyCode == KeyEvent.VK_RIGHT) {
            updateGameState("right");
        }
        if (keyCode == KeyEvent.VK_LEFT) {
            updateGameState("left");
        }
    }
    public void keyReleased(KeyEvent e) {
    }
}

注意:你的paintComponent实现和使用方式基本上是错误的 - 永远不要在另一个组件上调用它,而是添加组件并让默认的绘制工作完成!

0
0 Comments

问题的出现原因是在遍历列表时,同时对其进行了修改。解决方法是使用迭代器来遍历列表,并且使用迭代器的remove()方法来删除元素。

以下是解决问题的代码示例:

Iterator iterator = asteroids.iterator();
while (iterator.hasNext()) {
    Asteroid asteroid = iterator.next();
    asteroid.move();
    if (asteroid.isOutOfBounds()) {
        iterator.remove();
    }
}

使用迭代器遍历列表可以避免在遍历过程中对列表进行修改造成的问题。通过调用迭代器的remove()方法来删除元素可以确保不会出现并发修改异常。

0