1

I'm making a Breakout Game and I want the bricks to get a random BackColor. Right now I have the bricks getting filled with all type of colors: red, green, blue, yellow, pink and all others.

What I want to do though is only get the random to randomize three colors only : blue, yellow and green.

This is what I have now:

private Random rnd = new Random();

Color randomColor = Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256));

bricks[x, y].BackColor = randomColor;

I've searched and tried many different things and nothing has worked! I feel like this might be simple to do but somehow can't really get to it. I thought about making a list of the 3 colors and try randomizing the list but it didn't work out!

Bassie
  • 9,529
  • 8
  • 68
  • 159

5 Answers5

3

Disclaimer: I'm a newbie (to C#).

private Random rnd = new Random();
Color[] colorArr = {Color.FromArgb(0, 0, 255), Color.FromArgb(255, 255, 0), Color.FromArgb(0, 255, 0)};
bricks[x, y].BackColor = colorArr[rnd.Next(colorArr.Length)];

(colorArr.Length edit suggested by Corak)

Uses an array to store all the colors from which one will be picked. Next, a random element is called from the array.

Vedaant Arya
  • 475
  • 6
  • 18
  • 4
    If you use `rnd.Next(colorArr.Length)`, you don't need to think about it when adding or removing colors. – Corak May 12 '18 at 13:27
3

About the comments:
The use of Thread.Sleep() is just an example to test the results of a local instance of the Random class when used in a close loop.
You will, probably, get series of the same result. Or all identical values.


Here, as a test, I'm inserting a small pause (1ms) when returning the random color, so the colors will be selected using a different seed (almost) every time. Test it without the pause.

The default implementation, using a single instance of the Random class, can yield similar results.

private Color[] Colors = { Color.Red, Color.Yellow, Color.Green};

private Color GetColor()
{
    Random random = new Random(DateTime.Now.Millisecond);
    Thread.Sleep(1);
    return Colors[random.Next(0,3)];
}

Test it without the Thread.Sleep() pause:

for (int i = 0; i < 100; i++)
{
    Console.WriteLine(GetColor().Name);
}

Or, more properly, using a static Field:

private static Random random = new Random();

private Color GetColor()
{
    return Colors[random.Next(0,3)];
}

A slightly different method to get different shades of Red, Green and Yellow for each element:
(It should probably be tweaked a little to avoid semi-gray color).

private Color GetColor2()
{
    Color color = Colors[random.Next(0, 3)];
    switch (color.Name)
    {
        case "Yellow":
            color = Color.FromArgb((160 + random.Next(0, 96)), (160 + random.Next(0, 96)), 0);
            break;
        case "Red":
            color = Color.FromArgb((160 + random.Next(0, 96)), 0, 0);
            break;
        case "Green":
            color = Color.FromArgb(0, (160 + random.Next(0, 96)), 0);
            break;
    }
    return color;
}

This is a random palette this method generates:

enter image description here

