【问题标题】:Java Game: ArrayList and Iterator vs. ThreadJava 游戏:ArrayList 和迭代器与线程
【发布时间】:2011-06-28 02:09:38
【问题描述】:

伙计们。

我正在为我的 Java 类编写一个简单的僵尸游戏,但遇到了一个小问题:僵尸是我创建的一个类,我在 ArrayList 上处理它们,如下所示:

horda.add(new Zumbi( (int)(Math.random()* 750), 0));

参数代表屏幕上的僵尸生成位置。要杀死它们,您必须单击它们,非常简单,使用迭代器检查碰撞,这里:

java.util.Iterator<Zumbi> itr = horda.iterator();
        while (itr.hasNext()){
            Zumbi z = itr.next();
            if (tiroPos.x > z.zumbiPos.x && 
                tiroPos.x < z.sprite.getWidth() + z.zumbiPos.x &&
                tiroPos.y > z.zumbiPos.y &&
                tiroPos.y < z.sprite.getHeight() + z.zumbiPos.y){

                //things to do when it hits    
            }

tiroPos 是一个指针,用于保存玩家射击的坐标。问题是:有时当你击中僵尸时应该发生的那些事情并没有发生。不知道是不是迭代器跑得不够快还是其他什么原因。

也许为每个僵尸作品创建一个不同的线程,但这会改变代码是一些基本的方法,如果没有帮助,我不想冒失去所有时间的风险。

那么,有什么想法吗?

//编辑:忘了说:我正在检查重写绘制方法中的碰撞,因为我不知道如何在其他方法上绘制东西以及当我尝试访问 ArrayList(它是一个同步的 ArrayList)在另一个线程上它给我一个共同修改异常。

//EDIT2: 问题已解决(从未解决)。

MouseListener传递的MouseEvent对象传递的是鼠标指针下端的坐标。所以这不是一个真正的碰撞问题,更多的是一个数学问题。我必须比较 clickPoint.y - 25 才能正确。

感谢所有试图提供帮助的人!

【问题讨论】:

  • 每次单击时都会将迭代器重置为开头,对吧?
  • 您是否真的在单独的线程中收集用户输入?
  • 阅读编辑部分。忘了这个。

标签: java multithreading arraylist


【解决方案1】:

要记住两件事:

  1. 如果您需要在迭代时从 ArrayList 中删除项目,则必须通过迭代器上的 remove() 方法来完成。如果您修改列表本身,它将失败。

  2. 如果有两个线程访问列表,你应该用Collections.synchronizedList包裹它,或者选择不同的数据结构。

编辑:听起来您正在修改一个线程上的列表,同时在另一个线程上迭代它。这将导致 ConcurrentModificationException。避免它的最简单方法是在两个线程上使用同步块包装列表的使用。示例:

synchronized(horda) {
    iterator = horda.iterator();
    while (iterator.hasNext()) {
        z = iterator.next();
        ...
    }
}

另一种选择是在迭代之前克隆列表或使用 java.util.concurrent 中的特殊列表实现之一,例如 CopyOnWriteArrayList

【讨论】:

  • 这两件事都做了。奇怪的是它一直在抛出异常。
  • synchronized(horda) 包装了两个访问,它仍然给了我不寻常的行为。
  • 什么样的异常行为?
  • 迭代器有时不会删除对象。
【解决方案2】:

多线程只能帮助你这么多,它真的取决于你有多少处理能力。

四叉树通常用于碰撞检测,因此作为替代方案可能值得研究。

【讨论】:

  • 我不确定实现 quad tree 是初学者 Java 程序员应该担心的事情;)
  • 嗯,当然不是。但对于碰撞来说,这绝对是更好的选择。 :D
【解决方案3】:

在我看来,你最好使用 for-each 循环来遍历僵尸。它是为了执行这样的任务而引入的,所以你不妨使用它。

【讨论】:

  • For-each 循环很不错,但是如果您需要访问迭代器的 remove(),那么您就不走运了,因为 @Naro 会想要“杀死”僵尸被击中,for-each 循环不适合他。
【解决方案4】:

我假设玩家通过点击窗口“射击”,因此tiroPos 是点击的 x,y 坐标。

如果是这种情况,并且您的问题是,当用户点击很多时,某些僵尸在被点击时似乎没有被击中,这可能是只有最后一个“镜头”被保存在 @ 987654322@.

您可以通过在 for 循环周围添加适当的 System.out.println() 调用以及在您设置 tiroPos 的位置添加另一个调用来测试这一点。如果 tiroPos 在你的 for 循环中间发生变化,这就是为什么一些僵尸没有被击中的原因。

如果是这种情况,您需要开始存储点击列表,而不仅仅是最近的点击。

编辑:但这不会修复您的并发修改异常。

【讨论】:

  • 它不再抛出异常,因为我使用了@ataylor 发布的提示,但我仍然得到这种奇怪的行为。我会尝试那些System.out.println() 进行进一步调试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-06
  • 1970-01-01
  • 1970-01-01
  • 2012-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多