Почему метод возвращает одно и то же значение дважды, когда должен возвращать случайное значение?

Я делаю игру "Построй башню". В моей игре я текстурирую стороны куба случайным образом, поэтому каждый новый куб имеет случайные текстуры на каждой стороне. Новые кубы создаются скриптом, прикрепленным к пустому игровому объекту gamemanager. Этот игровой менеджер прикрепляет скрипт "TextureController" к каждому новому кубу. Этот скрипт отвечает за создание текстурного атласа и подбор УФ-лучей для каждой стороны куба. Текстуры загружаются и сохраняются в скрипте "TextureContainer" (также прикрепленном к "gamemanager"), который имеет метод, который возвращает случайный массив текстур. Это прекрасно работает, и, как и планировалось, кроме одного. Первый (базовый) куб создается не скриптом, а мной. Он имеет другой скрипт (назовем его "baseCubeTextures"), который должен получить массив из "gamemanager", создать собственный текстурный атлас и установить UV-координаты по сторонам куба. Но дело в том, что текстуры базового куба всегда такие же, как и у первого созданного куба по сценарию. Чтобы было немного понятнее:

GameManager имеет скрипт GameManagerScript с методом CreateNextCube() с линией там:

playerCube.AddComponent<TextureController>().atlasTextures = GetComponent<TextureContainer>().getTextures(TextureSize.Ten);

он также имеет TextureContainer Сценарий привязан.

TextureContainer есть метод, который возвращает случайный массив текстур:

public Texture2D[] getTextures(TextureSize textureSize)
{

    switch (textureSize)
    {
        case TextureSize.Ten:
            textures[0] = textures10x6[Random.Range(0, textures10x6.Length)];
            textures[2] = textures10x6[Random.Range(0, textures10x6.Length)];
            textures[4] = textures10x6[Random.Range(0, textures10x6.Length)];
            textures[5] = textures10x6[Random.Range(0, textures10x6.Length)];

            break;
        case TextureSize.Eight:
            break;
        case TextureSize.Six:
            break;
        case TextureSize.Four:
            break;
        case TextureSize.Two:
            break;
        case TextureSize.One:
            break;
        default:
            break;
    }

    textures[1] = topBottomtextures[Random.Range(0, topBottomtextures.Length)];
    textures[3] = topBottomtextures[Random.Range(0, topBottomtextures.Length)];

    return textures;
}

Базовый куб имеет скрипт, более или менее похожий на этот:

public GameObject gameController;
private Texture2D[] atlasTextures = new Texture2D[7];
private Texture2D atlas;

Mesh mesh;
Vector2[] originalUVs;
private Rect[] atlasUVs;
// Use this for initialization
void Start()
{
    atlasTextures = gameController.GetComponent<TextureContainer>().getTextures(TextureSize.Ten);
// code for setting UVs
}

Так почему же у меня такие же текстуры из метода getTextures()? Это потому, что я вызываю этот метод почти одновременно (метод вызывается в Start() обоих сценариев)? Я читал, что это может произойти с генераторами случайных чисел. Можно ли здесь как-то избежать этого?

2 ответа

Решение

Мне нужен полный код, чтобы быть уверенным, но я думаю, что проблема здесь в том, что скрипт TextureContainer, прикрепленный к вашему GameManagerScript, всегда возвращает один и тот же указатель массива "текстуры".

Вам не хватает "Texture2D[] textures = new Texture2D[]" в начале функции.

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

Приведенные ниже функции выполняются с таймером для остановки, если не удается сгенерировать случайное число в течение 2 секунд. Вы всегда можете это изменить. Также в Unity есть ошибка для их класса Random, которая иногда возвращает одно и то же число в функции с циклом while. Эта ошибка также существует в Unity, даже если вы используете класс System.Random.

Эти две функции должны сделать случайные числа текстур не повторяющимися.

