我为我用Java创建的游戏世界创建了一个二维'网格'。我对我创建的“漫游”模式算法有疑问。
我注意到一个问题,即对象似乎偏向网格的右下角。我更改了算法并认为它已修复。
今天,在进行压力测试时,我注意到问题没有解决,现在游荡的物体偏向网格的左上角,但是它们需要更长时间才能在该区域内游荡。
算法的工作原理是: 1.获取人员位置的当前值 2.将3个块半径内的所有正方形放入链表中 3.随机化列表 4.从列表中选择一个随机值 5.将这些值设置为下一个目标
以下是代码段:
Point personAt = this.getTopLeftPoint();
personAt = Game.getGame().screenToGame(personAt);
LinkedList<Point> thisSet = new LinkedList<Point>();
for (int x = personAt.x - 2; x < personAt.x + 3; x++) {
for (int y = personAt.y - 2; y < personAt.y + 3; y++) {
if (!(x == personAt.x && y == personAt.y)) {
//TODO: Clean up the next line of code.
if (x > 0 && y > 0 && !Board.getBoard().getSquare(x, y).getSquareType().equals(SquareType.path)) {
if (!Game.getGame().getMap().blocked(x, y)) {
thisSet.add(new Point(x, y));
}
}
}
}
}
Collections.shuffle(thisSet);
//Random random = new Random();
//Integer randomNo = random.nextInt(thisSet.size());
setNextTarget(thisSet.get(0));
这里有什么我想念的吗?
我很困惑为什么他们仍然在网格的左上角四分之一。
编辑: 我完全删除了Random对象as suggested by Don。仍然会得到相同的结果。
编辑:更新了代码以解决问题的一部分,因此现在只忽略当前人所在的方格,而不是当前X或Y上的所有方格。正如rsp。
所建议的那样答案 0 :(得分:8)
有几点,其中一些已在其他答案中提出:
Random()
的单个实例。我怀疑这将是答案的一部分 - 很少有关于Stack Overflow 上的随机数的问题与此无关:)Board.getSquare()
应对,那么你真的需要&gt; 0检查?答案 1 :(得分:6)
仅初始化一次。你通过反复重新实现随机生成器来破坏随机性。
最好使用工厂为整个应用程序创建随机单例。
public class RandomFactory
{
private Random random;
public Random getRandom()
{
if( random == null ){ random = new Random(); }
return random;
}
}
答案 2 :(得分:3)
在该代码中很难找到任何问题,但是你在该代码之外调用了很多方法。从我的第一个嫌疑人getTopLeftPoint()开始,你确定你使用相同的坐标参考。如果getTopLeftPoint()返回最左边的最顶点但setNextTarget设置中间点,那么我们就有了问题!
下一步:screenToGame()也会更改坐标...也可能是问题的根源。
如果部分正确
!Board.getBoard().getSquare(x, y).getSquareType().equals(SquareType.path)
你只能走一条不是路径的广场? (与问题无关......)
另一个:阻止()不确定那是什么意思。如果所有正方形在人行走时都会被阻挡,那么他将会在左上角结束。
最后一个,与第一个几乎相同:setNextTarget()与screenToGame()相同的坐标引用?
总结:更好地创建某种单元测试来测试没有所有这些“噪音”的随机漫游算法 我得到了很好的结果(没有阻挡,没有路径)......人们几乎同样访问每个角落。
还有一点:我宁愿使用随机而不是改组所有列表来获得它的一个元素......
答案 3 :(得分:2)
假设shuffle()
方法是无偏的,那么你没有理由需要在改组后随机选择一个元素,你可以简单地选择第一个元素。换句话说,替换它:
Collections.shuffle(thisSet);
Random random = new Random();
Integer randomNo = random.nextInt(thisSet.size());
setNextTarget(thisSet.get(randomNo));
使用:
Collections.shuffle(thisSet);
setNextTarget(thisSet.get(0));
答案 4 :(得分:1)
正如其他人所说,你应该只实例化一次Random对象然后重用它,而shuffle()调用应该意味着你根本不需要使用Random。但至于你的bug的根本原因,看起来每次调用它都会在this.getTopLeftPoint()初始化,所以我不知道它怎么会不会总是在左上角。我认为你想在他们的实际位置实例化personAt,而不是在左上角。
答案 5 :(得分:1)
你说你把所有周围的点放在列表中但是你的代码排除了水平和垂直线,所以你的对象往往只在对角线方向上移动,这可能解释了左上角的偏好。
顺便说一句,您的条件可以放得更有可读性,从而节省了一些不必要的执行过程:
for (int x = personAt.x - 2; x < personAt.x + 3; x++) {
if (x > 0 && x != personAt.x) {
for (int y = personAt.y - 2; y < personAt.y + 3; y++) {
if (y > 0 && y != personAt.y) {
if (!Game.getGame().getMap().blocked(x, y) &&
!Board.getBoard().getSquare(x,y).getSquareType().equals(SquareType.path)) {
thisSet.add(new Point(x, y));
}
}
}
}
答案 6 :(得分:0)
Person对象列表的顺序是什么(运行此代码的对象)是什么?如果你以一些预先设定的顺序迭代它们,那么你可能会在那里引入偏差,因为第一个的结果将对第二个产生影响(依此类推)。
您可以在处理之前尝试改组人员列表。