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.
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.