Reputation: 486
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". My 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.
Upvotes: 1
Views: 1826
Reputation: 1799
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.
Upvotes: 3
Reputation: 273274
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.
Upvotes: 1
Reputation: 3689
Random class ensures pseudo-randomness, if that is what you are using. Have a look at RNGCryptoServiceProvider.
Upvotes: -1