Почему метод возвращает одно и то же значение дважды, когда должен возвращать случайное значение?
Я делаю игру "Построй башню". В моей игре я текстурирую стороны куба случайным образом, поэтому каждый новый куб имеет случайные текстуры на каждой стороне. Новые кубы создаются скриптом, прикрепленным к пустому игровому объекту 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;
}