Jimi
  • 29,621
  • 8
  • 43
  • 61
  • *Or* have *one* source of randomness for the whole application... -- btw. `new Random(DateTime.Now.Millisecond)` is (theoretically) ten thousand times worse than not specifying a seed. Without a given seed `Environment.TickCount` is used. See [Recerence Source Random.cs](https://referencesource.microsoft.com/mscorlib/System/random.cs.html). And there are [10000 Ticks per Millisecond](https://msdn.microsoft.com/library/system.timespan.tickspersecond.aspx). -- Although you usually only see "jumps" of somewhere between 100 and 200 Ticks. – Corak May 12 '18 at 13:53
  • @Corak As I said, it's just an example. But you can test Random without a Seed with or without a pause and see what comes out. Then confront it with what I posted. – Jimi May 12 '18 at 13:57
  • I *know* creating a new instance of `Random` in a close loop is bad. And because of the reasons you state, too. But your conclusion, that using Milliseconds would somehow make it better is wrong. What *does* make it better in you example is `Thread.Sleep(1);` but (as you also stated) that will kill performance if you need any serious amount of random values. Much *much* better would be for example to have *one* `static Random random = new Random();` outside any method and use *that* how often and in how ever quick succession you want. – Corak May 12 '18 at 14:03
  • @Corak Thread.Sleep is just an example to test the results. It won't really be needed. Performance can be an issue, of course, but also, since you need a random number, you want it *random*. If you rely on the standard results, you'll probably get some series of the same pseudo random value. Maybe, if you really care about randomness, you can pay your tribute to performance. That is a choice. The important thing, I think, is to know about it. – Jimi May 12 '18 at 14:16
  • 1
    The `Random` class is perfectly fine if you want random numbers. It's not *cryprographically secure*, but that security is not needed here. Again, the problem of getting "the same value over and over" is *only* because a lot of instances of `Random` are created in a close loop. You *don't* have that problem if you only work with *one* instance. Try this: `public static class RandomTest { private static Random random = new Random(); public static void Test() { for(i = 1; i < 1000; i++){ Console.WriteLine(random.Next()); } } }` and tell me, how many "same" numbers you get in a row. – Corak May 12 '18 at 14:26
  • Sorry, this statement is plain wrong: "The point is, pay attention to how Random() is implemented, otherwise you'll quite probably get series of the same result. Or all identical values." -- We're talking about the `Random` class provided by the Framework, so you don't need to "pay attention" to how it's implemented. And for the last time, you only get a "series of the same result" if you're creating new instances of `Random` in very quick succession (i.e. in a loop). I don't know how to explain it to you any better, and at this point, I give up. – Corak May 12 '18 at 15:03
  • @Corak I don't want you to think that I don't agree with you on the use of the Random class. I just wanted to point out (since I've seen this a lot) that you have to pay attention when using the Random class (when you implement it in your code), if you need it to actually return random values. I wrote *Test it without the pause:* for that reason. I probably didn't explain it that well. – Jimi May 12 '18 at 15:21
  • 1
    Okay, If you meant it as "pay attention to how you **use** Random()" I agree. I took it as critique on how the `Random` class itself is implemented. -- And sorry for having overlooked your "Or ..." part. – Corak May 12 '18 at 15:32
  • @Corak No, you're right. I wrote this very badly. Thanks for your remarks. – Jimi May 12 '18 at 15:35
2

Write your own method and call that instead. Generate a random number e.g 0,1,2 and using a switch return the correct colour. E.g:

Color randomColor;
int random = rnd.Next(3)
  switch (random)
  {
      //red
      case 1:
          randomColor = Color.FromArgb(255, 0, 0);
          break;
      //green
      case 2:
          randomColor = Color.FromArgb(0, 255, 0);
          break;
      //blue
      default:
          randomColor = Color.FromArgb(0, 0, 255);
          break;
  }
jducreux
  • 107
  • 2
  • 9
1

why not map the 3 colors of your choice to numbers {0,1,2} and then make a simple switch statement?

int color;
color = rnd.Next(3);
switch(color) {
case 0:
    // do something here for the first color
    break;
case 1:
    // do something.. you get the idea
    break;
case 2:
    break;
}

and then just hope that the randomness of Random in C# is good enough for your game ;)

EDIT: damn it, too late :D

BassSultan
  • 574
  • 1
  • 5
  • 11
1

You could write it as an extension to Color

public static class ColorExtensions
{
    private static Color[] rgb = 
        {Color.FromArgb(0, 0, 255), Color.FromArgb(255, 255, 0), Color.FromArgb(0, 255, 0)};
    private static Random random = new Random();
    public static Color GetRandomRgb(this Color color)
    {
        return rgb[random.Next(rgb.Length)];
    }
}

However, since you can't yet extend a class by adding static methods, meaning you have to call that using an instance of Color, eg

var colour = new Color().GetRandomRgb();

and Color is a sealed class (meaning we can't inherit from it), you might like to do

public static Color GetRandomRgb()
{
    return rgb[random.Next(rgb.Length)];
}

Which you can call with

var colour = ColorExtensions.GetRandomRgb();
Bassie
  • 9,529
  • 8
  • 68
  • 159