【问题标题】:Why the method returns same value twice when it should return random value?为什么该方法应该返回随机值时两次返回相同的值?
【发布时间】:2016-04-04 07:55:28
【问题描述】:

我正在制作一个“建塔”游戏。在我的游戏中,我随机地对立方体侧面进行纹理处理,因此每个新立方体的每一面都有随机纹理。新立方体由附加到“gamemanager”空游戏对象的脚本创建。此游戏管理器将“TextureController”脚本附加到每个新立方体。该脚本负责创建纹理图集并为立方体的每一面拾取 UV。纹理被加载并存储在“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 个 RNG 产生相同的一组数字,因为它们使用相同的时间作为它们的种子)。
  • @RB., Random 是一些 Unity 的东西。
  • textures10x6.Length 的值是多少?您是否尝试过调试解决方案?
  • Random.Range 从参数中定义的范围返回 int。我知道单个实例可能会有所帮助(类似帖子的一些答案建议),但我不知道在 Unity 中是否可行。 textures10x6.Length 没有问题
  • 它总是返回相同的值吗?还是只是有时? (因为在后一种情况下,这将是预期的行为。)

标签: c# arrays random unity3d return-value


【解决方案1】:

我需要完整的代码来确定,但我认为这里的问题是附加在 GameManagerScript 上的 TextureContainer 脚本总是返回相同的数组指针“纹理”。

您在函数开头缺少“Texture2D[] textures = new Texture2D[]”。

【讨论】:

  • 嗯,不,不是那样的。如果是这样,他会得到一个 NRE 而不是相同的值。
  • 令我惊讶的是,这实际上是有效的。我没有在这里设置纹理[],因为我需要在之前(编码的早期阶段)在 Awake() 中加载纹理,然后我就这样离开了。现在,我根据您的建议重新编写了代码,并且效果很好。还是为什么它没有返回不同的随机值?
  • 有一件事我不太明白,那就是 > textures[0] = textures10x6[Random.Range(0, textures10x6.Length)];纹理[2] = 纹理10x6[随机范围(0,纹理10x6.长度)];纹理[4] = textures10x6[Random.Range(0, textures10x6.Length)];纹理[5] = 纹理10x6[随机范围(0,纹理10x6.长度)];具有所有相同的值?还是调用 getTextures() 中的纹理?
  • 该方法返回了不同的纹理[0]、纹理[1]等,因此生成器在这里正常工作。但是当另一个脚本调用相同的方法时,它会返回相同的纹理集。但它只发生在第一个游戏周期,后来,当游戏周期中只有一次调用该方法时一切正常(因为 basecube 在游戏中只调用一次 getTextures())。
  • 好吧我明白了,那么我认为这与 Unity 在着色器中设置其 UV 时有关。最有可能的是,当您设置 UV 时,它在调试中可能看起来“不错”(我的意思是不同的值)。但是如果 Unity 等待所有 Starts 调用结束来实际设置 UV,它们也可能都指向同一个数组。
【解决方案2】:

我知道这个问题已经得到解答,但我决定提供我的答案,因为我已经在研究这个问题,当前的解决方案无法使随机数不重复。因此,您可能会有两个具有相同纹理的面。

下面的功能是用定时器来做的,如果在 2 秒内没有生成随机数,就会停止。你总是可以改变它。 Unity 的 Random 类也有一个错误,有时会在函数中通过 while 循环返回相同的数字。即使您也使用 System.Random 类,Unity 中也存在此错误。

这两个函数应该使纹理的随机数不重复。

/// 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;
    }

【讨论】:

  • 谢谢!我会研究一下 :) 因为我不介意在随机生成中重复,所以我可能不会应用它,但它仍然非常有趣 :)
  • 关于 System.Random() - 我注意到,用 System.Random 实例替换了 Random.range 并得到了相同的结果。但正如您所指出的,这是已知的 Unity 问题
  • 好的。如果重复不是您的游戏中的问题,您就不需要它。是的,这是一个已知问题。几年前,我尝试在 while 循环中生成 rand 数组,但它们都是一样的。有时会发生,有时不会发生。许多人报告了这个错误,但 Unity 无法修复该错误。我上面的代码是解决方案,希望它能帮助其他人。快乐编程。
  • WTF 老兄 .. 我无法通读此 QA 中的所有代码,因为它太长了。但是要让你随机播放的任何东西都“不重复”。这里的所有都是它的。 shuffled = x.OrderBy(r=&gt;Random.value).ToList();
  • 是的,乔,我记得你的解决方案,因为我是喜欢它的人之一。它非常简单且更易于实现,但该解决方案的问题是它有时会在 iOS 上崩溃。这是因为使用了 LINQ。这个话题在这里描述起来很复杂,但我不使用任何具有 linq 或 unity 事件的东西。一个例外是统一事件是否来自 UI。您可能在 iOS 上使用 linq 没有任何问题或内存问题,但是当您的游戏无缘无故开始崩溃时,您会明白的。 :)
猜你喜欢
  • 2012-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-10
  • 1970-01-01
  • 2013-12-31
相关资源
最近更新 更多