Как активировать 2 игровых объекта случайным образом?

#c# #unity3d

Вопрос:

У меня есть этот код, но похоже, что случайный активирует тот же игровой объект. Как я могу быть уверен, что не то же самое будет активировано? Например, этот код активирует 2 игровых объекта, но иногда только один, потому что случайный выбор одного и того же игрового объекта дважды.

 for (int i = 0; i < 2; i  )
{
    int index = Random.Range(0, EyeButtonArray.Length);
    EyeButtonArray[index].SetActive(true);
}
 

Комментарии:

1. Вам действительно не нужен цикл только для 2 вещей. Лучшим вариантом, вероятно, является создание временного массива всех объектов за вычетом первого выбора, а затем выбор из нового списка.

2. @DerekC. You really don't need a loop for only 2 things. .. пока возможно .. но с циклом он доступен для обслуживания и масштабируется в соответствии с любыми последующими желаниями 😉

3. @derHugo, а потом вставишь это в петлю позже? Делай то, что тебе нужно сейчас, и не делай вид, что это не может измениться.

4. @DerekC. Ну, да .. или сразу сделайте это хорошо, и вам не нужно даже думать о том, происходит ли это для одного, двух или тысячи объектов ^^ Хорошо, для одного и двух объектов вы можете спорить о накладных расходах .. но с точки зрения обслуживания имеет смысл использовать цикл, начинающийся с двух элементов

Ответ №1:

Вы можете случайным образом перетасовать контейнер и выбрать первые два элемента.

 int wanted = 2;
int[] nums = System.Linq.Enumerable.Range(0, EyeButtonArray.Length).ToArray();
System.Random rnd = new System.Random();

nums = nums.OrderBy(x => rnd.Next()).ToArray();
for(int x = 0; x < 2;   x)
    EyeButtonArray[nums[x]].SetActive(true);
 

Другое решение с использованием a HashSet состоит в том, чтобы отслеживать выбранные вами элементы и продолжать генерировать их до тех пор, пока вы не выберете уникальный.

 HashSet<int> RandomElementIdx = new HashSet<int>();
int picked = 0;
int wanted = 2;

while(picked < wanted)
{
    int index = Random.Range(0, EyeButtonArray.Length);
    
    if(RandomElementIdx.Contains(index))
        continue;
        
    RandomElementIdx.Add(index);
    EyeButtonArray[index].SetActive(true);
      picked;
}
 

Приведенный выше фрагмент предполагает, что ваш список больше или равен wanted . Если он меньше, это приведет к бесконечному циклу. Это также не совсем эффективно, так как оно будет постоянно пытаться создавать новые числа, пока случайно не попадет в неиспользуемое.

Комментарии:

1. Эй, спасибо за ответ, но Unity говорит, что System.Linq. Диапазон недопустим. Я пытаюсь понять, почему. Я уже добавляю, используя System.Linq; в верхней части файла.

2. @Khrys Ой, извините, что я удалил важную часть с помощью редактирования. Теперь исправлено.

3. Спасибо, приятель. Это исправило эту линию. У меня также есть предупреждение для nums. Подкачка, говорящая » int []», не содержит определения «Подкачки», и не может быть найден доступный метод расширения «Подкачка», принимающий первый аргумент типа «int []» (у вас отсутствует директива using или ссылка на сборку?). Это было видно с момента первоначального сообщения, извините, что не привел это. Я пытаюсь понять, почему. Еще раз спасибо.

4. Ой, да, я допустил еще одну ошибку при редактировании. Своп используется для списков. Вы можете поменять свой контейнер на список. Если вы хотите использовать массив, вы можете использовать прямой обмен для хранения временной переменной. Я обновлю ответ, чтобы использовать его.

5. Спасибо за ответ. Это действительно помогло мне.

Ответ №2:

Это звучит так, как будто ты хочешь

  • У вас есть список/массив объектов
  • Вы хотите включить следующие два случайных из них
  • (необязательно — не уверен в этом) вы хотите отключить два текущих

Вы можете просто «перетасовать» свой массив, а затем включить два первых из теперь перетасованных элементов, таких как, например

 using System.Linq;

...

// OPTIONAL (but I thought makes sense)
// store the currently enabled objects to also be able to disable them later
// when you enable the next pair
private GameObject[] _currentEnabled;

public void EnableTwoRandom()
{
    // OPTIONAL (but I thought makes sense)
    // if exists first disable the last selected two buttons
    if(_currentEnabled!=null)
    {
        foreach(var item in _currentEnabled)
        {
            item.SetActive(false);
        }
    } 

    // Pick two random buttons
    // This first "shuffles" the buttons and then simply takes the
    // first two random elements
    _currentEnabled = EyeButtonArray.OrderBy(i => Random.value).Take(2).ToArray();

    // enable the new two random buttons
    foreach(var item in toEnable)
    {
        item.SetActive(true);
    }
}
 

Видеть


если дополнительно вы хотите быть уверены, что новые выбранные кнопки также не совпадают с предыдущими, вы можете добавить

 // Pick two random buttons
if(_currentEnabled != null)
{
    // if there already exists a previous selection
    // then exclude this selection from the available options first
    _currentEnabled = EyeButtonArray.Except(_currentEnabled).OrderBy(i => Random.value).Take(2).ToArray();
}
else
{
    _currentEnabled = EyeButtonArray.OrderBy(i => Random.value).Take(2).ToArray();
}
 

Видеть

Комментарии:

1. Спасибо за ваш ответ.