我正在编写一个简单的Top Down Shooter。玩家可以按住鼠标连续拍摄。由于没有本机方法来检查鼠标按钮是否按下,我实现了这个解决方案:https://stackoverflow.com/a/6828990/3716866
这完全没问题。但问题是我将每个子弹对象和每个GameObject(敌人,玩家,桶等)放在一个链接列表中(两个列表一个用于对象,一个用于子弹)。当你射击子弹时,它会被添加到LinkedList中。游戏循环的每个runthrough整个List都会通过碰撞检查。在射击大约2次射击后,游戏因Null指针异常而崩溃。我认为问题是,因为我使用第二个线程来实现鼠标按钮按住,一个子弹对象正在创建,而在另一个线程中它检查列表。由于我正在检查列表,当大小被改变时,它正在检查列表,它崩溃了。但那只是我的理论。有人知道如何保持同步吗?
如果您需要更多代码等,请告诉我,我会上传它。我只是不确定我应该发布什么。所以在我发送垃圾邮件之前,我想等待你的反馈。
例外:
Exception in thread "Thread-2" java.lang.NullPointerException
at shooter.main.Handler.checkForCollision(Handler.java:50)
at shooter.main.Handler.tick(Handler.java:41)
at shooter.main.Game.tick(Game.java:189)
at shooter.main.Game.run(Game.java:290)
at java.lang.Thread.run(Unknown Source)
Handler Class,它运行每个Object的所有tick和update方法,包括碰撞:
我的MouseListener类,其中实现了另一个Thread:
我的主要游戏课程,虽然我不认为这对这个问题非常重要:
我的抽象GameObject类:
GameObject示例:
我的抽象弹药课程:
子弹的例子:
拍摄方法如何:
public void shoot() {
//play sound effect
// fire bullet
game.getHandler().addBullet(new Bullet9mm(game.getHandler().getPlayer().getX(), game.getHandler().getPlayer().getY(), game.getBulletImageManager(), game));
// remove 1 bullet from magazine
game.getHandler().getPlayer().getCurWeapon().setMagAmmo(-1);
}
我希望我提供了所有必要的信息。如果您还需要我的代码中的其他内容,请告诉我。
答案 0 :(得分:1)
LinkedList删除任何后续元素向左移动(从索引中减去一个)。返回从列表中删除的元素。因此,如果你正在删除它可能没有你访问的子弹或播放器。你可以突出你的课程和方法签名,我自己或有人可以帮助你更好地设计它。
答案 1 :(得分:1)
即使没有多线程访问,您的实现也会失败,因为外部for循环没有考虑到您可能在迭代时删除对象。因此,即使由于冲突而移除了对象,计数器s
也总是递增。出于这个原因,在您的实现中跳过了被删除的对象的每个后继者。
(说明:如果删除位置s
处的对象,则所有连续对象都会向前移动一个位置,因此位置s + 1
处的对象移动到位置s
。但是作为for循环之后增加s
,跳过该位置的新对象。
对于带有计数器的循环,你应该总是使用迭代器。它们提供安全的对象删除,并且在您想要更改集合的实现时更灵活。 (在您的情况下,迭代器提供的性能远远优于计数器,因为LinkedList
上基于索引的操作需要顺序遍历列表。)
这是一个示例实现,有一些更多改进,应该适用于您的情况:
private void checkForCollision() {
// use iterator instead of index based for loop
while (Iterator<GameObject> iter = objects.iterator(); iter.hasNext();) {
GameObject object = iter.next();
// in case the object is the player, we can skip all collision tests
if (object == getPlayer()) continue;
// use implicit iterator instead of index based for loop
for (Bullet bullet : bullets) {
if (object.getCol().getBounds2D().intersects(bullet.getCol().getBounds2D())) {
iter.remove(); // remove object via iterator
break; // no need to check the rest => leave inner loop
}
}
}
}
注意:此实现不线程安全,因此,如果您的对象(集合objects
或bullets
或其中的任何对象)被访问通过多个线程,需要同步或线程安全的集合!