Jednoduchá hra v konzolové aplikaci

V rámci výuky matic (2D polí) v konzolové aplikaci jsem zkusil vytvořit trochu zábavnější příklad - jednoduchou hru (chodičku). Hráč se pohybuje pomocí šipek po celé ploše konzole a sbírá znaky rozmístěné po její ploše. Některé mu body přidají, jiné uberou - čím víc bodů získá, tím samozřejmě lépe. 

 

Hra v konzolové aplikaci 

Veškerý kód bude zapsán přímo v hlavní metodě Main v tom pořadí, v jakém zde bude uveden. Výjimkou je pouze deklarace objektu random a pomocná metoda VykresliHrace, proto jimi raději začnu.

private static Random random = new Random();

A nyní pomocná metoda, která vykreslí hráče na zadaných souřadnicích a vypíše doprava dolů aktuální počet získaných bodů. Pokud jsou zadány i nepovinné parametry oldX a oldY, pak na tuto pozici vykreslí znak z mapy (mezeru), což bude používáno pro překreslení hráče na staré pozici, ze které před tím vyšel.

static void VykresliHrace(ref char[,] mapa, int x, int y, int body, int oldX = -1, int oldY = -1)
{
    // Na starou pozici hráče vypsat mezeru (znak z mapy)
    if (oldX >= 0 && oldY >= 0)
    {
        Console.SetCursorPosition(oldX, oldY);
        Console.Write(mapa[oldX, oldY]);
    }
    // Vykreslení hráče na nové pozici
    Console.SetCursorPosition(x, y);
    Console.BackgroundColor = ConsoleColor.Green;
    Console.Write("X");
    Console.BackgroundColor = ConsoleColor.Black;
            
    // Vypsání Score doprava dolů
    string bodu = "    Bodů: " + body.ToString("N0");
    Console.SetCursorPosition(mapa.GetLength(0) - bodu.Length - 5, mapa.GetLength(1));
    Console.Write(bodu);
}

V hlavním kódu pak nejprve vygenerujeme herní mapu. Pro její uchování v paměti použijeme dvourozměrné pole (array) znaků (char). Rozměry této mapy by měly odpovídat rozměrům konzolového okna, což je 80x25. Poslední řádek necháme pro výpis bodů. Do každé buňky pole (člena matice) pak vložíme náhodný znak z možností + (plus, přičte bod) nebo - (mínus, odečte bod), v poměru 3:2 pro plus. Aby hra byla zajímavější, do mapy se pak ještě náhodně rozmístí 5x znak / (děleno, vydělí počet bodů dvěma) a 3x znak * (krát, zdvojnásobí počet bodů).

// Vegenerování mapy
int w = 80, h = 24; // Rozměry mapy odpovídají konzoli
char[,] mapa = new char[w, h]; // 2D pole znaků
// Vyplnění pole znaky + a - v poměru 3:2 pro plus
for (int i = 0; i < h; i++)
    for (int j = 0; j < w; j++)
        mapa[j, i] = "-+-++"[random.Next(0,5)];
for (int i = 0; i < 5; i++) // Umístit 5x /
    mapa[random.Next(w), random.Next(h)] = '/';
for (int i = 0; i < 3; i++) // Umístit 3x *
    mapa[random.Next(w), random.Next(h)] = '*';

 V dalším kroku náhodně určíme výchozí pozici hráče a na jeho pozici vymažeme znak z mapy.

// Výchozí pozice hráče a body
int x = random.Next(w), y = random.Next(h), body = 0;
mapa[x, y] = ' '; // Na této pozici (pod ním) nic nebude (bude tam mezera)

Po té již můžeme vykreslit mapu, resp. vypsat znaky na jejich pozice. Pro projití pole jsou tedy použity dva standardní do sebe vnořené for-cykly a plánek je vykreslován znak po znaku. Zalamování řádků na konci není třeba, jelikož rozměr pole přesně odpovídá rozměrům konzolového okna a text je tak zalomen automaticky. Kdyby byl plánek menší (užší) bylo by třeba ještě po projití celého řádku použít příkaz Console.WriteLine();. Po mapě je vykreslen i hráč prostřednictvím metody VykresliHrace.

// Vykreslení scény (mapy)
Console.Clear();
for (int i = 0; i < h; i++)
    for (int j = 0; j < w; j++)
        Console.Write(mapa[j, i]);
VykresliHrace(ref mapa, x, y, body);

Následující část v cyklu zachytává stisknutou klávesu, dokud touto klávesou nebude Esc (tím dojde k vypnutí hry). Pokud ovšem stisknutou klávesou bude jedna ze šipek, pak dojde k posunu souřadnic hráče daným směrem. Na jeho nové pozici se zjistí, jaký znak tam je a podle toho se přepočítá získaný počet bodů. Tento znak je následně z mapy vymazán a hráč vykreslen na své nové pozici (a vymazán - přepsán mezerou - na pozici staré). Následně hra čeká na stisk další klávesy a celý cyklus se opakuje (až do stisku Esc).

// Pohyb
var key = Console.ReadKey(); // Čeká na stisk klávesy
while (key.Key != ConsoleKey.Escape) // Esc = konec
{
    // Uložení staré pozice
    int oldX = x, oldY = y;
    // Posun
    switch (key.Key)
    {
        case ConsoleKey.DownArrow:  if (y < h-1) y++; break;
        case ConsoleKey.UpArrow:    if (y > 0)   y--; break;
        case ConsoleKey.LeftArrow:  if (x > 0)   x--; break;
        case ConsoleKey.RightArrow: if (x < w-1) x++; break;
        default: break;
    }
    // Započtení bodů za sebrání předmětu na nové pozici
    switch (mapa[x, y])
    {
        case '+': body++; break;    // +1 bod
        case '-': body--; break;    // -1 bod
        case '*': body *= 2; break; // zdvojnásobení bodů
        case '/': body /= 2; break; // polovina bodů
        default:
            break;
    }
    mapa[x, y] = ' '; // Vymazání předmětu z mapy
    // Vykreslení hráče na nové pozici
    VykresliHrace(ref mapa, x, y, body, oldX, oldY);
    // Čekání na stisk nové klávesy
    key = Console.ReadKey();
}

Tato hra je velmi jednoduchá, jak graficky, tak i funkčně. Aby k něčemu byla, chtělo by to do ní zapracovat ještě její zakončení, nejlépe po sebrání všech znaků na obrazovce a ukládání bodů do nějakého skóre přehledu.

Hra nicméně ukazuje, že konzolovou aplikaci lze použít také jinak. Jelikož jsem s programováním začínal v DOSovém Pascalu, tak mé první hry byly právě v textovém módu konzolové aplikace. Příkladem budiž hra Mise 01 z roku 1996 (8. třída ZŠ), první toť variace na současnou hru Mission game.

Hra Mise 01

 

on 03 březen 2014