Register
Hello There, Guest!


Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Retro-ish project: Tetris in the command line
#1
So, last Monday I started a little game project as an excuse to experiment with my ConsolePaint library for .Net, but also as an exercise for a much more ambitious project later (which will be fully retro). For this occasion, I thought I'd replicate one of my favourite games of the NES; Tetris, but with a twist; the user should be able to create his own difficulty by directly modifying drop delays, game execution speed and the rate at which the game becomes faster (and thus, more challenging).

There are a couple of challenges in doing a game in the console terminal:
  • Printing characters to the console window is slow.
  • Refreshing the screen is even slower and just printing the characters on new lines wouldn't entirely sell the illusion of a piece moving.
  • You can only use characters when using the terminal, so no graphics (duh!)
  • In this case, the "user interface" needs to be user friendly enough so that anyone can play and alter the game variables without having to remember the command names.
  • There needs to be some kind of sound for tetrises and background music.

I couldn't really solve the first problem since .Net doesn't have any way to hijack the console screen buffer like in C++ with windows.h, so I ended up trying to minimize as much as possible calls to Write and WriteLine by only writing and rewriting in precise areas of the screen by repositioning the cursor. Because some areas of the screen are only drawn once or occasionally, it saved some execution time. This did more to solve the second problem than the first one actually, since it entirely got rid of the slow refresh problem you'd get with the Clear method.

First shot shows the areas where the characters are only printed once on the screen. Second shot shows areas which are only reprinted when the information needs to be updated.
[Image: 899920200_drawnonce.png.318dd80ec0b321b7...3d118e.png][Image: 1811272452_drawnoccasionally.png.a81fc7c...dd6e1e.png]

So the thing with Tetris is that the game is basically just squares on a screen. You don't need to be particularly fancy with the graphic design and people know this (except maybe the folks who made Tetris Effect haha). However, I still wanted to use the most out of the character set to make it as pleasant to the eye as possible. This is where the lack of graphics really hurts because the .Net console only supports 16 colours and a limited set of characters. I did notice also that the pieces in classic nes Tetris actually don't always use the same palette and appearance, so I at least wanted to include alternating colours and use fun characters as alternative tetromino blocks. However, after I started showing pictures on a few discord groups and to friends, all were unanimous that the special characters HAD to go and at least half of them found the colours jarring and too much to process. That made me sad because I really liked the fun character set and I sincerely thought the colours made the experience better. But I aim to please everyone, including I. So what I ended up doing is making those things optional; they can be turned on and off in the game settings.

The above screenshot shows a game where the special characters are disabled with colour enabled, this one below is the reverse. These options are not mutually exclusive by the way; you can have grey bland tetrominos or colourful tetrominos using the fun characters.
[Image: 472755253_optionalfancy.png.342c50341f15...783a94.png]

"The fool did not see that he was not Tetris ready. He was severely disappointed!"


Now, there remains the case of the GUI. If I was going to write code for something which wouldn't make people flee, it would take a while. Remember earlier when I wrote that I was looking for an excuse to use my ConsolePaint library? Well, I put it to good use. All these rectangles on the screen were "drawn" by it, I just called the right methods and it wasn't even something I had to worry about. The library can draw all sorts of different borders too and initially I tried a more varied design until I ended up with what we have now. I also used that library to draw a picture on the screen so that the main menu didn't look too empty. What I did first was to draw some quick pixel "art". The colours of the image were converted to the 16 colour palette of the .Net console and then the pixels were converted to characters. Although in this case, the conversion was probably not needed. The image I drew: [Image: image.png.391a72cb7c5073866c0617180ed31e04.png]
The result:

[Image: tetris_main.png.fc2ede6a73d1513e478885b3f3c0c854.png]
You may be surprised to see that I named my Tetris clone "Retro Tetro Pro". That's actually because the name Tetris is trademarked. Maybe I'm being overly cautious, but I want no trouble for a game which only a few number of people are going to play.

I'm not going to talk to much about the user friendliness of the GUI, I think navigating the menus with the arrow keys and pressing enter is a pretty obvious design choice. However it may or may not surprise you to learn that I didn't use a switch statement or if statement for handling user choices in the menu. That would have been too long and tedious! Instead I chose to put some actions in an array and the arrow keys actually increase or decrease an index which is used to call those actions. I wish I had thought of that before. Strictly speaking of design though, the only thing I consciously thought about for more than one second is how to give an obvious visual cue that a value is being increased or decreased. I chose to print a green upward triangle when the user is increasing a value and red downward triangle when the user is decreasing the value. You can see more of the GUI and the effects the options have on the game in this little demonstration video:
https://www.youtube.com/watch?v=MuE_L0-kAlI

