开发者

2D particle system with random velocities

I have recently used Visual Basic .Net to write a particle system which emits particles with random velocities in the x and y direction and is affected by gravity. I switched to C# .Net and used the XNA Game Studio which makes the graphics handling much more convenient than GDI+.

The problem I have with C# is that the random numbers are not "random enough". M开发者_运维百科y particle system has 2500 particles but you can clearly see that the particles are distributed in a grid-like fashion about 100 pixels apart and I did not have that problem with Visual Basic's Rnd() function.

What does Visual Basic do which C# does not, and how can I get the same results in C#?

I have tried to re-initialise my random numbers at different stages of the game loop but I end up either with my particles staying at one position or emitting just in a constant stream in one direction.

This is my C# code: LoadContent is called first thing after the program has started. I'm using the millisecond as a seed just so that I start each time with a different configuration.

The next time I re-seed is after all the calculations are done on the system just before rendering. The other alternative I tried is to re-seed after every 100 particles have been calculated but with no difference.

        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;

        }

    }

This is my VB code, the only place where I use the rnd function:

            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

In my VB code there is no place where I call the randomize function, I have noticed that my particles have the same pattern-like behaviour if I do. Excuse all the strange arithmetic, it's all just experimentation.


Ok, what you do to fix it Charl, is to create a single Random object (which you are) with no seed, and use it over and over again. So something like:

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

To get a random floating point value (float or double) between a lower and upper bound, you can use something like:

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

EDIT: And make sure to use double or float. Ints are whole numbers only, doubles and floats can store real numbers and is probably what VB was using.


If you had posted some code we would probably have been able to point out where you are creating a new Random() object for each call .

Like in, for example, Random number in a loop


After seeing the code,

are you aware that (rnd.Next(2000)-1000)/100 is an integer only expression? The result will be converted to float but always end in ##.0.

In VB I / J yields a double.


Random class ensures pseudo-randomness, if that is what you are using. Have a look at RNGCryptoServiceProvider.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