1

我在使用 TreeSets 从我正在开发的游戏中删除一个单元时遇到问题。我正在制作一个塔防游戏,路径被分成设定长度的不同块。这些块知道其中的单元以及路径上的下一个块。当单元离开块的边界时,块将其从列表中删除并将其添加到下一个块。

我正在使用 TreeSet 来跟踪块中单元的顺序,这样我就可以知道哪个单元在路径上最远。这些单元有一个位置字段,可以跟踪它们沿路径的距离,位置越高,它们越远。

在我的一些块上,我注意到当它试图从其 TreeSet 中删除一个单元时,remove 返回 false。我使用了一些断点,我可以看到该单元实际上在 TreeSet 中,所以我认为我的问题是我的攻击单元的 compareTo 方法。

这是我的 compareTo 代码:

public int compareTo(Object other) {
    if (other != null && AttackingUnit.class.isAssignableFrom(other.getClass())) {
        AttackingUnit o = (AttackingUnit) other;
        int amount = position - o.position;
        if (amount != 0) {
            return amount;
        } else if (amount == 0 && this == o) {
            return 0;
        }
    }
    return 1;
}

我注意到问题的街区之一是单位进入顶部,中途转角并退出右侧的街区。该块有两个 ArrayList,一个用于从上到下的单元 (enPath),一个用于从左到右的单元 (exPath)。这是我遇到问题的代码:

for (int i = 0; i < exPath.size(); i++) {
    AttackingUnit unit = exPath.get(i);
    unit.stepX();
    if (unit.getX() > rightX) {
        nextBlock.addUnit(unit);
        units.remove(unit);
        exPath.remove(unit);
        i--;
    }
}

单位在 exPath 和单位(TreeSet)中,但 units.remove(unit) 返回 false。关于如何更改 AttackingUnit 上的 compareTo 以解决此问题的任何想法?

4

2 回答 2

1

我看到的一个问题compareTo是:

} else if (amount == 0 && this == o) {

您应该对它们进行 ORing(或摆脱this == o支票)。就像现在一样,两个相同AttackingUnit的不同实例position将返回 1(第一个更大)。这肯定会在树集中给出不一致的顺序。

顺便说一句,您可以替换:

if (other != null && AttackingUnit.class.isAssignableFrom(other.getClass()))

if (other instanceof AttackingUnit)

这更容易阅读。

于 2011-05-08T20:37:31.410 回答
1

你的 compareTo 方法很奇怪。首先,您的列表中不应包含任何类型不正确的元素,也不应包含 null 元素,因为这无论如何都会产生问题。因此,您可以在这些情况下简单地抛出异常而不是返回1.

其次,正如史蒂夫已经指出的那样,this == o检查是不正确的 - 这违反了您的关系的对称性,给您提供了找不到元素的情况。这给出了这个更简单的版本:

public int compareTo(Object other) {
    AttackingUnit o = (AttackingUnit) other;
    int amount = position - o.position;
    return amount;
}

第三,确保当一个单元在您的 TreeSet 中时位置(即比较的结果)不会改变。如果位置必须改变,首先从集合中移除元素,改变位置然后再次添加。

于 2011-05-08T20:49:26.947 回答