Wednesday, November 16, 2011

Windows Console Game: Setting up the Window

Have you ever seen cool looking games made with purely ASCII graphics? For example the image on the right is an amazing mock-up of an idea for a game that seems to revolve around creating some sort of city on a platform to defend from air-based attackers. I've done a bit of research, and have actually begun a project of creating an entire game from scratch by using the Windows Console as the platform. This is a great way for newer programmers to jump into game development for the following reasons:
  • Easy construction of graphics. All the graphics are just ASCII characters with varying colors!
  • Very little overhead required to get a project up and running. The Windows Console is a very simple platform to get started on.
  • All the documentation you would ever need can be found on MSDN and abroad.
  • The Windows Console is packaged with every version of the Windows OS that is popular today, so no extra anything is needed to be downloaded or installed in order to get coding.


This post is the first in a series that will show you some techniques that will allow you to create a game within the Windows Console. MSDN Documentation at this link contains all the info of all the documented functions available to manipulate the windows console programmatically. Most info in this post will be an explanation of the MSDN documentation with example code on how to use it. On the left is a screenshot from a game I'm developing called TerraNisi, which revolves around a walking tree character that has a goal of saving his Forest from spreading fire ghouls!

The first thing you need to do is set up handles for your window. The handles of a window are what the Windows OS use to identify and manipulate a window. A handle datatype looks like this: HANDLE. This type is defined within windows.h with a typedef, and thus you can declare variables of the HANDLE type once you include windows.h to your project. Once we set them up we have access to manipulate our own window! Observe the following code that simply sets up handles, and calls getchar in order to pause the program once opened so you can see the window:

#include <windows.h> /* for HANDLE type, and console functions */
#include <stdio.h> /* standard input/output */

HANDLE wHnd; /* write (output) handle */
HANDLE rHnd; /* read (input handle */

int main(void)
{
  /* initialize handles */
  wHnd = GetStdHandle(STD_OUTPUT_HANDLE);
  rHnd = GetStdHandle(STD_INPUT_HANDLE);
  getchar();
}

This code doesn't do much but set up and initialize some handles for our window. Lets set the text title for the window, as this is the simplest thing I know how to do with console functions:

#include <windows.h> /* for HANDLE type, and console functions */
#include <stdio.h> /* standard input/output */

HANDLE wHnd; /* write (output) handle */
HANDLE rHnd; /* read (input handle */

int main(void)
{
  /* initialize handles */
  wHnd = GetStdHandle(STD_OUTPUT_HANDLE);
  rHnd = GetStdHandle(STD_INPUT_HANDLE);
 
  SetConsoleTitle("Our shiny new title!");
 
  getchar();
}

Now the title of your window should say "Our shiny new title!". Congrats! You've used another console function called SetConsoleTitle! Moving on to something a little more difficult, lets try using SetConsoleWindowInfo.
  • This function takes three parameters: the first is the output handle the screen's buffer
  • The second is a boolean - if this parameter is TRUE the coordinates specify the new upper-left and lower-right corners of the window. If it is FALSE, the coordinates are relative to the current window-corner coordinates. TRUE and FALSE are defined within windows.h as 1 and 0, and if you don't understand the previous sentence I suggest just leaving this parameter as TRUE.
  • The third parameter is a SMALL_RECT structure containing the size of the new window. This parameter will set the window's edges to a size smaller than the screen's buffer. This means you cannot make it larger than the default buffer size of 80x300 (width x height) until you change the buffer size, which I'll cover momentarily.
Observe:

#include <windows.h> /* for HANDLE type, and console functions */
#include <stdio.h> /* standard input/output */

HANDLE wHnd; /* write (output) handle */
HANDLE rHnd; /* read (input handle */

int main(void)
{
  /* Window size coordinates, be sure to start index at zero! */
  SMALL_RECT windowSize = {0, 0, 69, 34};
 
  /* initialize handles */
  wHnd = GetStdHandle(STD_OUTPUT_HANDLE);
  rHnd = GetStdHandle(STD_INPUT_HANDLE);
 
  /* Set the console's title */
  SetConsoleTitle("Our shiny new title!");
 
  /* Set the window size */
  SetConsoleWindowInfo(wHnd, TRUE, &windowSize);
 
  getchar();
}

I chose to set the window size to 70 by 35, which is a decent size for some sort of game. Now you have successfully changed your window size! However you should immediately notice an ugly scroll bar on the right side of your console, and at the bottom of the console. This scroll bar is there because the console's screen buffer (the inside of the window) is larger than the window. To remedy this simply change the size of the screen buffer to that of your window coordinates with the SetConsoleScreenBufferSize function. This function has only two parameters: the output handle and COORD struct for the buffer size. Observe:

#include <windows.h> /* for HANDLE type, and console functions */
#include <stdio.h> /* standard input/output */

HANDLE wHnd; /* write (output) handle */
HANDLE rHnd; /* read (input handle */

int main(void)
{
  /* Window size coordinates, be sure to start index at zero! */
  SMALL_RECT windowSize = {0, 0, 69, 34};

  /* A COORD struct for specificying the console's screen buffer dimensions */
  COORD bufferSize = {70, 35};

  /* initialize handles */
  wHnd = GetStdHandle(STD_OUTPUT_HANDLE);
  rHnd = GetStdHandle(STD_INPUT_HANDLE);

  /* Set the console's title */
  SetConsoleTitle("Our shiny new title!");

  /* Set the window size */
  SetConsoleWindowInfo(wHnd, TRUE, &windowSize);

  /* Set the screen's buffer size */
  SetConsoleScreenBufferSize(wHnd, bufferSize);

  getchar();
}

Thus far we have created the initialization of a nice console window! The next step is to begin writing things onto the console with a double buffering system! This may sound fancy, but in actually it's very simple in this project. The next post in this series will be devoted to this!


Series on creating a Windows Console game:


Source(s):
http://benryves.com/
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682073(v=vs.85).aspx

9 comments:

  1. Thanks for making these! I'm a little busy with school right now, but I'm going to try to use this to make a game over winter break.

    ReplyDelete
  2. Sweet! You must post whatever you finish :D

    ReplyDelete
  3. Thanks man, awesome tutorials!

    ReplyDelete
  4. I noticed that if you try to create a window that is too large the scrollbars will reappear. Have you encountered this problem, and do you know remedy. thx for the blog

    ReplyDelete
  5. Yeah, if you create a buffer size that is larger than the window size, you need to reset the window size to the buffer size.

    ReplyDelete
  6. When I tried this it said it wasn't compatible with the version of windows I was using.

    ReplyDelete
  7. Could you try to provide more info? Your source code, what compiler you were using, etc. You can also email me if you like.

    ReplyDelete
  8. On Visual studio 2010 I think you need to use:

    SetConsoleTitle(L"Our shiny new title!");

    See: http://stackoverflow.com/questions/667616/cast-to-lpcwstr for more info.

    ReplyDelete

Note: Only a member of this blog may post a comment.