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();
}
}
Это ваша проблема (а также установка старого индекса там). Вам не только нужно генерировать индекс, отличный от старого, он также должен отличаться от IndexMoney и IndexFriend.
Теперь, что произойдет, если, например, IndexOld = 0, IndexMoney = 1 и IndexFriend = 2? Вы должны сгенерировать индекс, отличный от 0, так что вы получите (опять же, например) 1. IndexMoney тоже 1, поэтому условие будет терпеть неудачу, и вы выполните рекурсивный вызов. (Почему у вас даже есть рекурсивный звонок?)
OldIndex был 0, и теперь в следующем вызове вы устанавливаете его на 1. Таким образом IndexOld = 1, IndexMoney = 1 и IndexFriend = 2. Вы видите проблема сейчас? Наложенный индекс теперь ошибочен. И новый индекс может быть равен 0 независимо от того, сколько рекурсивных вызовов требуется.
Вы стреляете в ногу более одного раза. Рекурсивный вызов не приводит к бесконечному циклу (переполнение стека фактически), потому что вы меняете Старый индекс. (Который, опять же не в том месте)
Это условие делает так, чтобы только что созданный индекс не мог перекрывать ЛЮБОЙ из предыдущих индексов. Из того, что вы сказали раньше, это не то, что вы хотите.
Вы можете упростить вашу функцию, как это,
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);
Теперь значение снова доступно, и вам не нужно беспокоиться об проверке индексов.
Ну, это общая идея для моего предложения. Вам придется адаптировать его, чтобы он работал так, как вам нужно, особенно когда вы возвращаете значение в массив, поскольку я не знаю, где в вашем коде вы можете это сделать.
EDIT:
Другая альтернатива, вы сохраняете массив, который ранее имел. Нет необходимости удалять из него значения или что-то еще.
Если вы хотите получить новую координату, создайте дополнительный массив только с доступными значениями, то есть значениями, которые не будут перекрывать другие объекты.
...
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()» из вашего кода, но и других ответов/комментарии относятся, что вы должны использовать один экземпляр, помните, что)
Что такое delayTimer? Где вы его меняете? Когда вы называете порождением нового врага? –
Используйте только один экземпляр Random для лучшего дистрибутива. – Ezequiel
@OrestSavchak delayTimer - переменная, которую я использую для таймера, который я создал в моем основном классе, который диктует, когда появляются новые объекты (от 0 до 2 секунд). Я присваиваю ему значение в моем основном классе и оттуда вызывается метод, который случайным образом определяет, создавать ли врага, друга или деньги, а если он возвращает врага, вызывается генерацияNewEnemy(). –