Konzolový Had 2 – Vykreslovanie

 V dnešnom dieli sa pozrieme na vykresľovanie na obrazovku.

Úvod

Napriek tomu, že robíme len konzolovú aplikáciu, si spravíme triedu, ktorá obstará vykresľovanie na obrazovku.

Vykresľovanie

Na vykresľovanie budeme používať samostatnú triedu, ktorú nazveme Renderer. Keďže budeme vykresľovať obsah len do jednej konzoly, bude nám stačiť jedna inštancia tejto triedy, takže ju spravíme statickú. V nej si budeme ukladať, čo sa ma vykresľovať, veľkosť okna a robiť všetky grafické operácie.

Premenné

Na začiatok budeme potrebovať premenné, do ktorých si budeme všetko ukladať. Nasledujúce tri definujte ako súkromnéPrivate. Ako prvé budeme potrebovať dvojrozmerné pole pixelov, pričom jeho veľkosť som nastavil na 80×30 a pomenoval som ho Display. Ďalej budete potrebovať premennú označujúcu veľkosť okna – nazval som ju Size a ako základné údaje som mu dal X 80 a Y 30. Na koniec ešte definujeme premennú určujúcu farbu pozadia – BackroundColor, ktorá bude typu ConsoleColor.

private static Pixel[,] Display = new Pixel[80, 30];
private static Vector2 Size = new Vector2(80, 30);
private static ConsoleColor BackgroundColor = ConsoleColor.Black;

Ďalej si pridáme jednu verejnú –  Public vlastnosť, ktorá bude slúžiť na nastavovanie veľkosti okna. Jej getter bude vracať hodnotu premennej Size. V setteri najprv vytvoríme nové pole Pixelov podľa novej hodnoty a do neho skopírujeme staré pole. Pokiaľ sa pole zväčšilo, zaplníme ho novými pixelmi farbi BackgroundColor, až po tomto nastavíme premennú Size.

public static Vector2 WindowSize
{
    get
    {
        return Size;
    }
    set
    {
        Pixel[,] DisplayNew = new Pixel[value.X, value.Y]; //Vytvoríme nové pole pixelov
        for (int x = 0; x < value.X; x++)
        {
            for (int y = 0; y < value.Y; y++)
            {
                if ((x >= Size.X) || (y >= Size.Y)) //Ak je nová veľkosť väčšia ako stará
                {
                    DisplayNew[x, y] = new Pixel() { Color = BackgroundColor }; //Vytvoríme nový pixel
                }
                else
                {
                    DisplayNew[x, y] = Display[x, y]; //Inak ponecháme starý
                }
            }
        }
        Display = DisplayNew; //Uložíme nové pole
        Size = value; //Priradíme novú veľkosť
    }
}

Inicializácia a čistenie

Nasleduje inicializovanie všetkých premenných, ktoré prebehne ako prvá vec po zapnutí hry. V tom nastavíme veľkosť okna, zakážeme viditeľnosť kurzora a pripravíme všetky pixeli.

public static void Init()
{
    Console.SetWindowSize(Size.X, Size.Y);
    Console.CursorVisible = false;
    for (int x = 0; x < Size.X; x++)
    {
        for (int y = 0; y < Size.Y; y++)
        {
            Display[x, y] = new Pixel() { Color = BackgroundColor, Changed = false };
        }
    }
}

Potom si ešte pripravíme základnú metódu na vyčistenie obrazovky. V nej nahradíme všetky pixeli prázdnymi, ktorých farba bude mať hodnotu BackroundColor. Okrem toho však skontrolujeme, či sa zmenili oproti originálu a podľa toho im nastavíme premennú Changed na true, alebo hodnotu akú mali pôvodne.

public static void Clean()
{
    for (int x = 0; x < Size.X; x++)
    {
        for (int y = 0; y < Size.Y; y++)
        {
            Pixel p = new Pixel();
            p.Color = BackgroundColor;
            if (p != Display[x, y]) p.Changed = true;
            else p.Changed = Display[x, y].Changed;
            Display[x, y] = p;
        }
    }
}

Čo sa týka čistenia, spravíme si ešte pomocnú metódu, ktorá nastaví farbu pozadia.

public static void Clean(ConsoleColor Background)
{
    BackgroundColor = Background;
    Clean();
}

Vykresľovanie do premennej Display

Teraz už prichádzajú štyri metódy, ktoré budú obstarávať vykresľovanie do premennej Display. Ako prvé si pripravíme jednoduché vykreslenie jedného bodu. Toto skontroluje, či sa nesnažíme vykresliť bod mimo obrazovku a následne ho zapíšeme.

public static void DrawPoint(Vector2 Point, ConsoleColor color)
{
    if ((Point.X >= 0) && (Point.Y >= 0) && (Point.X < Size.X) && (Point.Y < Size.Y)) //Ak nieje mimo obrazovku
    {
        Pixel p = new Pixel(); //Vytvorí nový bod
        p.Color = color; //Nastaví mu farbu
        Display[Point.X, Point.Y] = p; //A priradí ho. Nový bod ma automaticky nastavené Changed na true
    }
}

