2

Possible Duplicate:
Random number generator only generating one random number
Random not that random

This is my first attempt at using classes and objects and I have absolutely no clue as to how to handle the situation I'm currently in. I'm creating a game which requires the spawning of enemies at the edges of the screen, so I created a method that creates 10 objects and randomly selects an edge and a suitable coordinate to assign to them.

    private void spawner()
    {
        if (enemies.Count < 10)
        {
            int a;
            a = 10 - enemies.Count;

            for (int i = 0; i < a; i++)
            {
                int x, y, c;
                Random random = new Random();
                c = random.Next(0, 4);

                if (c == 0)
                {
                    x = random.Next(0, 839);
                    y = 1;
                }
                else if (c == 1)
                {
                    y = random.Next(0, 647);
                    x = 1;
                }
                else if (c == 2)
                {
                    x = 839;
                    y = random.Next(0, 647);
                }
                else
                {
                    y = 647;
                    x = random.Next(0, 839);
                }

                enemies.Add(new Enemy(5, 25, 3, new Point(x, y)));
                enemies[enemies.Count - 1].adjustPosition(player1.centreX, player1.centreY);
            }
        }
    }

I then call the method within the Enemy class to make the coordinates shift closer to the centre of the Player controlled object as well as create 3 new points that will be used to draw the enemy: enemies[enemies.Count - 1].adjustPosition(player1.centreX, player1.centreY);

    public class Enemy
    {
        public int enemyLife { get; set; }
        public Point enemyCentre { get; set; }
        public int enemyRadius { get; set; }
        public double enemySpeed { get; set; }
        public Point[] enemyVertices { get; private set; }

        public Enemy(int life, int radius, double speed, Point centre)
        {
            enemyLife = life;
            enemyCentre = centre;
            enemyRadius = radius;
            enemySpeed = speed;
        }

        public void adjustPosition(int centreX, int centreY)
        {
            double vx = 0;
            double vy = 0;
            double mag = 0;
            int x, y;

            if (enemyCentre.X != 0)
            {
                vx = centreX - enemyCentre.X;
                vy = centreY - enemyCentre.Y;
                mag = Math.Sqrt(vx * vx + vy * vy); // length

                vx /= mag;
                vy /= mag;

                x = (int)((double)enemyCentre.X + vx * enemySpeed);
                y = (int)((double)enemyCentre.Y + vy * enemySpeed);
                enemyCentre = new Point(x, y);

                int px, py, px2, py2, px3, py3;
                double angle;

                vx = centreX - x;
                vy = centreY - y;
                mag = Math.Sqrt(vx * vx + vy * vy); // length

                vx /= mag;
                vy /= mag;

                px = (int)((double)x + vx * 20);
                py = (int)((double)y + vy * 20);

                angle = Math.Atan2(centreY - y, centreX - x);

                px2 = (int)(px + (-30 * Math.Cos(0.785398163 + angle)));
                py2 = (int)(py + (-30 * Math.Sin(0.785398163 + angle)));

                px3 = (int)(px + (-30 * Math.Cos(-0.785398163 + angle)));
                py3 = (int)(py + (-30 * Math.Sin(-0.785398163 + angle)));

                Point[] points = new Point[3];
                points[0] = new Point(px, py);
                points[1] = new Point(px2, py2);
                points[2] = new Point(px3, py3);

                enemyVertices = points;
            }
        }
    }

The problem is that when I attempt to execute the program using 'Start Debugging' every created object shares the same centre coordinates with the the last added object to the list. Yet when I add a breakpoint before the objects are added to the list and Step through the code, the objects are assigned random values as they should be. Also if I remove the breakpoint after manually executing the code for some of the objects, the objects that been run manually will contain random values while the rest of the objects will share the same values. Does anyone know what could be causing this problem?

Community
  • 1
  • 1
Aedif
  • 23
  • 2
  • I dont know if thats the error, but give your random generator a seed, otherwise its not random. Random random = new Random(unchecked((int)DateTime.Now.Ticks)); – Tim Kathete Stadler Jan 18 '13 at 12:58
  • @Tim: that actually wont help him, since the ticks dont change that fast. see my answer – x4rf41 Jan 18 '13 at 13:01
  • 1
    http://stackoverflow.com/q/2727538 , http://stackoverflow.com/questions/932520/why-does-it-appear-that-my-random-number-generator-isnt-random-in-c , http://stackoverflow.com/questions/767999/random-number-generator-not-working-the-way-i-had-planned-c – H H Jan 18 '13 at 13:03

3 Answers3

3

Your problem is the new Random() since its called very fast it wont actually be random, because the random seed .net uses for the default constructor does not change (i think they use the ticks or some hash generated from it)

just make sure that new Random() is called in a way that there is some time between the calls, and use next() if u need "fast" random numbers

x4rf41
  • 5,184
  • 2
  • 22
  • 33
  • I believe Microsoft's implementation seeds with http://msdn.microsoft.com/en-us/library/system.environment.tickcount.aspx and this behavior is documented. – ta.speot.is Jan 18 '13 at 13:11
2

That's because you're re-creating the Random() object in your loop. This object generates pseudo-random numbers using a time-based seed, so several Random() objects created in a very fast loop will generate the exact same values in the same order.

When you put a breakpoint in the middle of the loop, you cause a delay changing the seed of the Random() object.

The simplest solution for this is to create the Random() object only once for this method and reuse it during the loop.

Badaro
  • 3,460
  • 1
  • 19
  • 18
  • Thank you! It works perfectly now. Never even for a second thought that it was the random number generator that was causing the problem here. – Aedif Jan 18 '13 at 13:12
  • Just for reference, if you need a better RNG you can also use System.Security.Cryptography.RNGCryptoServiceProvider. It's an overkill for most situations though. – Badaro Jan 18 '13 at 13:15
1

Move Random random = new Random(); outside of the for loop.

It is only necessary to initialize the random number generator once. Perhaps you can make it even a static variable and initialize it only once per entire lifetime of the game. Random must be seeded. It will generate the same sequence of number for the same seed. If you do not specify seed, then current time is used as the seed. Making many calls of new Random() in a short time will create them with the same seed.

Eiver
  • 2,594
  • 2
  • 22
  • 36