产生随机对象而不重叠(Java)?

时间:2015-06-17 20:30:10

标签: java object overlap

我正在用Java开发游戏,其中一部分要求对象在屏幕顶部产生并继续下降。我有三个可能会产生的对象,以及三个可能产生的x坐标,它们都存储在一个名为xCoordinate[]的数组中。
其中一个对象是一个名为Enemy的类,它继承了一个名为FallingThings的类。在FallingThings类中,我有生成新对象的方法,我的敌人方法如下:

public static void generateNewEnemy() {
    xIndexEnemyOld = xIndexEnemy;
    xIndexEnemy = new Random().nextInt(3);
    if (delayTimer == 0) {
        while (xIndexEnemy == xIndexEnemyOld) {
            xIndexEnemy = new Random().nextInt(3);
        }
    }
    if (xIndexEnemy != xIndexMoney && xIndexEnemy != xIndexFriend) {
        Enemy enemy = new Enemy(xCoordinates[xIndexEnemy]);
        enemies.add((Enemy) enemy);
    } else {
        generateNewEnemy();
    }
}

xIndexEnemy表示xCoordinates数组的索引 xIndexMoneyxIndexFriend是其他两个对象的xCoordinates数组的索引(与这些值的比较可确保一个对象不会直接在另一个对象之上生成)。
delayTimer变量表示新对象生成之间的随机延迟,这是在我的主类中先前设置的 我将Enemy对象的每个实例存储在ArrayList中。

一切都有效,除了有时候一个物体会在它自身产生的事实(例如,延迟为0,所以两个敌人的物体直接在彼此之间产生,然后以相同的速度向下坠落同时)。

过去两天我一直试图解决这个问题,但我明白为什么我的代码现在无法正常工作。我甚至尝试实现碰撞检测以检查空间中是否已存在另一个对象,但这也不起作用。

我非常感谢任何建议和想法。

2 个答案:

答案 0 :(得分:0)

如我所见,如果延迟== 0一切都很好,但如果没有,你有机会用相同的指数产生新的敌人。如果delayTimer!= 0,可能要调用return;

<强>已更新

在这种情况下看看你有什么: OldEnemyIndex = 1 NewEnemyIndex = random(3) - &gt; 1 DelayTimer = 2

然后你没有传递给你的if语句,然后在下一个如果一切正常,如果你的敌人与金钱或其他东西没有相同的索引,所以你用与之前相同的索引创建新的敌人

答案 1 :(得分:0)

<强> EDIT2

您似乎仍然不了解您的功能问题。在另一个答案中解决了这个问题,但我会尽力使其更清楚。

public static void generateNewEnemy() {
    xIndexEnemyOld = xIndexEnemy;

这是错的。如果尚未实际使用新索引,则无法设置旧索引。

    xIndexEnemy = new Random().nextInt(3);
    if (delayTimer == 0) {
        while (xIndexEnemy == xIndexEnemyOld) {
            xIndexEnemy = new Random().nextInt(3);
        }
    }

这实际上没问题。你得到一个索引,直到得到一个不同的索引。它可能不是最优雅的解决方案,但它可以完成这项工作。

    if (xIndexEnemy != xIndexMoney && xIndexEnemy != xIndexFriend) {
        Enemy enemy = new Enemy(xCoordinates[xIndexEnemy]);
        enemies.add((Enemy) enemy);
    } else {
        generateNewEnemy();
    }
}

这是你的问题(同时将Old索引设置回那里)。您不仅需要生成与旧索引不同的索引,还必须与IndexMoney和IndexFriend不同。

现在,如果,例如,IndexOld = 0,IndexMoney = 1和IndexFriend = 2,会发生什么?你必须生成一个与0不同的索引,所以你得到(例如)1。IndexMoney也是1,因此条件将失败并且你进行递归调用。 (为什么你甚至有一个递归的电话?)

OldIndex为0,现在在下一个调用中你将其设置为1.所以IndexOld = 1,IndexMoney = 1和IndexFriend = 2.你现在看到问题了吗?重叠的索引现在是错误的。无论需要多少次递归调用,新索引都只能为0。

你不止一次在脚下射击自己。递归调用不会导致无限循环(实际上是堆栈溢出),因为您正在更改Old索引。 (这又是在错误的地方)

如果条件正在进行,那么新生成的索引不能与之前的索引中的任何一个重叠。从你之前说的不是你想要的。

您可以像这样简化您的功能,

public static void generateNewEnemy() {
    xIndexEnemy = new Random().nextInt(3);
    if (delayTimer == 0) {
        while (xIndexEnemy == xIndexEnemyOld) {
            xIndexEnemy = new Random().nextInt(3);
        }
    }

    Enemy enemy = new Enemy(xCoordinates[xIndexEnemy]);
    enemies.add((Enemy) enemy);
    xIndexEnemyOld = xIndexEnemy;
    // Now that you used the new index you can store it as the Old one
}

会起作用吗?当delayTimer为0时,它肯定会避免重叠,但我不知道你的其余代码(我也不想),你做了什么。这是你应该知道的。

关于我的建议,它们是如何生成所需索引的替代方案。我假设您会知道如何在代码中使用它们,但在修复实际问题后,您仍然可以自由地尝试它们。

原始答案

这是一个建议。

你可以做的一件事就是让这些敌人从阵列中“借用”元素。假设你有一个数组,

ArrayList< Float > coordinates = new ArrayList< Float >();
// Add the coordinates you want ...

您可以选择其中一个索引,但请使用数组的最大大小,然后删除您选择的元素。通过这样做,您将删除其中一个索引选项。

int nextIndex = new Random().nextInt( coordinates.size() );
float xCoordinate = coordinates.get( nextIndex );
coordinates.remove( nextIndex ); // Remove the coordinate

稍后,当你完成了这个值(比如,当足够的时间过去,或者敌人死亡)时,你可以把它放回到数组中。

coordinates.add( xCoordinate );

现在该值再次可用,您无需为检查索引而烦恼。

嗯,这是我的建议的总体思路。您将不得不对其进行调整以使其按您所需的方式工作,特别是当您将值重新放入数组时,因为我不知道您可以在代码中执行此操作。

修改

另一种选择是,保留以前拥有的数组。无需从中删除任何值或任何内容。

如果要获取新坐标,请创建一个仅包含可用值的额外数组,即不会与其他对象重叠的值。

...
if (delayTimer == 0) {
    ArrayList< Integer > availableIndexes = new ArrayList< Integer >();
    for ( int i = 0; i < 3; ++i ) {
        if ( i != xIndexEnemyOld ) {
            availableIndexes.add( i );
        }
    }
    int selectedIndex = new Random().nextInt( availableIndexes.size() );
    xIndexEnemy = availableIndexes.get( selectedIndex );
}
// Else no need to use the array
else {
    xIndexEnemy = new Random().nextInt( 3 );
}
...

现在你确定你得到的索引应该是不同的,所以不需要检查它是否重叠。 缺点是你必须创建这个额外的数组,但它会使你的条件更简单。

(我从你的代码中保留了“新的Random()”,但是其他答案/评论指的是你应该使用单个实例,请记住)