Vykreslenie jedného bodu je jednoduché, a podobne je to aj z obdĺžnikom. Pri ňom musíme však prejsť všetky body, ktoré obdĺžnik obsiahne.

public static void DrawRectangle(Rectangle Rectangle, ConsoleColor color)
{
    for (int X = Rectangle.X; X < Rectangle.X + Rectangle.Width; X++)
    {
        for (int Y = Rectangle.Y ; Y < Rectangle.Y + Rectangle.Height; Y++)
        {
            //Prejde všetky body obdĺžnika
            if ((X < Size.X) && (X >= 0) && (Y < Size.Y) && (Y >= 0)) //Skontroluje, či sú na obrazovke
            {
                Pixel p = new Pixel();
                p.Color = color;
                Display[X, Y] = p; //A vykreslí ich
            }
        }
    }
}

Na záver už prichádza len dvojica metód na vykreslenie textu. Pri nich podľa dĺžky vstupného stringu vykreslíme body, ktorým priradíme vlastnosti – farby písma, charakter, informácia o zmenie a prípadne aj farba pozadia.

public static void DrawString(string str, Vector2 Point, ConsoleColor fontColor)
{
    for (int i = 0; i < str.Length; i++) //Pre každý bod dĺžky textu
    {
        if ((Point.X + i >= 0) && (Point.Y >= 0) && (Point.X + i < Size.X) && (Point.Y < Size.Y)) //Overíme či sa nachádza na obrazovke
        {
            Display[Point.X + i, Point.Y].Character = str[i]; //Priradíme znak
            Display[Point.X + i, Point.Y].CharColor = fontColor; //Farbu písma
            Display[Point.X + i, Point.Y].Changed = true; //A informujeme o zmene
        }
    }
}

public static void DrawString(string str, Vector2 Point, ConsoleColor fontColor, ConsoleColor backColor)
{
    for (int i = 0; i < str.Length; i++)
    {
        if ((Point.X + i >= 0) && (Point.Y >= 0) && (Point.X + i < Size.X) && (Point.Y < Size.Y))
        {
            Display[Point.X + i, Point.Y].Character = str[i];
            Display[Point.X + i, Point.Y].CharColor = fontColor;
            Display[Point.X + i, Point.Y].CharColor = backColor; //Nastavíme farbu pozadia
            Display[Point.X + i, Point.Y].Changed = true;
        }
    }
}

Týmto sme obsiahly vykresľovanie tvarov a textu. Teraz pri triede Renderer zostáva už len posledná vec.

Vykresľovanie do konzoly

Pri vykresľovaní do konzoly budeme kopírovať obsah premennej Display na obrazovku, pričom zohľadníme zmenu pixelu.

Na začiatku zabezpečíme, aby používateľ nemohol manuálne zmeniť veľkosť okna, presunieme kurzor na ľaví horný roh a tiež ho spravíme neviditeľným. Nasledujúci kód vložíme do statickej metódy Draw.

Console.SetWindowSize(Size.X, Size.Y);
Console.CursorTop = 0;
Console.CursorLeft = 0;
Console.CursorVisible = false;

Následne prebehne vykresľovanie pixelu za pixelom. Zároveň budeme kontrolovať, či je premenná Changed nastavená na true.

for (int x = 0; x < Size.X; x++)
{
    for (int y = 0; y < Size.Y; y++)
    {
        if (Display[x, y].Changed) //Ak sa pixel zmenil
        {
            Console.BackgroundColor = Display[x, y].Color; //Nastavíme farbu popredia
            Console.ForegroundColor = Display[x, y].CharColor; //Nastavíme farbu pozadia
            Console.CursorTop = y;
            Console.CursorLeft = x; //Presunieme kurzor na pozíciu
            Console.Write(Display[x, y].Character); //A zapíšeme pixel
            Display[x, y].Changed = false; //Na záver pixelu nastavíme Changed na false
        }
    }
}

Vykresľovanie samotné prebieha konzolovou metódou Write, ktorá vypíše jeden znak. Ak je pixel prázdny, je to medzera – čiže vidno len pozadie. Nastavením hodnoty Changed zabezpečíme, aby sa pixel nemusel zbytočne vykreslovať, ak sa nezmenil.

Na koniec už len znova presunieme kurzor do ľavého horného rohu, vďaka čomu nebude blikať riadok pod hrou.

Console.CursorTop = 0;
Console.CursorLeft = 0;

Integrovanie triedy Renderer

Aby všetko bolo pripravené, musíme triedu Renderer integrovať do nášho kódu. To spravíme v triede Program, kde na začiatku metódy Main pridáme Renderer.Init(); a na koniec našej hernej slučky Renderer.Draw(); .

V triede Game môžete ešte do metódy Draw pridať Renderer.Clean(); . To je vhodné vložiť aj hneď po inicializácií rendereru v triede Program.

Teraz už môžete Renderovanie odskúšať v metóde Draw triedy Game. Nabudúce sa už pozrieme na tvorbu hada.

Pridajte Komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *

Scroll to Top