Console Demo (1)

This project demonstrates how to use the new font support in XNA by building a basic console type application. Eventually it could be combined into a more robust program but for now we just want to focus on text input. For an introduction to the new XNA font support, see our last post.

Our definition of a console consists of two parts. First is the command prompt line where the user can enter text, press enter, and something occurs if the user enters a valid command. Below that line are past lines of text that the user has typed or it could be used to display information about the program.

Console1


Console Object

We first need to design our console object that will be used to store both the input text and the past lines of text for display purposes.

dia_shConsole

As you can see, we define how many history lines to remember and the pixel height of each line. We also store the prompt symbol (::) separate from the user-inputed text in case we want to change it in our application. The console’s methods includes functions to add text, erase text, clear text, and the actual drawing of the console.

Keyboard Object

Having a console object is only half of the solution. We also need a way to tell the console what text the user is typing and when the user presses keys such as ENTER, SPACE, BACKSPACE, etc. So we decided to create a Keyboard object that will encapsulate code needed to find which key the user pressed.

dia_shKeyboard

There is only one public property (LastKeyPressed) and two methods. If you download the source code, you will see that there is also private variable used to store the keyboard state:

KeyboardState keyState;

When either method is called, this keyState is updated just as any other XNA program would do. But since we are creating a console demonstration, we need to convert the pressed key result (Keys.X, Keys.Enter, etc.) to a string so we can add it to our console. For example, if the user presses “S”, we add “S” to the console but if the BACKSPACE key is pressed, we need to remove text from the console. Pressing the space bar should generate a 1 character empty string ” ” to simulate a space. Those examples are why we created a FindPressedKey method.

Using the Objects

We then setup a new XNA game application, add the two new classes for our console and keyboard objects, and develop their code. Following the steps in our last post, we also setup a XNA SpriteFont to store the type of text to be displayed in our console. Using the objects in our main program is fairly easy. Below is a quick summary and the full source code is available below.

Step 1 - Define the classes

shConsole console = new shConsole();
shKeyboard keyboard = new shKeyboard();

Step 2 - Check for pressed keys in the Update function

string keyPress = keyboard.FindPressedKey();
if (keyPress == ">>ESCAPE")
{
  this.Exit();
}
else if (keyPress == ">>ENTER")
{
  if (console.Text == "QUIT") this.Exit();
  console.ClearText();
}
else if (keyPress == ">>BACKSPACE")
{
  console.Backspace(1);
}
else
{
console.AddText(keyPress);
}

Step 3 - Draw the console in the Draw function

console.Draw(spriteBatch, courierNew);

Time Delay

The program runs extremely fast so it could potentially be checking for keyboard presses dozens of times per second. This does create a situation where a single key press by the user is picked up several times by program and consequently the console would show the same letter several times. A simple way to avoid this is to add a slight delay between key presses and that is how our program avoids the duplicate letter effect. After a key press, a 50 millisecond delay is enforced where any subsequent key presses are ignored until the time has passed. This isn’t a perfect solution but does a good enough job for now.

Every XNA game template comes with a GameTime variable already ready to use for both the Update and Draw functions. Finding out how much time has passed since the last frame is easy:

gameTime.ElapsedRealTime.Milliseconds;

To track when a certain time has elapsed, just add a time counter variable:

timeCounter += gameTime.ElapsedRealTime.Milliseconds;

And then use it to avoid performing tasks until an amount if time has pass:

if (timeCounter >= 50)
{
  // do something
  timeCounter = 0;
}

Conclusion

Feel free to download the source code and try it out for yourself. There is a lot of room for improvement but at least we have laid the foundation to include some command-line functionality into our future programs.

Download Source Code

Comments are closed.