Showing posts with label Project. Show all posts
Showing posts with label Project. Show all posts

Tuesday, February 21, 2012

Game Program Structuring/Design: Game State Manager

Not too long ago I created my own first game from scratch in pure C. I struggled most with program design. I'd like to share what I've learned about a proper game state manager.

A game state manager is a method of creating a highly organized main game loop, which is generalized to the point that it can apply to any situation without pre-runtime modification of code. The game should always be in a state during runtime. That state could be the main menu, a pause screen, or a specific level or scenario. A state is divided up into multiple categories, and these categories are generalized enough to apply to every state the game can be in.

The idea is to use function pointers, and a specific set of them. There are six different functions to know:
  • Load
  • Initialize
  • Update
  • Draw
  • Free
  • Unload
These are the six functions that will make up your main loop, and once constructed your main loop should need little to no modification throughout the development of your game. Each function represents a category of functionality during a state. Every state consists of these categories. Each different state will have six functions designed for each of the function pointers in the main loop to point to them. This way your main loop will simply point to different states with its six pointers whenever you want to switch from one state to another.

The load function takes care of loading all of a state's necessary data. Load should be called only once per state -not even if the state restarts. Load also initializes the loaded data. This function is called first when a state starts.

The initialize function prepares the state's data to be used initially. It should not load any data, only prepare it. This allows a fast restart of a state in the event a restart is required -no loading or unloading will be involved in a state restart.

The update function uses a change in time (dt) to hand off to necessary functions to update the game in realtime. dt is defined as the time elapsed since the last call to update. Input should be gathered once per update call before calculations are made. All gameplay logic should happen in this state, and all live objects should be updated here.

The draw function renders all required images onto the screen, and additionally plays any desired sound effects. A well organized program will send data off to a graphics manager in this state, allowing further decoupling of major system and logic components.

The free function is what frees any objects or data no longer required, and sets the state up for switching or restarting. No data is unloaded (image sources, sound sources, meshes, etc). The idea is to set everything up to be initialized cleanly again.

The unload function is called during state termination, and unloads all data loaded in the load state. Here is an example of a properly set up game flow of a main loop: 
Initialize system components
GSM_Initialize( firstState )
while not quitting
  if currentState is quitting
    nextState is Quit
  if currentState is restart
    currentState is previousState
    nextState is previousState
  else
    GSM_Update( )
    Load( )
  Initialize( )
  while currentState is nextState
    Update
      gather input
      get dt
      update game logic
    Draw( )
  Free( )
  if nextState is Restart
    previousState is currentState
    currentState is nextState
  else
    Unload( )
    previousState is currentState
    currentState is nextState
Unload

By analyzing the setup of the above game flow you should be able to see how it works. To change a state, you simply modify the global variables currentState and nextState. previousState is then kept on-hand automatically. GSM_Update is responsible for updating the function pointers Load, Initialize, Update, Draw, Free and Unload whenever a state is started. In the event the global variable currentState changes, these function pointers will then change to their appropriate values via a switch statement. This switch statement lies within the GSM_Update function. The switch runs on the value of currentState, and once it finds a match it assigns the function pointers in the main loop to the appropriate matching state. Here is an example of a GSM_Update function:

// Update the Game State Manager by syncing the three state indicators to their
// corresponding function pointers (all six of them).
int GSM_Update( void )
{
  switch(currentState)
  {
  case Level_1:
    Load = &Level1_Load;
    Initialize = &Level1_Initialize;
    Update = &Level1_Update;
    Draw = &Level1_Draw;
    Free = &Level1_Free;
    Unload = &Level1_Unload;
    break;
  case Level_2:
    Load = &Level2_Load;
    Initialize = &Level2_Initialize;
    Update = &Level2_Update;
    Draw = &Level2_Draw;
    Free = &Level2_Free;
    Unload = &Level2_Unload;
    break;
  case MapEditor:
    Load = &MapEditor_Load;
    Initialize = &MapEditor_Initialize;
    Update = &MapEditor_Update;
    Draw = &MapEditor_Draw;
    Free = &MapEditor_Free;
    Unload = &MapEditor_Unload;
    break;
  case Presentation:
    Load = &PresentationLoad;
    Initialize = &PresentationInitialize;
    Update = &PresentationUpdate;
    Draw = &PresentationDraw;
    Free = &PresentationFree;
    Unload = &PresentationUnload;
    break;
  /*case Template:
    Load = &Load;
    Initialize = &Initialize;
    Update = &Update;
    Draw = &Draw;
    Free = &Free;
    Unload = &Unload;
    break;*/
  case Restart:
    break;
  case Quit:
    break;
  }
  return RETURN_SUCCESS;
}