/// FOR textures10x6
    public List<int> newRandtextures10x6List = new List<int>();
    private void newRandtextures10x6Func(int arrayAmount)
    {
        System.Random a = new System.Random();
        int MyNumber = 0;

        //Reset
        newRandtextures10x6List.Clear();

        //2 seconds Timer. If it blocks exit 2 seconds exit
        System.DateTime startTime = System.DateTime.UtcNow;
        System.TimeSpan exitTime = System.TimeSpan.FromSeconds(2);

        bool quitRand = false;

        for (int i = 0; i < arrayAmount; i++)
        {
            do
            {
                if (System.DateTime.UtcNow - startTime > exitTime)
                {
                    quitRand = true;
                    Debug.Log("Time out Reached! ...Assigning 0 to it");
                    newRandtextures10x6List.Add(0);
                    break;
                }
                MyNumber = a.Next(0, arrayAmount);
            } while (newRandtextures10x6List.Contains(MyNumber));
            newRandtextures10x6List.Add(MyNumber);

            /* OPTIONAL. WILL QUIT THE WHOLE FUNCTION INSTEAD OF JUST THE WHILE LOOP
            if (quitRand)
            {
                break;
            }*/
        }
    }

    /// FOR topBottomtextures
    public List<int> newRandTopBottomtexturesList = new List<int>();
    private void newRandTopBottomtexturesFunc(int arrayAmount)
    {
        System.Random a = new System.Random();
        int MyNumber = 0;

        //Reset
        newRandTopBottomtexturesList.Clear();

        //2 seconds Timer. If it blocks exit 2 seconds exit
        System.DateTime startTime = System.DateTime.UtcNow;
        System.TimeSpan exitTime = System.TimeSpan.FromSeconds(2);

        bool quitRand = false;

        for (int i = 0; i < arrayAmount; i++)
        {
            do
            {
                if (System.DateTime.UtcNow - startTime > exitTime)
                {
                    quitRand = true;
                    Debug.Log("Time out Reached! ...Assigning 0 to it");
                    newRandTopBottomtexturesList.Add(0);
                    break;
                }
                MyNumber = a.Next(0, arrayAmount);
            } while (newRandTopBottomtexturesList.Contains(MyNumber));
            newRandTopBottomtexturesList.Add(MyNumber);

            /* OPTIONAL. WILL QUIT THE WHOLE FUNCTION INSTEAD OF JUST THE WHILE LOOP
            if (quitRand)
            {
                break;
            }*/
        }
    }

Чтобы проверить newRandtextures10x6Func() Функция, которую вы можете использовать:

 newRandtextures10x6Func(6);

for (int i = 0; i < newRandtextures10x6List.Count; i++)
{
    Debug.Log(newRandtextures10x6List[i]);
}

Он сгенерирует 6 разных чисел, и они никогда не будут одинаковыми.

Ниже остальная часть кода для вашего вопроса.

public Texture2D[] getTextures(TextureSize textureSize)
    {

        switch (textureSize)
        {
            case TextureSize.Ten:

                //Generate the random numbers here with no repeated values
                newRandtextures10x6Func(textures10x6.Length);
                textures[0] = textures10x6[newRandtextures10x6List[0]];
                textures[2] = textures10x6[newRandtextures10x6List[2]];
                textures[4] = textures10x6[newRandtextures10x6List[4]];
                textures[5] = textures10x6[newRandtextures10x6List[5]];

                break;
            case TextureSize.Eight:
                break;
            case TextureSize.Six:
                break;
            case TextureSize.Four:
                break;
            case TextureSize.Two:
                break;
            case TextureSize.One:
                break;
            default:
                break;
        }

        //Generate the random numbers here with no repeated values
        newRandTopBottomtexturesFunc(topBottomtextures.Length);
        textures[1] = topBottomtextures[newRandTopBottomtexturesList[0]];
        textures[3] = topBottomtextures[newRandTopBottomtexturesList[1]];

        return textures;
    }
Другие вопросы по тегам