Zachary Patten
Posted on February 10, 2022
Back on Jan 28, 2020 I wrote an article, Learn C# Through Console Games.
TLDR: I have been working on a GitHub repository with open source C# console game examples aiming to help people learn C# in fun ways. :)
When I wrote that first article, the repo had 8 console game examples. As of now I have coded 27 console games, so I've added 19 in the past 2 years. I felt like writing this follow-up article so I could highlight some of those games and share some thoughts I had while coding them. :)
Keep in mind I only work on this in my spare time for fun. Most of the games in the repo took me less than 10 hours to develop, although there are a few exceptions I'll mention below.
NOTE! The mobile versions of this site don't use monospace font for code blocks, so the visual examples in this article do not render correctly on mobile. They render correctly when on a desktop browser.
Drive
Added November 2021
.............. ........................
............... .......................
................ ......................
................. .....................
.................. ....................
................... ...................
.................... ..................
.................... ..................
.................... ..................
.................... ..................
.................... ..................
.................... ..................
.................... ..................
................... ...................
.................. ....................
................. .....................
.................. ....................
................... ...................
.................... ..................
..................... .................
...................... ................
....................... ^ ...............
...................... ................
In this game, the background scrolls downwards and you try to keep your ^
car on the road with the arrow keys ↑, ←, →
.
One topic I had to overcome while making this game is that there is no built-in way to query if a key is down or not; there is no Console.IsKeyDown(ConsoleKey.LeftArrow)
method. You would have to dig into native libraries for that, which I wanted to avoid for these game examples. So, I couldn't just have the car move left while you hold down the ←
left arrow key. I had to compromise by having the arrow keys ↑, ←, →
set the velocity of the car rather than needing to be held down. Press left arrow key ←
once and it will set the velocity of the car to turn left. Now there is no need to continually query if the left arrow is down because the velocity will be constant until a different key is pressed.
The road is randomly generated. Each time the background scrolls downward it randomly generates a new row at the top. There are three types of road that it can generate:
1. straight
2. turn left
3. turn right
When I started randomly generating the road, I split it evenly and gave each possible option a 1/3 chance to be the next row. However, that usually resulted in a mostly straight road with jagged edges that wasn't very fun to play. :D
.................... ..................
................... ...................
.................... ..................
..................... .................
.................... ..................
.................... ..................
..................... .................
.................... ..................
..................... .................
..................... .................
...................... ................
..................... .................
...................... ................
....................... ^ ...............
...................... ................
How did I fix this? I added in a bias that so that when a new row is generated it has a 4/5 chance to be the same as the previously generated row. For example, this meant that once a left turn was started, it would likely continue to turn left for at least several rows. This resulted in roads that you would expect to see in a driving game with some longer turns and straightaways.
Drive
was one of the easiest games to make and turned out to be one of the most enjoyable to play in my opinion. Unlike Snake
, which starts off slow/easy and gradually gets harder, Drive
has a consistent difficulty until you make a mistake and die.
Role Playing Game
Added October 2021
╔═══════════════════════════════════════════════════════════════════════════════════════════════════╗
║ ║
║ ║
║ /---\ /---\ ║
║ /---\/-Inn-\ _._ /Store\ /---\ ║
║ /-\/-\| | |___| | | /-\/-\ ║
║ \ /\ /| █ | | █ | \ /\ / ║
║ O ║
║ L|( ║
║ | ║
║ ( \ ║
║--\ /---\ /---\ /---\ /---\ /---\ /---\ /--║
║---\ /-----\/-----\ /-----\ /-----\/-----\ /-----\ /---║
║ |#######| || |#######| | | || |#######| |#######| ║
║█ |#######| █ || █ |#######| █ | | █ || █ |#######| █ |#######| █║
║═══╗╔═════╗╔═════╗╔═════╗╔═════╗╔═════╗ |-| |-| |-| ╔═════╗╔═════╗╔═════╗╔═════╗╔═════╗╔═══║
║███║║█████║║█████║║█████║║█████║║█████║ _| |_ _| |_ _| |_ ║█████║║█████║║█████║║█████║║█████║║███║
║███║║█████║║█████║║█████║║█████║║█████║ \ / \ / \ / ║█████║║█████║║█████║║█████║║█████║║███║
║═══╝╚═════╝╚═════╝╚═════╝╚═════╝╚═════╝ \ / \ / \ / ╚═════╝╚═════╝╚═════╝╚═════╝╚═════╝╚═══║
║ ║
╚═══════════════════════════════════════════════════════════════════════════════════════════════════╝
Move: arrow keys or (w, a, s, d)
Check Status: [enter]
Quit: [escape]
This game is pretty self explanatory... It is a role playing game. When most people think of a "text based RPG" they probably think of a purely text question-and-answer type of game with stuff like Where would you like to move (n, s, e, w)?
. Although Role Playing Game
is technically a "text-based RPG", it visually represents the world with WASD movement and character animations (albeit rather simple character animations).
Role Playing Game
is currently the most complex of the games I have added to the repo. While most games took 5-10 hours to code, Role Playing Game
took 25-30 hours to code. Luckily I was able to re-use some assets from other games, such as the character running animation from Hurdles, and the punching + fall + get up + idle animations from Fighter.
One of the features I wanted to add with this game was respecting the current console size. You can resize the console window and the game will re-render itself with the character in the center of the screen. Nothing revolutionary of course :D but dynamic screen size is a little weird when you are dealing with a console/terminal application. Not sure if it was a bug, but I kept getting ArgumentOutOfRangeException
exceptions when setting the Console.BufferHeight
or Console.BufferWidth
even though my values were totally valid, so I had to wrap it in an ugly try-catch. Also, there are some differences between cmd.exe
and the VsDebugConsole.exe
(Visual Studio Debug Console). When you write to the last character in a line, they behave differently. One will write the character and stay on the same line while the other will write the character and jump to the next line, and since I was Console.WriteLine()
-ing at the end of each row, one console had blank lines while the other did not. :D But it was an easy fix once I figured out what was happening.
Even though all the graphics were made out of ascii characters, I still found it beneficial to make sprite sheets and define the maps with sprites. The game has 3 different maps: town, field, and castle. Here is what the definition of the field map currently looks like for example:
public static readonly char[][] Field = new char[][]
{
"mmmpmmmmpmmmmmpmmmmmpmmmmmpmmmpmmmpmmmpmm".ToCharArray(),
"mmpppppppmmmpppmmmpppppmmppmmmpmmmmpppmmm".ToCharArray(),
"mmpmmpmmpmppmmpmpmmpmmpmmmmmmpppmmpmpmmmp".ToCharArray(),
"TTTTTc mpmm cTT m2mcmmpp".ToCharArray(),
"TTTT mm g mmm".ToCharArray(),
"TTT TT mm mpm".ToCharArray(),
"TTT TTT mmmm TT ppm".ToCharArray(),
"www T mm TTT www".ToCharArray(),
"www TT ww T www".ToCharArray(),
"www ww TTT wwwww".ToCharArray(),
"www w0w Tww mmmmmm".ToCharArray(),
"wwww wwwwwww TT cmmmmmmmm".ToCharArray(),
"wwwwwwwwwwwwwwwwwwwwwTTTTTTTTTTTTmmmmmmmm".ToCharArray(),
"wwwwwwwwwwwwwwwwwwwwTTTTTTTTTTTTTTmmmmmmm".ToCharArray(),
"wwwwwwwwwwwwwwwwwwwTTTTTTTTTTTTTTTTmmmmmm".ToCharArray(),
};
Each of the characters is an id of a sprite. See the source code for the full list, but here are what a few of the characters represent: W
is water, m
is mountains, and T
is tree.
Wordle
Added January 2022
╔═══╦═══╦═══╦═══╦═══╗
║ H ║ O ║ U ║ S ║ E ║
╠═══╬═══╬═══╬═══╬═══╣
║ P ║ L ║ A ║ C ║ E ║
╠═══╬═══╬═══╬═══╬═══╣
║ S ║ E ║ A ║ R ║ S ║
╠═══╬═══╬═══╬═══╬═══╣
║ ║ ║ ║ ║ ║
╠═══╬═══╬═══╬═══╬═══╣
║ ║ ║ ║ ║ ║
╠═══╬═══╬═══╬═══╬═══╣
║ ║ ║ ║ ║ ║
╚═══╩═══╩═══╩═══╩═══╝
"Wordle" has gone a bit viral and is all over social media. I just wanted to mention that I hate this game. :P But I went ahead and coded it because it was too easy not to code it. :D But the game still sucks...
PacMan
Added December 2020
╔═══════════════════╦═══════════════════╗
║ · · · · · · · · · ║ · · · · · · · · · ║
║ · ╔═╗ · ╔═════╗ · ║ · ╔═════╗ · ╔═╗ · ║
║ + ╚═╝ · ╚═════╝ · ╨ · ╚═════╝ · ╚═╝ + ║
║ · · · · · · · · · · · · · · · · · · · ║
║ · ═══ · ╥ · ══════╦══════ · ╥ · ═══ · ║
║ · · · · ║ · · · · ║ · · · · ║ · · · · ║
╚═════╗ · ╠══════ ╨ ══════╣ · ╔═════╝
║ · ║ ║ · ║
══════╝ · ╨ ╔════---════╗ ╨ · ╚══════
· ║ █ █ █ █ ║ ·
══════╗ · ╥ ║ ║ ╥ · ╔══════
║ · ║ ╚═══════════╝ ║ · ║
║ · ║ READY ║ · ║
╔═════╝ · ╨ ══════╦══════ ╨ · ╚═════╗
║ · · · · · · · · · ║ · · · · · · · · · ║
║ · ══╗ · ═══════ · ╨ · ═══════ · ╔══ · ║
║ + · ║ · · · · · · █ · · · · · · ║ · + ║
╠══ · ╨ · ╥ · ══════╦══════ · ╥ · ╨ · ══╣
║ · · · · ║ · · · · ║ · · · · ║ · · · · ║
║ · ══════╩══════ · ╨ · ══════╩══════ · ║
║ · · · · · · · · · · · · · · · · · · · ║
╚═══════════════════════════════════════╝
PacMan
is... a PacMan clone in the console. Get the dots. Dodge the ghosts. It's not intended to be very faithful though. I didn't research the AI of the ghost, I just came up with my own AIs that worked. Here is what I did for the ghost AIs:
- Ghost a: follows you via Dijkstra Path Finding and updates every 6 frames (faster)
- Ghost b: randomly moves and updates every 6 frames (faster)
- Ghost c: follows you via Dijkstra Path Finding and updates every 12 frames (slower)
- Ghost d: randomly moves and updates every 12 frames (slower)
Note: for this game I pulled in a reference to my nuget package Towel because it includes generic versions of the Dijkstra Path Finding algorithm.
Out of all the games, this is the only one that really needs color. All the other games could likely be pretty easily made to not rely on color, but without different colors in Pac Man, you wouldn't be able to distinguish the ghosts or Pac Man, and we also need the ghosts to turn blue when Pac Man eats one of the +
bigger dots. The ConsoleColor
enum only has 16 different colors, but luckily I've been able to make everything work so far with that very limited palette. Yes there are ways to render more colors in the console, but these are intended to be relatively simple examples for newer developers, so I don't want to overcomplicate things if I can make due with just ConsoleColor
.
PacMan
, like Role Playing Game
, took a bit longer than most of the other games to develop. I can't remember exactly how long it took to code, but a good guess is that it took me ~20 hours to code. I've never actually been a fan of Pac Man, so it wasn't all that fun to make for me. :D But... I like a challenge so I did it anyway.
Mancala
Added February 2022
╔══════════════════════════════════╗
║ | |[ 8][ 0][ 1][ 0][ 6][ 7]| | ║
║ | | | | ║
║ | 3| | 4| ║
║ | | \/ | | ║
║ | |[ 7][ 1][ 0][ 7][ 2][ 2]| | ║
╚══════════════════════════════════╝
Mancala
is currently the newest game in the repo. It was a suggestion from a user on the C# Discord Server. I had never played Mancala before coding this game, so if anyone is a Mancala expert and finds a bug in my code, please let me know. :D
Mancala
was a funny game to code, because the game itself is extremely simple, but I found visually representing it in the console harder than it would seem. When you make a move, you pick up seeds and move in a counter-clockwise motion putting a seed in each pit along the way. How do you represent that in the console? I started to make a little counter clock-wise animation, but quickly found myself thinking, "This animation is not going to help anyone learn how to play Mancala." :D So instead of trying to have some fancy animation, I just show the +X
and -X
of each pit and store after a move is processed:
╔══════════════════════════════════╗
║ | |[ 4][ 4][ 4][ 4][ 4][ 4]| | ║
║ | | | | ║
║ | 0| +1| 1| ║
║ | | -4 +1 +1 +1 | | ║
║ | |[ 4][ 4][ 0][ 5][ 5][ 5]| | ║
╚══════════════════════════════════╝
I thought that would be the best way to convey what happened to the user. But it still isn't great, and I assume Mancala
is probably the most confusing game to play in the entire repo unless you are already familiar with Mancala.
Fighter
Added February 2020
HP █████ ███████████ HP
EN ███████ ███ EN
o
O___. _>)
L( \|
| |
/ >
=================================
I'd never seen a 2D fighter game in the console, so I decided to make this game to try to push myself to see if it was possible. Is it good? Nope. :D But... hey... it works. So, can you make a 2D fighting game in the console? Yes! Yes you can!
As of writing this article, Fighter
definitely has the worst code quality of all the games. There is spaghetti code and magic numbers . :P You are welcome. Maybe someday I'll clean up the code and improve the game a bit. But the goal isn't to make AAA games here, this is the console/terminal after all.
Sudoku
Added August 2020
╔═══════╦═══════╦═══════╗
║ 7 6 2 ║ 9 1 5 ║ 8 4 3 ║
║ 5 4 3 ║ 7 8 6 ║ 2 1 9 ║
║ 9 1 8 ║ 2 3 4 ║ 5 7 6 ║
╠═══════╬═══════╬═══════╣
║ 4 3 1 ║ 5 9 8 ║ 7 6 2 ║
║ 6 2 5 ║ 4 7 3 ║ 1 9 8 ║
║ 8 7 9 ║ 1 6 2 ║ 3 5 4 ║
╠═══════╬═══════╬═══════╣
║ 3 9 6 ║ 8 5 1 ║ 4 2 7 ║
║ 1 8 4 ║ 6 2 7 ║ 9 3 5 ║
║ 2 5 7 ║ 3 4 9 ║ 6 8 1 ║
╚═══════╩═══════╩═══════╝
Pretty much exactly what you would expect... Sudoku in the console....
Conclusion
If anything here caught your interest, or if you know someone who is looking for fun beginner C# projects, I encourage you to check out the repo where all the games are open source: https://github.com/ZacharyPatten/dotnet-console-games. My general recommendation is for beginners to play the games, find one they like, then try to code it from scratch; if you get stuck you have the working example to refer to.
I would also gladly accept contributions if you make a console game of your own and would be willing to add it to the repo. Or if you have an idea of a game you would like to see in the console, feel free to comment below or open a discussion on the GitHub repo. :)
How many more console game will I make? No idea. :P But I have several ideas, so you can expect to see more in the future.
Thank you for reading. Have a great day!
Posted on February 10, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.