And there you have it; a proper organizational setup to allow an excellent method of managing game states. Using this sort of organization allows for each state to have a universal format which allows for modification of states, additions of states, and deletions of states during development to be very easy and time-efficient.

Saturday, November 26, 2011

Windows Console Game: Event Handling

The last post in this series was on writing to the console; this post I'd like to go over handling events within the Windows Console. There are two types of events we're interested in: Keyboard Events and Mouse Events. The rest of the type of events we're going to ignore (and MSDN actually advises this on a couple internally used event types). In order to read keyboard events and mouse events, we need to get a record of all events that have occurred to the console since the last time these events were retrieved. This can be done with the following console functions: GetNumberOfConsoleInputEventsReadConsoleInput.


In order to read the console's input buffer (the record of events that have happened from input, including user input), we have to know how many events there are in order to dynamically allocate memory to store those events. This is where GetNumberOfConsoleInputEvents comes. It takes the read handle and a DWORD pointer as its parameters, and places the number of events there are in the address pointed by the DWORD pointer.



/* Read console input buffer and return malloc'd INPUT_RECORD array */
DWORD getInput(INPUT_RECORD **eventBuffer)
{
  /* Variable for holding the number of current events, and a point to it */
  DWORD numEvents = 0;


  /* Variable for holding how many events were read */
  DWORD numEventsRead = 0;


  /* Put the number of console input events into numEvents */
  GetNumberOfConsoleInputEvents(rHnd, &numEvents);


  if (numEvents) /* if there's an event */
  {
    /* Allocate the correct amount of memory to store the events */
    *eventBuffer = malloc(sizeof(INPUT_RECORD) * numEvents);
    
    /* Place the stored events into the eventBuffer pointer */
    ReadConsoleInput(rHnd, *eventBuffer, numEvents, &numEventsRead);
  }


  /* Return the amount of events successfully read */
  return numEventsRead;
}


The above code is a function that places an array of INPUT_RECORD structures into the content of the pointer pointed by the parameter eventBuffer. If you're confused about the double asterisk **, then read the rest of the paragraph. If you already understand what this function is doing, skip to the next paragraph. The asterisk, known as the dereference operator, can be read as "the content pointed by". In order for this getInput function to place the INPUT_RECORD structs into the address pointed by a pointer, we have to pass a pointer to a pointer to the function -otherwise we'd only pass the value of a pointer to the function, which isn't what we want. Then, to access the the pointer we passed, we'd use one asterisk. To access the value pointed by the pointer that is pointed to by the parameter pointer, we must use a second *. See the below diagram for a visual representation. On the left, Pointer 1 is dereferenced giving you direct access to Pointer2. Pointer2 is dereferenced giving you direct access to the INPUT_RECORD. The right side of the diagram uses two dereferences to directly access INPUT_RECORD in a single stroke.




Now that we have a function for getting the INPUT_RECORD structs, we need to be able to loop through each structure and analyze what kind of record it is, and depending on what it does we can do whatever action we like.


while(1)
  {
    /* Get the input and number of events successfully obtained */
    numEventsRead = getInput(&eventBuffer);
    
    /* if more than 0 are read */
    if (numEventsRead)
    {
      /* loop through the amount of records */
      for (i = 0; i < numEventsRead; i++)
      {
        /* check each event */
        switch (eventBuffer[i].EventType)
        {
          /* if type of event is a KEY_EVENT */
          case KEY_EVENT:
            switch (eventBuffer[i].Event.KeyEvent.wVirtualKeyCode)
            {
              /* if escape key is pressed*/
              case VK_ESCAPE:
                return 0;
            }
        }
      }
    }
  }

The above code continuously loops until a user presses the escape key on their keyboard, which then makes the program close. This works by getting the INPUT_RECORD structs into the pointer eventBuffer (which points to type INPUT_RECORD) using our getInput function, and placing the return value thereof into numEventsRead. The loop then checks for a KEY_EVENT, and if found checks to see if the escape key was pressed. Similarly, you can check to see if a MOUSE_EVENT occurred in this very same way. If you understood what I've explained thus far in all of this series, you should be able to check for any keypress, with the help of the virtual keycode page, and then do something thereafter.


