Java 游戏中多个物体之间的碰撞检测?

Java 游戏中多个物体之间的碰撞检测?,java,multithreading,swing,collision-detection,Java,Multithreading,Swing,Collision Detection,我试图理解如何实现多个对象之间的碰撞检测。 我的项目检测到对象之间的碰撞,但它在碰撞后立即崩溃 这是我的主类,带有JFrame和main循环: public class Window { public static void main(String[] args){ GamePanel gamepanel = new GamePanel(); JFrame f = new JFrame("Multiple Collision Detection"); f.setSize

我试图理解如何实现多个对象之间的碰撞检测。 我的项目检测到对象之间的碰撞,但它在碰撞后立即崩溃

这是我的主类,带有
JFrame
main循环

public class Window {

public static void main(String[] args){
    GamePanel gamepanel = new GamePanel();
    JFrame f = new JFrame("Multiple Collision Detection");
    f.setSize(400, 400);
    f.add(gamepanel);
    f.setVisible(true);
    f.setResizable(false);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setLocationRelativeTo(null);

    while(true){
        gamepanel.repaint();
        gamepanel.update();
        try{
            Thread.sleep(10);
        }catch(Exception e){
            System.out.println("Main Loop Error");
        }
    }
}

}
然后我有两门课,一门给玩家,一门给敌人:

玩家:

public class Player {

int x = 175, y = 175, w = 50, h = 50, dx = 0, dy = 0;
Rectangle rect;

public void paint(Graphics g) {
    rect = new Rectangle(x, y, w, h);
    g.setColor(Color.black);
    g.fillRect(rect.x, rect.y, rect.width, rect.height);
    g.setColor(Color.CYAN);
    g.drawRect(x, y, w, h);
}

public void setDx(int dx) {
    this.dx = dx;
}

public void setDy(int dy) {
    this.dy = dy;
}

public void move() {
    x += dx;
    y += dy;
}

public void update() {
    move();
}

}
敌人:

public class Enemy {

int x, y, w = 35, h = 35;

Rectangle rect;

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

public void paint(Graphics g) {
    rect = new Rectangle(x, y, w, h);
    g.setColor(Color.red);
    g.fillRect(rect.x, rect.y, rect.width, rect.height);
}

public void update() {

}

}
我有一个EnemyManager类,它通过
列表
吸引了多个敌人(在本例中为3):

public class EnemyManager {

Player player = new Player();
Rectangle playerrect;
Rectangle enemyrect;
List<Enemy> enemies = new ArrayList<Enemy>();

public void paint(Graphics g) {

    enemies.add(new Enemy(20, 20));
    enemies.add(new Enemy(320, 20));
    enemies.add(new Enemy(20, 320));

    for (Enemy e : enemies) {
        e.paint(g);
    }
}

public void update() {

}

}
当游戏检测到玩家和敌人之间发生碰撞时,会将“碰撞”打印到控制台,但之后会出现以下错误:

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at GamePanel.checkPlayerEnemyCollision(GamePanel.java:22)
at GamePanel.update(GamePanel.java:34)
at Window.main(Window.java:20)
有人知道问题是什么,也许知道如何解决吗


提前感谢。

我尝试了你的程序,但使用A、W、S、D键无法移动任何东西。但是,我确实像你所说的那样,在for循环点上出现了并发mod异常

尝试将所有增强循环更改为正常循环。例如,在

for (Enemy e : enemies) {
        e.paint(g);
    }
改为:

for (int i = 0; i < enemies.size(); i++)
    enemies.get(i).paint(g);
for(int i=0;i
这样做之后,我再也没有得到错误了


如果在某些时间对数组执行某些操作,则增强的for循环会导致错误。但我不确定为什么会出现这种情况,因为我不太熟悉Java中图形在幕后的工作方式。

您得到的是ConcurrentModificationException,这意味着您试图在一个线程中修改集合,而在另一个线程中对其进行迭代(如果在迭代时尝试修改集合,也可能在单个线程中发生,但这里不是这样)

这一切都源于这样一个事实:你没有注意到你的事件发生在哪个线程中。你有两个活动线程,不管你意识到与否

线程#1是程序的主线程,应用程序从这里开始

线程#2是Swing EDT,所有用户操作都从该线程启动

在从Swing EDT对集合进行迭代时,您似乎正在尝试从主线程更新域模型。您需要同步访问,或者通过稍后将其包装在调用中使所有更新在EDT上执行:

SwingUtilities.invokeLater(new Runnable(){
  public void run(){
    gamepanel.repaint();
    gamepanel.update();
  }
});

请注意,我不知道在循环+线程.sleep中简单地使用上面的代码片段是正确的操作,因为我没有通读您的所有逻辑。至少您应该阅读一个从事件调度程序线程调用的

。您可以使用此方法修改列表

event dispatcher thread
-> GamePanel.paint
-> EnemyManager.paint
-> enemies.add
但是,您可以通过
GamePanel中的“foreach”循环使用列表的迭代器。checkPlayerEnemyCollision

for(Enemy e : enemymanager.enemies)
但是
ArrayList的迭代器
会失败,如果您在创建迭代器后修改列表,并且出现异常

由于列表修改和迭代器可以从不同的线程使用,因此它们很容易相互干扰,例如:

  • 主线程创建迭代器
  • 主线程读取一些元素
  • 事件调度程序线程调用
    paint
  • 事件调度程序线程将敌人添加到列表中
  • 主线程调用尝试从迭代器->异常获取元素

  • 你的设计有点瑕疵:

    调用
    paint
    时,您几乎没有控制权,正如方法名称所示,它用于绘制。不要更改此方法中的数据,只需绘制它即可

    重新设计你的程序,记住这一点(例如,可以先阅读教程)

    您仍然需要从不同于修改列表的线程读取
    敌方
    列表。请使用列表的
    获取
    方法而不是迭代器,并记住,列表的大小可以更改,因此您需要稍微同步一些内容。如果线程“保留”一个允许他们访问的特定索引范围。

    这不是一个合适的(或正确的修复)。它不抛出ConcurrentModificationException的唯一原因是因为您没有活动的迭代器。相反,它将在几种糟糕的情况下结束,例如1)在同一个敌人身上画两次2)IndexOutOfBounds例外,当他超过限制时3)不画敌人,因为他们在他到达最后一个索引后被添加
    for(Enemy e : enemymanager.enemies)