Those who went ahead and watched the video will notice that the game only plays a sound when its in the menu... That's actually a reflection of the how bad it is to use sounds in .Net. There was nothing I could do to really play music or fun sounds without it being a huge pain in the neck. I tried several solutions and ways to circumvent the problem, but the tools .Net comes with are insufficient for a pleasant experience. I figure if I have enough time and motivation in the future that I'll have to use a custom sound library with .Net bindings; Beeps are too annoying and trial-and-error based to be practical and the SoundPlayer is incredibly frustrating; it has its own little thread and it does its own little thing, so no way to directly interact with it or do "complex" algorithms like having a playlist of music or playing consecutive sounds. It plays the tune until its over or until the process is dead and sometimes its stop method inexplicably doesn't work. Also there's no way to tell when the SoundPlayer is done... not mentioning several limitations like being limited to playing wav files out of anything. At this point, I was a bit tired of working on this project and anyways, to me, one of the rare people on earth who does not enjoy music due to a medical condition, it was the least of my priorities.

Thus, I felt it was a job well done and decided to release the game to a slightly wider audience with the bugged music player (I ended up removing the music altogether in the new version because the obsolete wav files made the download too large). I haven't gotten a lot of feedback yet because well... it's a Tetris clone. Everyone and their grandmother has both played and made it before. So I can't tell you if it was a success from the point of view of others. But I can tell you I'm satisfied with what I came up with despite the fact that I wasn't able to solve every issue I had. I learned a lot of things by putting myself to the challenge of making it work in the terminal window and it was a pretty interesting experience which I don't regret.

Thank you for reading this post. And if you try Tetro Retro Pro, thank you once more, it makes me incredibly happy that it will not all be merely for showing off and experimenting. You can download the game here. Arrow keys to move and z to rotate.

Edit: New release. Added controls information to the menu, added a jingle for a quadruple line clear and added the pause functionality.
[-] The following 5 users Like Doigt's post:
  • nachochesse, QueenHeather, Shade1453, Sora, Squirrel
Reply
#2
(09-16-2020, 02:41 AM)Doigt Wrote:
So, last Monday I started a little game project as an excuse to experiment with my ConsolePaint library for .Net, but also as an exercise for a much more ambitious project later (which will be fully retro). For this occasion, I thought I'd replicate one of my favourite games of the NES; Tetris, but with a twist; the user should be able to create his own difficulty by directly modifying drop delays, game execution speed and the rate at which the game becomes faster (and thus, more challenging).

There are a couple of challenges in doing a game in the console terminal:
  • Printing characters to the console window is slow.
  • Refreshing the screen is even slower and just printing the characters on new lines wouldn't entirely sell the illusion of a piece moving.
  • You can only use characters when using the terminal, so no graphics (duh!)
  • In this case, the "user interface" needs to be user friendly enough so that anyone can play and alter the game variables without having to remember the command names.
  • There needs to be some kind of sound for tetrises and background music.

Nice to see that your creative juices are alive and well, and your brain continues to come up with new things for yuo to try!