Now how about writing something onto the console when you click your left mouse button? The first thing you'd need is to be able to check for a MOUSE_EVENT record, and get the mouse's x and y coordinates from the MOUSE_EVENT structure. Here's an example of a case to do such a thing:


case MOUSE_EVENT:
  offsetx = eventBuffer[i].Event.MouseEvent.dwMousePosition.X;
  offsety = eventBuffer[i].Event.MouseEvent.dwMousePosition.Y;
  if (eventBuffer[i].Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)
  {
    writeImageToBuffer(consoleBuffer, REDRECTANGLE.chars, REDRECTANGLE.colors, REDRECTANGLE.width, REDRECTANGLE.height, offsetx - 1, offsety - 1);
    write = YES;
  }

This indexes the INPUT_RECORD structs when a MOUSE_EVENT structure is found, and then accesses the data members X and Y, as detailed here, and places the values of the x and y position into two integers. The large constant FROM_LEFT_1ST_BUTTON_PRESSED is a Microsoft definition for a left-click. Now what is this writeImageToBuffer function? That doesn't seem to be a MSDN documented function... Well it's not! It's a simple function I wrote to write any image onto the screen buffer, given the correct parameters. The image it is writing is called REDRECTANGLE, which is actually a structure defined in a file I've written called redRectangle.h. The red rectangle is a square of 9 red characters, so to write this square onto where the user clicks, you must use offsetx - 1, and offsety -1, otherwise the top left of the red rectangle image will be placed on the left-click location, instead of the center.


Now lets check out redRectangle.h so you can see how I've set up the image of REDRECTANGLE!


/* redRectangle.h */


#ifndef FILEREDRECTANGLEH
#define FILEREDRECTANGLEH


/* A red rectangle! */


#define REDRECTANGLEW 3
#define REDRECTANGLEH 3


typedef struct
{
  int width;
  int height;
  int chars[REDRECTANGLEW * REDRECTANGLEH];
  int colors[REDRECTANGLEW * REDRECTANGLEH];
} _REDRECTANGLE;


_REDRECTANGLE REDRECTANGLE = 
{
  REDRECTANGLEW,
  REDRECTANGLEH,
  {
    219, 219, 219,
    219, 219, 219,
    219, 219, 219,
  },
  {
    4  , 4  , 4  ,
    4  , 4  , 4  ,
    4  , 4  , 4  ,
  }
};


#endif /* FILEREDRECTANGLEH */

This was the cleanest way I could think of for setting up an image that should be compatible with all versions of C. I'll start explaining from the top of the file. The two preprocessor directives ifndef and define are used to see if FILEREDRECTANGLEH is defined yet or not. If it is not yet defined, then the entire contents of the file will be included wherever an include of this file is placed. If the define FILEREDRECTANGLEH is already defined, it means that you've already included this file somewhere, and so the entire contents of the file will be skipped!


Screenshot of the final demonstration program, drawing on the window!


I have two defines for each image I write in this format, and they represent width and height as 3 in this image. These defines are critical for declaring a REDRECTANGLE, as the size needs to be defined at compile, since a template for the structure needs to be created for the program to run, and as such you need to know the size of the arrays within the REDRECTANGLE structure in order to properly place it in memory! However, the use of defines in this way makes it very simple to create other copies of images. For example, to create a new image called BLUETRIANGLE, you simply use find and replace (ctrl + h for a lot of programs) and replace all instances of REDRECTANGLE, with BLUERECTANGLE. You then would modify the color and character arrays to contain the correct data, and change the WIDTH/HEIGHT values for the defines accordingly. The structure called _REDRECTANGLE is typedef'd allowing declaration of variables by skipping writing the annoying legacy struct keyword. An instance of _REDRECTANGLE called REDRECTANGLE is then declared and initialized with the arrays containing the values for the ASCII characters, and color values.


