我遇到了TreeSet从我正在处理的游戏中移除一个单元的问题。我正在制作塔防游戏,并且路径被分解成一组长度不同的块。块知道其中的单元和路径上的下一个块。当单元离开块的边界时,该块将其从列表中删除并将其添加到下一个块中。
我正在使用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;
}
我注意到这个问题的其中一个区块是单位进入顶部的一个区块,一个角落中途并退出右侧。该块有两个ArrayLists,一个用于从上到下的单元(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以修复此问题的任何想法?
答案 0 :(得分: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)
更容易阅读。
答案 1 :(得分:1)
您的compareTo方法很奇怪。首先,您不应该在列表中包含任何不正确类型的元素,也不应该使用null元素,因为这样会产生问题。因此,您可以简单地在这些情况下抛出异常,而不是返回1
。
其次,正如史蒂夫已经指出的那样,this == o
检查不正确 - 这违反了你的关系的对称性,为你提供了找不到你的元素的情况。这给出了这个更简单的版本:
public int compareTo(Object other) {
AttackingUnit o = (AttackingUnit) other;
int amount = position - o.position;
return amount;
}
第三,确保单元位于TreeSet中时位置(即比较结果)不会改变。如果位置必须更改,请先从集合中删除元素,更改位置,然后重新添加。