Базовый класс System.Drawing.Color, возвращающий только один цвет после нескольких итераций - PullRequest
0 голосов
/ 20 октября 2019

Отказ от ответственности: я, вероятно, включил слишком много информации, поэтому не пугайтесь количества включенной информации.

Я хочу сделать простую 2D-игру с графикой для консольного приложения c #. Чтобы узнать, как я справлюсь с основами графики, я сделал небольшой проект, в котором я играю с базовым классом Color (и библиотекой Colorful.Console, больше информации по адресу: http://colorfulconsole.com/). Просто пытаюсь понять основыцветового представления и смешивания.

Однако я столкнулся с проблемой, когда дело доходит до рисования нескольких цветов. Так как консоль может сохранять только 16 цветов по умолчанию, она будет возвращать пользовательские цвета RGB до 15-й итерации (Я предполагаю, что один цвет зарезервирован для черного) программы, и затем возвращаю только 15-е число снова и снова. Есть ли способ изменить значение одного из «KnownColor» снова и снова вместо заполнения всех их итогда не имея возможности перезаписать новые значения?

Мой код (упрощенный) выглядит примерно так:


class Object{
    Color color; 
    //for simplicity, let's say that I previously had byte a, r, g, b defined here;
    public Object()
    {
        byte[] rgba = new byte[4];
        Random random = new Random();
        random.NextBytes(rgba);
        color = Color.FromArgb(rgba[0], rgba[1], rgba[2], rgba[3]);
        //previously I assigned a = rbga[0] and so on.
    }
}

class Program
{
    List<Object> objects = new List<Object>();
    static void Main(string[] args)
    {
        while(true)
        {
        objects.Add(new Object()); //I have some user input here, but essentially.
            foreach(Object o in objects) 
            {
                PrintColor(o.color);
                PaintColor(o.color);
            }
        }
    }

    void PrintColor(Color c)
    {
        Console.Write("R:" + c.R + ", G:" + c.G +", B:"+ c.B + ", A:" + c.A);
    }

    static void PaintColor(Color c)
    {
        Console.BackgroundColor = Color.FromArgb(c.R, c.G, c.B);
        Console.Write(" ");
        Console.BackgroundColor = Color.Black;
    }

}

Я также пытался создать программу, которая должна рисовать диагональный серый градиент(и позже полный градиент RGB), но напрасно.

class Program
{
    static void Main(string[] args)
    {
        GraphicsEngine.GetWindowSize();
        while (true)
        {
            GraphicsEngine.FillWindowGradient();
            Console.Clear(); //I am going to replace this with moving the cursor to 0,0

            if (Console.KeyAvailable)
            {
                GraphicsEngine.GetWindowSize();
            }
        }
    }

    public static void FillWindowGradient()
    {
        int yMax = windowSize.GetLength(0);
        int xMax = windowSize.GetLength(1);
        for (int y = 0; y< yMax; y++)
            for (int x = 0; x < xMax; x++)
            {
                PaintGray((byte)((y/yMax + x/xMax)*127));
            }
    }

    public static void PaintGray(byte gray)
    {
        Console.BackgroundColor = Color.FromArgb(gray, gray, gray);
        Console.Write(" ");
        Console.BackgroundColor = Color.Black;
    }
}

Этот пример работал с любым одним столбцомили он начинался с, но не мог справиться с градиентом, что, как я полагаю, связано с той же проблемой, что и в первом примере.

PS: было бы также неплохо узнать, есть ли «более дешевый» / более быстрый способ окраски ячейки, чем:

Console.BackgroundColor = Color.Argb (a, r, g,б);

Console.Write ("");

1 Ответ

0 голосов
/ 21 октября 2019

Ваша проблема в том, что вы создаете новый объект Random каждый раз, когда вы генерируете новый объект типа Object.

Из MSDN:

Только в .NET Framework, поскольку часы имеют конечное разрешение, использование конструктора без параметров для создания различных случайных объектов в последовательной последовательности создает генераторы случайных чисел, которые генерируют идентичные последовательности случайных чисел.

Возможное решение:

  1. Создайте один объект Random в вашем классе Program и используйте его инициализацию с использованием текущей отметки времени.

    Random _random = new Random((int)DateTime.UtcNow.Ticks);
    
  2. Передайтеэкземпляр случайного числа в классе Object.

  3. ИЛИ, намного чище -> Передать фактический случайный цвет конструктору Object.

    class Object
    {
        private Color color; 
    
        public Object(Color c)
        {        
            color = c;   
        }
    }
    
    var rgba = new byte[4];
    random.NextBytes(rgba);
    var obj = new Object(Color.FromArgb(rgba[0], rgba[1], rgba[2], rgba[3]));
    

Редактировать:

В продолжение ваших комментариев. Я использовал ваш пример для генерации Object экземпляров в цикле, генерируя случайное Color. В конце проверяем дубликаты, используя ToArgb в качестве ключа. Запуск 1000 раз в цикле, без дубликатов. Запуск 1M раз, в среднем ~ 110 дубликатов.

class Program
{
    static List<Object> objects = new List<Object>();

    static Random _random = new Random((int) DateTime.UtcNow.Ticks);

    static void Main(string[] args)
    {
        var i = 0;
        while (i<1000)
        {
            var rgba = new byte[4];
            _random.NextBytes(rgba);
            objects.Add(new Object(rgba));
            i++;
        }

        foreach (Object o in objects)
        {
            PrintColor(o.color);
        }

        var query = objects.GroupBy(x => x.color.ToArgb())
            .Where(g => g.Count() > 1)
            .Select(y => y.Key)
            .ToList();

        Console.WriteLine($"Duplicates {query.Count}");
    }

    static void PrintColor(Color c)
    {
        Console.WriteLine("R:" + c.R + ", G:" + c.G + ", B:" + c.B + ", A:" + c.A);
    }
}
...