Using this format in conjunction with the writeImageToBuffer function, you can pretty easily create new images and write them with limited amounts of code! Now lets check out a finished product: link (I didn't want to post the entire unwieldy thing here).


The last thing to mention is that if you update the screen with WriteConsoleOutputA every loop, you'll probably see little flickers as the screen is updated. This is simply a limitation of the function WriteConsoleOutputA. There are a few solutions to this. The easiest solution I've come up with is to just update screen less often, and I chose to do this by limiting the time in which the screen is updated to only when the consoleBuffer is changed. Another solution is to keep track of which portions of the screen you actually need to update, and call WriteConsoleOutputA and only write with the smallest portion of the screen as possible. Also supposedly if you update the screen with the same characters and colors multiple times it increases the chance of flickering lines, so this means you should try to avoid doing so. Lastly, you can multi-thread your program, and place just the call to WriteConsoleOutput within the additional thread. I do the first solution with a simple if statement:


  /* If write is 1, meaning the screen needs to be updated */
  if (write)
  {
    /* Write our character buffer (a single character currently) to the console buffer */
    WriteConsoleOutputA(wHnd, consoleBuffer, characterBufferSize, characterPosition, &consoleWriteArea);
    write = NO;
  }

This will only call the WriteConsoleOutputA function when write is not 0.


The entire final program demonstrates drawing a square image on the screen on left-click, and a red dot to the screen on right click. There is boundary checking on the click coordinates to prevent indexing outside of the screen!


You might by now have realized that the characters you're writing to the screen are oddly shaped rectangles. What about nice square characters? Square characters are essential for creating a nice game :( Well the next post in this series covers setting the console's font, font size, and even the color palette!


Series on creating a Windows Console game:

Wednesday, November 16, 2011

Windows Console Game: Writing to the Console

Previously I showed you all how to set up a console window! Now lets talk about writing to the Windows console. One can use printf, or fprintf, but those options aren't really exactly ideal; you don't have a desired amount of control. We're going to use the function WriteConsoleOutput in order to write a buffer of characters (array of characters) onto the console's screen buffer. The screen buffer is the inside of your game's window in which characters are written to and appear. In order to use the WriteConsoleOutput function, you have to pass to it a buffer of characters, which is really just an array of characters. The character buffer will be comprised of an array of CHAR_INFO structures, which is a Microsoft defined type that comes from windows.h. Lets get started with just writing a single character to the screen.

In C characters are enclosed letters or numbers enclosed in single quotes, like so: 'c'. Characters in c, like 'c', are treated very similarly to integers. The main difference is that the range of a character (unsigned) is from 0 to 255, where a range of integers reaches much much higher. Due to this a character variable will be one byte in memory (8 bits). You can actually write in your code 'c', and it will be treated as the value of whatever the ascii value of C is, which is 99 in decimal. You can even write c - 8, and it will be treated as 99 - 8. Here is my favorite chart for all the values of all the ascii characters available, note the indices are in hexidecimal:



The CHAR_INFO structure contains two data members; a character and its attributes. The character can either be a unicode or ascii character. We're going to stick with ascii characters within the Char.AsciiChar data member (remember, this is just an integer with a range of 0-255). The Attributes data member is a WORD type, which is just a Microsoft defined type. The WORD type is simply a 16-bit unsigned integer with a range of 0 through 65535. The Attributes data member can be viewed simply as a byte of data with the following value representations as colors:
  • FOREGROUND_BLUE - 0x0001
  • FOREGROUND_GREEN - 0x0002
  • FOREGROUND_RED - 0x0004
  • FOREGROUND_INTENSITY - 0x0008
  • BACKGROUND_BLUE - 0x0010
  • BACKGROUND_GREEN - 0x0020
  • BACKGROUND_RED - 0x0040
  • BACKGROUND_INTENSITY - 0x0080
These values are the different colors accessible for use within the Windows console. The values are represented in hexadecimal, and should be viewed as a byte:



 In the picture above I've shown a single byte, which is 8 bits of information. Each bit can be either a 1 or a 0. The first bit is on the right (at least for this representation). If you wish for your Attributes data member to contain the value blue, then you set the first bit of this byte to 1. The second bit represents whether or not you want to add green to your color, and so on and so forth. The above image would contain the values of blue, red, and intensity. This value would be in decimal format 1 + 4 + 8, which is 13. Intensity brightens the color to be displayed. Knowing this will allow us to construct whatever color we like with some simple addition! For the first color lets mix blue, green, and intensity for a value of 11.

Here is what MSDN says for the WriteConsoleOutput function in regards to parameters required:

BOOL WINAPI WriteConsoleOutput(
  __in     HANDLE hConsoleOutput,
  __in     const CHAR_INFO *lpBuffer,
  __in     COORD dwBufferSize,
  __in     COORD dwBufferCoord,
  __inout  PSMALL_RECT lpWriteRegion
);

hConsoleOutput is simply the output handle for our window, *lpBuffer is a pointer to a buffer of CHAR_INFO structures, dwBufferSize is the size of the buffer in character elements, dwBufferCoord is the location on your console screen buffer in which to write the image, and lpWriteRegion is just a pointer to a COORD structure for dictating which portion of the console to write to. Here's some code using this knowledge to write a character to the screen:

#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};
  
  /* Setting up different variables for passing to WriteConsoleOutput */
  COORD characterBufferSize = {1, 1};
  COORD characterPosition = {0, 0};
  SMALL_RECT consoleWriteArea = {0, 0, 0, 0}; 
  
  /* A CHAR_INFO structure containing data about a single character */
  CHAR_INFO characterQ;
  characterQ.Char.AsciiChar = 'Q'; /* Setting the Char.Ascii data member of characterQ to the value of 'Q' */
  
  /* Setting up the color values for our Q character: blue + green + intensity */
  characterQ.Attributes = FOREGROUND_BLUE | FOREGROUND_GREEN |
                          FOREGROUND_INTENSITY;
 
  /* 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);
  
  /* Write our character buffer (a single character currently) to the console buffer */
  WriteConsoleOutputA(wHnd, &characterQ, characterBufferSize, characterPosition, &consoleWriteArea);
 
  getchar();
}
The code above prints the character Q to the screen in a bright cyan color. This probably seems like a lot of work to write a single character to the screen, and it sort of is. But in actuality this isn't really how you want to write every character onto the screen. The WriteConsoleOutput function is a very slow function, and so you want to call it as little as possible. You may have heard of a term called "double buffer", well we're going to use a double buffer to do all of our modifying of a buffer off-screen, and once all our modifications are finished we can write a single image to the screen all in one go. To create this buffer, simply create an array of CHAR_INFO structures and initialize all of the Char.AsciiChar and Attribute data members! Here's an example of looping through an array of CHAR_INFOs and assigning random colors to a single Char type.
#include <windows.h> /* for HANDLE type, and console functions */
#include <stdio.h> /* standard input/output */
#include <stdlib.h> /* included for rand */