When reading about the screen refresh, it made me laugh, because as a 17 yr old kid full of hope, and an Apple ][+ in front of me (no, not a Mac -- what they had before the Mac existed). I figured that merely having learned how to program in machine language would have been enough, and after my code was complete and ready for testing I was horrified how slowly it was redrawing!  It was like looking at a game played with a 300 baud modem, it was so slow. 300 bits/second was 300/9 (8 bits data plus a framing bit) or 33 characters per second, when everything was text and a single line had a maximum of 80 characters. So 2 seconds per line. It was so maddeningly slow, that after I showed the rest of the crew I'd assembled to work on this D&D-like game my mind had hatched up, we instantly knew it would never happen.

All the big gaming houses knew of these heartaches too, and the importance of a graphics engine written in assembly language that would  wrest every last bit of ability out of the machine given it's processor and environment.

After that, my machine language skills only got used for writing modem drivers, and reverse-engineering games to add cheats, and so on. (lol)


Good luck on this new project!

May it bring you pleasure, and may you be inspired to work on it enough to be proud of what you achieve with it!
Fight the Good Fight
(Listen with lyrics here!)
Make it worth the price we pay!
All your life you've been waiting for your chance,
Pray you'll fit into the Plan.
But you're the master of your own destiny,
So give and take the best that you can!
Reply
#3
I don't know if you didn't see the rest of that wall of text of mine but the project IS done. Thanks anyway.
Reply
#4
(09-16-2020, 05:41 PM)Doigt Wrote: I don't know if you didn't see the rest of that wall of text of mine but the project IS done. Thanks anyway.

O cool congrats bro!!
Hello there! I am Hitu. Nice to meet you! If you any questions about me or Agma.io private message me!  Btw I am youtuber make sure to subscribe to my channel- Hitu agma
Reply
#5
(09-16-2020, 02:41 AM)Doigt Wrote:
So, last Monday I started a little game project as an excuse to experiment with my ConsolePaint library for .Net, but also as an exercise for a much more ambitious project later (which will be fully retro). For this occasion, I thought I'd replicate one of my favourite games of the NES; Tetris, but with a twist; the user should be able to create his own difficulty by directly modifying drop delays, game execution speed and the rate at which the game becomes faster (and thus, more challenging).

There are a couple of challenges in doing a game in the console terminal:
  • Printing characters to the console window is slow.
  • Refreshing the screen is even slower and just printing the characters on new lines wouldn't entirely sell the illusion of a piece moving.
  • You can only use characters when using the terminal, so no graphics (duh!)
  • In this case, the "user interface" needs to be user friendly enough so that anyone can play and alter the game variables without having to remember the command names.
  • There needs to be some kind of sound for tetrises and background music.

I couldn't really solve the first problem since .Net doesn't have any way to hijack the console screen buffer like in C++ with windows.h, so I ended up trying to minimize as much as possible calls to Write and WriteLine by only writing and rewriting in precise areas of the screen by repositioning the cursor. Because some areas of the screen are only drawn once or occasionally, it saved some execution time. This did more to solve the second problem than the first one actually, since it entirely got rid of the slow refresh problem you'd get with the Clear method.

First shot shows the areas where the characters are only printed once on the screen. Second shot shows areas which are only reprinted when the information needs to be updated.
[Image: 899920200_drawnonce.png.318dd80ec0b321b7...3d118e.png][Image: 1811272452_drawnoccasionally.png.a81fc7c...dd6e1e.png]

So the thing with Tetris is that the game is basically just squares on a screen. You don't need to be particularly fancy with the graphic design and people know this (except maybe the folks who made Tetris Effect haha). However, I still wanted to use the most out of the character set to make it as pleasant to the eye as possible. This is where the lack of graphics really hurts because the .Net console only supports 16 colours and a limited set of characters. I did notice also that the pieces in classic nes Tetris actually don't always use the same palette and appearance, so I at least wanted to include alternating colours and use fun characters as alternative tetromino blocks. However, after I started showing pictures on a few discord groups and to friends, all were unanimous that the special characters HAD to go and at least half of them found the colours jarring and too much to process. That made me sad because I really liked the fun character set and I sincerely thought the colours made the experience better. But I aim to please everyone, including I. So what I ended up doing is making those things optional; they can be turned on and off in the game settings.

The above screenshot shows a game where the special characters are disabled with colour enabled, this one below is the reverse. These options are not mutually exclusive by the way; you can have grey bland tetrominos or colourful tetrominos using the fun characters.
[Image: 472755253_optionalfancy.png.342c50341f15...783a94.png]

"The fool did not see that he was not Tetris ready. He was severely disappointed!"


Now, there remains the case of the GUI. If I was going to write code for something which wouldn't make people flee, it would take a while. Remember earlier when I wrote that I was looking for an excuse to use my ConsolePaint library? Well, I put it to good use. All these rectangles on the screen were "drawn" by it, I just called the right methods and it wasn't even something I had to worry about. The library can draw all sorts of different borders too and initially I tried a more varied design until I ended up with what we have now. I also used that library to draw a picture on the screen so that the main menu didn't look too empty. What I did first was to draw some quick pixel "art". The colours of the image were converted to the 16 colour palette of the .Net console and then the pixels were converted to characters. Although in this case, the conversion was probably not needed. The image I drew: [Image: image.png.391a72cb7c5073866c0617180ed31e04.png]
The result:

[Image: tetris_main.png.fc2ede6a73d1513e478885b3f3c0c854.png]
You may be surprised to see that I named my Tetris clone "Retro Tetro Pro". That's actually because the name Tetris is trademarked. Maybe I'm being overly cautious, but I want no trouble for a game which only a few number of people are going to play.

I'm not going to talk to much about the user friendliness of the GUI, I think navigating the menus with the arrow keys and pressing enter is a pretty obvious design choice. However it may or may not surprise you to learn that I didn't use a switch statement or if statement for handling user choices in the menu. That would have been too long and tedious! Instead I chose to put some actions in an array and the arrow keys actually increase or decrease an index which is used to call those actions. I wish I had thought of that before. Strictly speaking of design though, the only thing I consciously thought about for more than one second is how to give an obvious visual cue that a value is being increased or decreased. I chose to print a green upward triangle when the user is increasing a value and red downward triangle when the user is decreasing the value. You can see more of the GUI and the effects the options have on the game in this little demonstration video:
https://www.youtube.com/watch?v=MuE_L0-kAlI

Those who went ahead and watched the video will notice that the game only plays a sound when its in the menu... That's actually a reflection of the how bad it is to use sounds in .Net. There was nothing I could do to really play music or fun sounds without it being a huge pain in the neck. I tried several solutions and ways to circumvent the problem, but the tools .Net comes with are insufficient for a pleasant experience. I figure if I have enough time and motivation in the future that I'll have to use a custom sound library with .Net bindings; Beeps are too annoying and trial-and-error based to be practical and the SoundPlayer is incredibly frustrating; it has its own little thread and it does its own little thing, so no way to directly interact with it or do "complex" algorithms like having a playlist of music or playing consecutive sounds. It plays the tune until its over or until the process is dead and sometimes its stop method inexplicably doesn't work. Also there's no way to tell when the SoundPlayer is done... not mentioning several limitations like being limited to playing wav files out of anything. At this point, I was a bit tired of working on this project and anyways, to me, one of the rare people on earth who does not enjoy music due to a medical condition, it was the least of my priorities.

Thus, I felt it was a job well done and decided to release the game to a slightly wider audience with the bugged music player (I ended up removing the music altogether in the new version because the obsolete wav files made the download too large). I haven't gotten a lot of feedback yet because well... it's a Tetris clone. Everyone and their grandmother has both played and made it before. So I can't tell you if it was a success from the point of view of others. But I can tell you I'm satisfied with what I came up with despite the fact that I wasn't able to solve every issue I had. I learned a lot of things by putting myself to the challenge of making it work in the terminal window and it was a pretty interesting experience which I don't regret.

Thank you for reading this post. And if you try Tetro Retro Pro, thank you once more, it makes me incredibly happy that it will not all be merely for showing off and experimenting. You can download the game here. Arrow keys to move and z to rotate.

Wow nice to see someone making a game, you need many time and dont be stressed too jeje, i want to play it in the future, i hope you can release the game soon, show your effort and make people enjoy your game Smile


Good job!
I love games, be responsible and be helpful.
Also i love pizza ✨
Reply
#6
Thank you, you may not have noticed it but I did say that I released it. I even included a download link in both the video description and the end of the post. Something is telling me people are not reading my post... you're the second one to think this thing is not released yet even though it absolutely is.

Let me repeat just to be clear: This is a report about a project which is done, finished, in a state of completion which satisfies the one in charge of it. It is released to the public. There are download links to try it. It is not a project I'm currently working on anymore.
[-] The following 1 user Likes Doigt's post:
  • QueenHeather
Reply
#7
(09-16-2020, 10:30 PM):)Doigt Wrote: Thank you, you may not have noticed it but I did say that I released it. I even included a download link in both the video description and the end of the post. Something is telling me people are not reading my post... you're the second one to think this thing is not released yet even though it absolutely is.

