Don't put your Random in the Ball class. Instead, pass it into the constructor. A better method would be to wrap the Random class in an Interface so you can supply various implementations of random number generators, especially useful for testing your application. This is called "dependency injection".
Instead of the Ball class using it's own RNG, it'll can use a Random implementation passed to it by the calling code.
The problem that you're running into is when your code creates a bunch of instances of Ball, one or more of them can use the default seed value which is the current Timer value. In that case, each one of those Random classes will kick out the same sequence of "random" numbers.
Your modified Ball class:
public class Ball
{
IRandom rng;
private Ball()
{
}
public Ball(IRandom random)
{
if (random == null)
{
throw new ArgumentNullException("random");
}
rng = random;
}
... snip 8< ...
}
The IRandom interface:
public interface IRandom
{
int Next();
int Next(int);
double NextDouble();
}
Your "default" IRandom implementation:
public class DefaultRandom : IRandom
{
Random rng;
public DefaultRandom()
{
rng = new Random();
}
public DefaultRandom(int seed)
{
rng = new Random(seed);
}
public int Next()
{
return rng.Next();
}
public int Next(int ceiling)
{
return rng.Next(ceiling);
}
public double NextDouble()
{
return rng.NextDouble();
}
}
Finally, in your game code, you simply create an instance of your IRandom implementation and pass it to your Ball. Your game should have only one IRandom and you can then pass that to as many objects as you want. Everything would work off of the same RNG:
DefaultRandom rng = new DefaultRandom();
Ball myBall = new Ball(rng);