Как предотвратить появление одного и того же префаба дважды подряд в Unity

Новичок в Unity, у меня есть случайный генератор сборных элементов, прикрепленный к моей игре в Unity, который случайным образом создает 3 сборных элемента. Проблема в том, что иногда я получаю один и тот же префаб 5 раз подряд. Как я могу предотвратить появление одного и того же префаба дважды подряд? Вот мой код:

public class randomspawnscript : MonoBehaviour
{
    public GameObject prefab1, prefab2, prefab3;


    public float spawnRate = 2f;

    float nextSpawn = 0f;

    int whatToSpawn;

    void Update()
    {
        if (collisionbutton.end != true || gameoverscreenrestart.restartPressed==true || gameovermainmenu.menuPressed==true)
        {
            if (Time.time > nextSpawn)
            {
                whatToSpawn = Random.Range(1, 4);
                Debug.Log(whatToSpawn);

                switch (whatToSpawn)
                {
                    case 1:
                        Instantiate(prefab1, transform.position, Quaternion.identity);
                        break;
                    case 2:
                        Instantiate(prefab2, transform.position, Quaternion.identity);
                        break;
                    case 3:
                        Instantiate(prefab3, transform.position, Quaternion.identity);
                        break;
                }
                nextSpawn = Time.time + spawnRate;
            }
        }
        else
        {
            return;
        }   
    }
}

person vaso    schedule 28.09.2019    source источник
comment
как насчет того, чтобы сохранить последний созданный предмет и, если вы выберете его случайным образом, снова случайным образом, пока не получите новый? это 1 способ я думаю.   -  person Talg123    schedule 28.09.2019


Ответы (2)


Простой способ использования системы случайных чисел в сборке Unity — просто создать список возможных сгенерированных чисел и выбрать случайное число из этого списка, например:

public class randomspawnscript : MonoBehaviour {
    public GameObject prefab1, prefab2, prefab3;

    public float spawnRate = 2f;

    float nextSpawn = 0f;

    int whatToSpawn;

    private void Awake() {
        // To not get a null ref error when generating the controlled random
        // for the first time.
        whatToSpawn = 0;
    }

    void Update() {
        if (/* ... */) {
            if (Time.time > nextSpawn) {
                whatToSpawn = GetControlledRandom();
                Debug.Log(whatToSpawn);

                switch (whatToSpawn) {
                    //...
                }
                nextSpawn = Time.time + spawnRate;
            }
        } else {
            return;
        }
    }

    int GetControlledRandom() {
        List<int> possibleChoices = new List<int> {
            1, 2, 3
        };

        // Removes what was spawned before from the possible choices.
        possibleChoices.Remove(whatToSpawn);

        return possibleChoices[Random.Range(0, possibleChoices.Count)];
    }
}

В качестве альтернативы более простой способ — просто продолжать генерировать число, пока не получите тот, который вас удовлетворит, например:

    int RetardedControlledRandom() {
        int generatedNumber;
        do {
            generatedNumber = Random.Range(1, 4);
        } while (generatedNumber == whatToSpawn);

        return generatedNumber;
    }

Это может помочь, если вместо этого вы решили использовать предоставленную .NET System.Random.

Кроме того, обратите внимание, что в настоящее время большинство ваших значений/переменных являются жестко заданными.
(Кроме того, это не подходит для динамического создания более 4 типов префабов)

Unity Inspector также принимает массив, поэтому вы можете использовать его и реорганизовать свой код следующим образом:

public class randomspawnscript : MonoBehaviour {
    public GameObject[] possibleSpawnPrefabs;

    public float spawnRate = 2f;

    float nextSpawn = 0f;

    int whatToSpawn;

    private void Awake() {
        whatToSpawn = 0;
    }

    void Update() {
        if (collisionbutton.end != true || gameoverscreenrestart.restartPressed == true || gameovermainmenu.menuPressed == true) {
            if (Time.time > nextSpawn) {
                whatToSpawn = GetControlledRandom();
                Debug.Log(whatToSpawn);

                var prefabToSpawn = possibleSpawnPrefabs[whatToSpawn];
                Instantiate(prefabToSpawn, transform.position, Quaternion.identity);

                nextSpawn = Time.time + spawnRate;
            }
        } else {
            return;
        }
    }

    int GetControlledRandom() {
        List<int> possibleChoices = new List<int>();

        for (int i = 0; i < possibleSpawnPrefabs.Length; ++i) {
            possibleChoices.Add(i);
        }

        // Removes what was spawned before from the possible choices.
        possibleChoices.Remove(whatToSpawn);

        return possibleChoices[Random.Range(0, possibleChoices.Count)];
    }
} 
person Kaynn    schedule 28.09.2019
comment
Большое спасибо за такой быстрый и подробный ответ, это не только решило мою проблему, но и оптимизировало мой проект. Большое спасибо! - person vaso; 29.09.2019

Ну, просто сделайте заявление, которое проверяет новый рандомизированный префаб с предыдущим рандомизированным префабом. Для ленивого кода вы можете просто

GameObject previousPrefab;

и в Рандомизации установите для параметра previousPrefab рандомизированный префаб.

и в следующей рандомизации проверьте, не является ли предыдущий префаб == рандомизированным префабом, если да, рандомизируйте снова.

^ Также, чтобы добиться чего-то подобного, вам нужно создать метод из раздела Update() и вызвать его в Update(), чтобы вы могли снова вызвать метод, если предыдущий префаб такой же, как рандомизированный.

person Kamil Ciesielski    schedule 28.09.2019