Let me repeat just to be clear: This is a report about a project which is done, finished, in a state of completion which satisfies the one in charge of it. It is released to the public. There are download links to try it. It is not a project I'm currently working on anymore.

This reminds me of what I just learned about with emails in Professional Communications, and it might work for your future posts! The assignment was talking about how people tend to skim through emails and try to find the key points, basically because of tl;dr. 
They recommended starting with a greeting, then a summary of what the email is about, then key points, starting with the most important point first. In the case of this thread, it was more like reading a story. Tongue I personally don’t mind it, but it might help grab people’s attention more if you start with the basic meaning behind the post, which in this case is “new game released!” Then follow with the story behind it  Smile
Have any questions? Feel free to send me a private message! 

Please remember, I’m only a forums moderator. Not in Agma!  Heart
Reply
#8
(09-16-2020, 10:30 PM)Doigt Wrote: Thank you, you may not have noticed it but I did say that I released it. I even included a download link in both the video description and the end of the post. Something is telling me people are not reading my post... you're the second one to think this thing is not released yet even though it absolutely is.

Let me repeat just to be clear: This is a report about a project which is done, finished, in a state of completion which satisfies the one in charge of it. It is released to the public. There are download links to try it. It is not a project I'm currently working on anymore.

Doh!  lol, sorry! I was in a hurry and was kind of skimming, but not very well, it seems. I didn't notice that the 'here' was clickable!

I'm more used to you introducing us to new projects, and not stuff that you've already finished! Sorry that I didn't notice, you'd already completed this one!
Fight the Good Fight
(Listen with lyrics here!)
Make it worth the price we pay!
All your life you've been waiting for your chance,
Pray you'll fit into the Plan.
But you're the master of your own destiny,
So give and take the best that you can!
Reply
#9
That's pritty cool
[Image: cebfaff72909ff0f894534bd405c8455.jpg]
Reply
#10
Printing characters to the console window is slow.
Refreshing the screen is even slower and just printing the characters on new lines wouldn't entirely sell the illusion of a piece moving.
You can only use characters when using the terminal, so no graphics (duh!)
In this case, the "user interface" needs to be user friendly enough so that anyone can play and alter the game variables without having to remember the command names.
There needs to be some kind of sound for tetrises and background music.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)