#define WIDTH 70
#define HEIGHT 35

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

int main(void)
{
  int x, y;
  
  srand(time(0));
  
  /* Window size coordinates, be sure to start index at zero! */
  SMALL_RECT windowSize = {0, 0, WIDTH - 1, HEIGHT - 1};

  /* A COORD struct for specificying the console's screen buffer dimensions */
  COORD bufferSize = {WIDTH, HEIGHT};
  
  /* Setting up different variables for passing to WriteConsoleOutput */
  COORD characterBufferSize = {WIDTH, HEIGHT};
  COORD characterPosition = {0, 0};
  SMALL_RECT consoleWriteArea = {0, 0, WIDTH - 1, HEIGHT - 1};
  
  /* A CHAR_INFO structure containing data about a single character */
  CHAR_INFO consoleBuffer[WIDTH * HEIGHT];
 
  /* 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);
  
  for (y = 0; y < HEIGHT; ++y)
  {
    for (x = 0; x < WIDTH; ++x)
    {
      consoleBuffer[x + WIDTH * y].Char.AsciiChar = (unsigned char)219;
      consoleBuffer[x + WIDTH * y].Attributes = rand() % 256;
    }
  }
  
  /* Write our character buffer (a single character currently) to the console buffer */
  WriteConsoleOutputA(wHnd, consoleBuffer, characterBufferSize, characterPosition, &consoleWriteArea);
 
  getchar();
}
The above code is creating a buffer called consoleBuffer, of a single dimensional array with the number of elements equal to WIDTH times HEIGHT, both of which are now defined at the top of the file. There is a loop that loops through all of the CHAR_INFO's Char.AsciiChar data member, and Attributes data members initializing them. You can see how I'm assigning a random value using rand, and seeding the table at the beginning of the code with srand.

You might be a little confused by the x + WIDTH * y portion of the code. I've created a single dimensional array of elements WIDTH * HEIGHT, and in order to index the array during a loop as if it were a two dimensional array, you need to use a formula. The idea behind the formula is to figure out what row you want to access, by taking the number of elements in a row and multiplying it by a value. To access the first row, you multiply the WIDTH value by 0. To access the fifth row, you'd multiply WIDTH by five. This works since as the single dimensional array is written to the screen with WriteConsoleOutput, it wraps around the screen buffer once ever WIDTH elements. Then, access a specific element within that row you add in your x value.



And there you have it! A method for writing an image onto the screen of any given size on any location of the console's screen buffer! The next post in this series will be on Event Handling.


List of all posts completed thus far:
Source(s):
http://benryves.com/
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682073(v=vs.85).aspx

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