【问题标题】:2D particle system with random velocities具有随机速度的二维粒子系统
【发布时间】:2011-08-17 20:09:13
【问题描述】:

我最近使用 Visual Basic .Net 编写了一个粒子系统,它在 x 和 y 方向以随机速度发射粒子并受重力影响。我切换到 C# .Net 并使用 XNA Game Studio,这使得图形处理比 GDI+ 方便得多。

我在 C# 中遇到的问题是随机数不够“随机”。我的粒子系统有 2500 个粒子,但您可以清楚地看到粒子以网格状方式分布,相距约 100 个像素,而 Visual Basic 的 Rnd() 函数没有这个问题。

Visual Basic 做了哪些 C# 不做的事情,如何在 C# 中获得相同的结果?

我尝试在游戏循环的不同阶段重新初始化我的随机数,但最终我的粒子要么停留在一个位置,要么仅以恒定的流向一个方向发射。

这是我的 C# 代码:在程序启动后首先调用 LoadContent。我使用毫秒作为种子,以便每次都以不同的配置开始。

下一次我重新播种是在渲染之前在系统上完成所有计算之后。我尝试的另一种选择是在计算每 100 个粒子后重新播种,但没有区别。

        protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);
        mousePos = Content.Load<Texture2D>("Point");
        spriteTex = Content.Load<Texture2D >("Point");
        rnd = new Random(a.Millisecond);
        for (int i = 0; i < spritePos .Length; i++)
        {
            newPos[i] = new Vector2(800, 450);
            spritePos[i] = newPos[i] ;
            Scale[i] = rnd.Next(100,500);
            renderCol[i] = new Color(rnd.Next(255), rnd.Next(255), rnd.Next(255), 1);
            spriteVelocity[i] = new Vector2((rnd.Next(2000)-1000)/100, -rnd.Next(500,1500)/100);
            Life[i] = rnd.Next(60);
            Rotate[i] = (rnd.Next(1000)-500) * 0.001f;
            RotateSpeed[i] = (rnd.Next(1000)-500) * 0.0001f;

        }

    }

这是我的VB代码,唯一用到rnd函数的地方:

            For i = x To x + 1000
                ptc(i) = New particle(New Vector((Rnd() * 200) - 200 * Rnd(), Rnd() * -100 - 200 * Rnd() - 200), New Vector(e.X, e.Y), 500, Color.FromArgb(Rnd() * 255, 255, 0))
                x += 1
            Next

在我的 VB 代码中,我没有调用 randomize 函数的地方,我注意到如果我这样做,我的粒子具有相同的类似模式的行为。请原谅所有奇怪的算术,这只是实验。

【问题讨论】:

  • 你能告诉我们你的代码(VB.net 和 C#)吗?
  • 你能发布一个sn-p的代码吗?即,初始化新粒子并设置其速度的代码。
  • 还要确保您没有为每个要创建 (link) 的随机数创建新的 Random 实例。
  • ((rnd.Next(2000)-1000)/100 使用 Random.Next(int maxValue) 生成介于 0 和 maxValue 之间的随机整数。我认为这可能是网格状外观的原因. 试试 Random.NextDouble()

标签: c# .net gdi+ xna-4.0


【解决方案1】:

好的,Charl 修复它的方法是创建一个没有种子的 Random 对象(你就是),然后一遍又一遍地使用它。所以像:

const double max = 1000.0;
Random rand = new Random();     // Like mentioned, don't provide a seed, .NET already picks a great seed for you
for(int iParticle = 0; iParticle < 2500; iParticle++)
{
    double x = rand.NextDouble() * max;     // Will generate a random number between 0 and max
    double y = rand.NextDouble() * max;
}

要在下限和上限之间获取随机浮点值(float 或 double),您可以使用类似的方法:

double x = (rand.NextDouble() * (max - min)) + min;

编辑:并确保使用双精度或浮点数。 Ints 只是整数,double 和 float 可以存储实数,这可能是 VB 使用的。

【讨论】:

  • 注意:如果你真的需要一个整数值,比如颜色,使用 rand.Next(255) 是完美的,这就是你应该使用的。
  • 非常感谢,这是完美的解决方案!所以整数就是问题所在。
  • 我不介意颜色,在那里很难看到任何图案,但现在我的粒子实际上“足够随机”了。
【解决方案2】:

如果您发布了一些代码,我们可能能够指出您在哪里为每次调用创建 new Random() 对象。

例如,Random number in a loop


看到代码后,

你知道(rnd.Next(2000)-1000)/100 是一个纯整数表达式吗?结果将转换为float,但始终以##.0结尾。

在 VB 中 I / J 产生一个双精度值。

【讨论】:

  • 谢谢,但是在循环中声明我的随机数只会让我的粒子看起来“围绕原点运行,它根本不动。这就是为什么我如此难过,任何补救的尝试我的困境只会使情况变得更糟,但我确信有一个解决方案。
  • 是的,我尝试了 John McD 的答案,确实是整数给我带来了问题,而且 C# 抱怨类型转换的次数比 VB 多得多。
【解决方案3】:

Random 类确保伪随机性,如果你正在使用它的话。看看RNGCryptoServiceProvider

【讨论】:

  • 我在这个论坛上阅读了很多关于随机数和 CSRNG 的大部分内容,在统计数据中,我们还了解了伪随机数,它们实际上不是随机的。让我烦恼的是,简单的 VB 函数 Rnd() 给了我足够的结果,但 C# 没有。它们都是 .Net,所以我认为它们会使用相同的算法,但 C# 没有 Rnd() 函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-26
  • 1970-01-01
  • 1970-01-01
  • 2011-02-09
  • 1970-01-01
  • 2012-06-28
相关资源
最近更新 更多