2015-06-17 15 views
0

Я разрабатываю игру на Java, и ее часть требует, чтобы объекты появлялись в верхней части экрана и продолжали падать. У меня есть три объекта, которые могут появиться, и три возможных координаты x для их появления, хранящихся в массиве с именем xCoordinate[].
Один из объектов относится к классу Enemy, который наследует класс, который я назвал FallingThings. В классе FallingThings, у меня есть методы, чтобы генерировать новые объекты, мой метод врага ниже:Создавать случайные объекты без перекрытия (Java)?

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.
xIndexMoney и xIndexFriend - это индексы массива xCoordinates для двух других объектов (сравнение с этими значениями гарантирует, что один объект не создается непосредственно поверх другого).
Переменная delayTimer представляет случайную задержку между тем, когда появляются новые объекты, которые были установлены ранее в моем основном классе.
Я храню каждый экземпляр объекта Enemy в ArrayList.

Все работает, за исключением того факта, что иногда объект будет порождаться сам по себе (например, задержка равна 0, поэтому два вражеских объекта появляются непосредственно друг над другом и продолжают падать с той же скоростью при в то же время).

Я пытаюсь взломать это в течение последних двух дней, но я точно понимаю, почему мой код сейчас работает неправильно. Я даже попытался реализовать обнаружение столкновений, чтобы проверить, существует ли еще один объект в пространстве, но это тоже не сработало.

Я был бы чрезвычайно признателен за любые предложения и идеи.

+0

Что такое delayTimer? Где вы его меняете? Когда вы называете порождением нового врага? –

+0

Используйте только один экземпляр Random для лучшего дистрибутива. – Ezequiel

+0

@OrestSavchak delayTimer - переменная, которую я использую для таймера, который я создал в моем основном классе, который диктует, когда появляются новые объекты (от 0 до 2 секунд). Я присваиваю ему значение в моем основном классе и оттуда вызывается метод, который случайным образом определяет, создавать ли врага, друга или деньги, а если он возвращает врага, вызывается генерацияNewEnemy(). –

ответ

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(); 
    } 
} 

Это ваша проблема (а также установка старого индекса там). Вам не только нужно генерировать индекс, отличный от старого, он также должен отличаться от 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()» из вашего кода, но и других ответов/комментарии относятся, что вы должны использовать один экземпляр, помните, что)

+0

Вы помещаете координату x обратно в массив, чтобы он ничем не отличался от того, что вы делали ранее. Вы должны вернуть координату только тогда, когда она доступна, возможно, когда противник упал достаточно низко или был убит. Я не знаю фактического состояния, которое должно сделать координату доступной снова. – aslg

+0

Извините за удаление моего комментария, форматирование выглядело плохо. Если координата больше не доступна, мои другие объекты, такие как Friend and Money, не смогут отображаться на экране. Мне нужно, чтобы все координаты всегда были доступны для всех, но нужно реализовать метод предотвращения перекрытия, когда delayTimer == 0. –

+0

Тогда вы могли бы удалить координату из массива за время, когда вам не нужны наложения , И когда это время прошло, вы можете поместить его обратно в массив? – aslg

0

Как я вижу, если задержка == 0 все хорошо, но если нет, у вас есть шанс создать нового врага с тем же индексом. Возможно, вы хотите позвонить return;, если delayTimer! = 0?

ОБНОВЛЕНО

Посмотрите, что у вас есть в таком случае: OldEnemyIndex = 1 NewEnemyIndex = случайная (3) -> 1 DelayTimer = 2

Тогда вам не пройти ваш, если заявление , то в следующем, если все в порядке, если у вашего врага нет единого индекса с деньгами или чем-то еще, поэтому вы создаете нового врага с тем же индексом, что и предыдущий

+0

Я хочу сделать это, если delayTimer == 0, а затем измените значение xIndexEnemy, пока оно не будет отличаться от значения xIndexEnemyOld (что должно помешать его появлению поверх уже существующего объекта противника), следовательно while() петля. После этого я начинаю как обычно с создания объекта. –

+0

И да, лучше использовать один случайный экземпляр. И почему вы применяете вражескую переменную к классу Enemy? Это бесполезный код. –

+0

Посмотрите мое обновление. –

Смежные вопросы