When I played Quake and Quake2, one of the 'neatest' things I saw was the console. The area where you could type commands like cheat codes. Remember? Well, I had never seen that in any game before. You just typed stuff while the game was running (e.g. DOOM) and that didn't impress me much. The idea of a console in a game interested me. I have spent a long time figuring it out and in the process have failed about 4 or 5 times. Nevertheless, I started on it again, but this time, I asked for help from the guys programming the VOID 3D Engine (Gaz and Ripper). Thanks to them, I was able to pull off this console.
In this article, I will be discussing a few methods you could use to implement your own console. At the end, I will present you with a fully working demo of a console. It is written in Visual Basic 6.0, since its string manipulation is simple, and half of the work is already done. I also chose VB for this task because I could use my previously written LibX game programming library, which would let me concentrate on the console, instead of rewriting the DirectDraw framework.
When I first started, I thought that all a console had to do was retrieve keyboard messages from the user and print them to the screen. Then, you just compare strings, right? Wrong!
When I tried to make my leap to creating the console, I encountered many annoying problems. Before we get into the problems you should consider before starting the console, I would like you to do this:
Open up the MS-DOS console in Windows, and type a few commands (even invalid commands). Notice how the DOS console responds to invalid commands by printing "Bad command or file name". Type a few copy commands to copy files from one place to another. This time, notice how the copy command accepts two "arguments" (source file and destination file). Lastly, notice that as the DOS window gets filled, the lines in the top get scrolled up and out of view. These are all things to consider, since we're trying to make a "clone" of this console in DirectDraw. Based on the observations we've done, the following could be considered problems we need to overcome:
We need a way to receive the line input the user has typed.
Since we're creating the console in DirectDraw, we also need to consider the character size, number of pixels to leave after each character, and after each line. We must also keep in mind the maximum number of characters that can fit on the screen. It might sound too much, but once we find that shortcut, we will reach home quickly. So let's get started.
Resolving the Conflicts
In the last section, we listed some of the conflicts we need to resolve before we can reach our goal. I approach the problem with the use of classes since classes can automate things. Even though C++ is somewhat easy, VB is much easier. Note that all things I did here could be done without using classes. However, I think it was simplified and cleared up when I used classes. You'll hopefully see what I mean later.
To wrap up this section--the first problem we mentioned above is going to be solved by having a class called "CLine". It contains functions for all sorts of line manipulations. The second problem will be resolved with our "CBuffer" class and the last two will be solved by our "CConsole" class.
You only need to use the CConsole class for implementing this console. CConsole uses the CBuffer and CLine classes to do its buffer manipulation. The way this console works is described here:
The programmer creates an instance of the CConsole class.
See how simple it is? It's much more simple than any one of my older approaches at least. (Special thanks to Gaz and Ripper)
Bitmapped Fonts -- Good or Bad?
Bitmapped fonts are something that can be a hassle, or something that will make your game look more attractive. Whenever you want to use bitmaps for fonts, always check to make sure you really need them. Meaning if you are looking at the fact that GDI is slow, and you need that few extra frames to increase your FPS, blitting the font from a surface is probably the best choice. However, it is worth considering that speed is not always the only issue. You might need to format your text output (like centering, italicizing, underlining, etc.) which is easier with GDI.
However most people (including myself) have some trouble using bitmapped fonts. Although there are many approaches to implement them, one method that Quake used, which changed the way I thought (creating a font editor, making my own custom font file format, etc.) was to create a font bitmap in ASCII order. Although it might seem obvious now, I had no idea that creating a font in ASCII order would be so much easier than creating a bitmap in A-Z order or keyboard order.
When you are creating a bitmapped font, always create them in ASCII order (you can look up ASCII codes in MSDN by using the keyword: "character codes"). Since the KeyPress Event (Message WM_KEYPRESS) comes with an ASCII code, you can just use this value as a base to get the position of the character you want in the bitmap file by using this formula (Special thanks to: Benjamin Marty). Excerpt 3.1 shows this:
'char_code: ASCII value of the key pressed.
'NUM_CHARS_PER_LINE: number of characters on each line
'FONT_START_Y: vertical pixel position for char's start.
'FONT_Y_SIZE: pixel size of each character's height.
'FONT_X_SIZE: pixel size of each character's width.
'FONT_BMP_WIDTH: width of the whole font bitmap file.
''Mod': VB's modulo operator (for those confused).
top = ( Int( (char_code-32) / NUM_CHARS_PER_LINE)
* FONT_Y_SIZE) + FONT_START_Y ' 32 is ASCII for space
left = (char_code * FONT_X_SIZE) Mod FONT_BMP_WIDTH
Pretty simple if you think about it, instead of hard-coding values which you may need to do over if you changed the file. If you already knew this technique, kudos to you.
In conclusion, having a console in your game is pretty handy, especially if you can't or don't want to write your own GUI. In more complex games, for example an RPG or RTS, a console might not suffice. But in a regular shoot-em up, it's usually more than enough.
If you happen to use DirectInput's exclusive level keyboard access, all you need to do is look for a key input (like DIK_ESCAPE) that will enable/disable the console. When you get this input, just un-acquire your Keyboard device until the console is deactivated (look for the same key in your KeyPress Event/WM_KEYPRESS message) this time. When you receive that message, re-acquire the Keyboard device again.
On a small note, the console I provide is by no means optimized or bug-free. It is no where near being organized and was just something I made "on the fly". The code is free to modify and distribute.
The console demo I am providing you with is fully customizable 'as-is'. All you probably need to do is just change a few constants. If you do is it, you don't have to give me any credits, royalties, or anything. If you have any comments, questions, or suggestions, don't hesitate to email me at VBDevelopr@hotmail.com.
The Console Demo
How to setup the demo to run properly: This demo uses LibX.DLL, an ActiveX DLL that requires 'registration'. First, place the LibX.DLL you receive with the ZIP in the Windows/System directory. To register properly, from the command prompt type:
regsvr32 c:\windows\system\LibX.DLLand press enter. You should receive a prompt saying whether the registration succeeded or not.
That's all for now, take care! Maybe a little DDraw GUI demo next time,