Skip to content

Tutorial: 'Console Screen' Basics

Hapaxia edited this page Sep 16, 2017 · 6 revisions

Console Screen Tutorial

Basics


Selba Ward Tutorials


Introduction

Console Screen is a C++ class for displaying a console-like screen to a render window.

These screens resemble those screens used by older, text-based computers and displays/windows used by command-line interfaces (aka Console, Shell, Command Line, Terminal).

Note that this tutorial makes use of C++11 features and Console Screen itself uses C++11 features so a C++11 compatible compiler is required.

Starting Point

We're going to need a basic program to use as a starting point. The following program includes SFML and then uses it to create a window with a loop that continues until the window is closed, also processing the window's events:

#include <SFML/Graphics.hpp>

int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 600), "Console Screen Basics Tutorial", sf::Style::Default);
	
	while (window.isOpen())
	{
	    sf::Event event;
		while (window.pollEvent(event))
		{
		    if (event.type == sf::Event::Closed)
			{
			    window.close();
			}
		}
		
		window.clear(sf::Color(128, 128, 128));
		window.display();
	}
	
	return EXIT_SUCCESS;
}

This is a simple, working SFML render window used for graphical displays and is the minimal required. If you use SFML, you should already be aware of this "skeleton" program. Note that we clear the window with a medium grey colour; this is because the Console Screen starts out black so it would not be visible on a window with a background that is black, which is the default colour when clearing a window.

First Steps

The first things we need to do are include Console Screen and create a Console Screen object.

To include Console Screen, we simply add:
#include <SelbaWard/ConsoleScreen.hpp>

To create an instance of a Console Screen object, we simply use:
Cs cs;
and "cs" becomes the name of our new Console Screen object.

Texture / Font

Console Screen requires an sf::Texture to be useful. It takes some small pieces of this texture and draws them in a grid of tiles that become the cells of the screen.

The texture, then, is effectively the font for Console Screen as it provides the image for each character.

For this tutorial, we're going to use "Windows Console ASCII.png", which is provided in Selba Ward's example/resources/ folder:
Windows Console ASCII.png
Note that the actual texture provided has a transparent background rather than a solid black one. This image with a black background is shown so that the texture can be seen clearly.

We create and load the texture as normal:

sf::Texture csTexture;
if (!csTexture.loadFromFile("PATH/Windows Console ASCII.png"))
    return EXIT_FAILURE;

Note that "PATH" is the absolute or relative directory in which you stored the image file.

Now that we have a texture, we need to tell Console Screen to use it:
cs.setTexture(csTexture);

Console Screen needs to know how the texture is broken up into the parts that it needs so you needs to specify the how the grid in the texture is formed.

First, we need to specify the size of each part (or tile). Remember that this is the size of that tile in the texture, not necessarily the size that it will be drawn. For the texture we are using, the tiles are 8 x 12 pixels.
cs.setTextureTileSize({ 8, 12 });

The texture tile size is set to a default size of 8x8 until it is changed.

We also need to specify how many tiles that are on each row in the texture. If you have a look at the texture we are using in this case, you can see that there are 16 tiles per row.
cs.setNumberOfTextureTilesPerRow(16);

The number of texture tiles per row is set to a default value of 16 until it is changed. This means that we didn't technically need to change this here but it's good practice to make sure you set things how you need them. The value used for the default might be changed in the future.

Drawing

To see that screen, it needs to be drawn to the window. Console Screen can be drawn like any standard SFML drawable:
window.draw(cs);

If you were to run the program so far, you would see a small black rectangle in the top-left corner of the window. This is the Console Screen at its default size, 100 x 100 pixels. We are going to make it larger and shown in the centre of the window.

First, we need to change its size. It is important that this step is done first because we need to use its size to work out its centre for the origin.
cs.setSize(cs.getPerfectSize());

We use setSize, which takes an sf::Vector2f, to set the size of the entire displayed screen. Using getPerfectSize allows us to set the recommended size that, in this case, displays each pixel of the texture 1:1 - in its own pixel of the window. Note that getPerfectSize was only introduced in v2.1

Now we need to change its origin and position - in the same way as standard SFML drawables - so that the screen is in the centre of the window.

cs.setOrigin(cs.getSize() / 2.f);
cs.setPosition(sf::Vector2f(window.getSize() / 2u));

If you run the program now, you will see a screen with a black background in the centre of the window and it has a small, white cursor at the top left of the screen.

Printing

Printing is the primary task in Console Screen; the most common printing task is outputting strings to the screen.

Printing is done by streaming directly into a Console Screen object.
cs << "Hello";

Moving The Cursor

Console Screen has a number of cursor commands that can be used to manipulate the location of the cursor.

To move the cursor the beginning of the row below its current location aka a new line, you use the Newline cursor command:
cs << Cs::CursorCommand::Newline;

Now, anything we print starts from the beginning of the line under the previous output.
cs << "World!";

Chaining

The print stream can chain together multiple types.

We can replace the three previous lines with:
cs << "Hello" << Cs::CursorCommand::Newline << "World!";

Changing The Mode

You may think that the text is too small. We aim to change that now.

The default "mode" is 80 x 45; the mode specifies how many columns and rows into which the screen is divided. We need to reduce the mode so that fewer cells are display then we can increase the overall size so that each cell is larger.

Our goal is to have the cells displayed at double-size. That is, double height and double width. First, though, we need to reduce the number of cells. We can simply halve the columns because they are currently at 80 so we'll change the columns to 40. However, we can't halve 45 so, instead, we will round down and change the rows to 22.

We change the mode to the number of cells we want.
cs.setMode({ 40, 22 });

At the moment, our program shows a screen with fewer cells since we've reduced the mode. However, we want the screen size to be doubled so that each cell is double-sized.

We can simply change the scale (as with normal SFML drawables) so that it displays at double size:
cs.setScale({ 2.f, 2.f });

We could also multiply the size provided by getPerfectSize and leave the scale at 1.

Now we have a screen of approximately the same size as the original screen but with half the number of columns and approximately half the number of rows and therefore each cell is now shown larger.

Note that changing the mode also clears the screen so we change it before doing any printing. We must also set the mode before the call to getPerfectSize as the perfect size is calculated using the current mode (see below).

The perfect size is calculated by multiplying the texture tile size by the mode.
This means that our current "perfect" size is:
columns: 8 x 40 = 320
rows: 12 x 22 = 264
So, our current screen's final display size is (we have scaled to double size):
columns: 8 x 40 x 2 = 640
rows: 12 x 22 x 2 = 528

The size used earlier was just the perfect size directly (without scaling):
columns: 8 x 80 = 640
rows: 12 x 45 = 540

Clearing The Screen

The screen starts in a clear state and is cleared whenever the mode is changed. A clear screen is one where all cells have values of zero. This removes all text from the screen, leaving it in a state where only the background is visible. The screen can also be cleared manually when required.

For our program, we are going to clear what we have done so far and print something else instead:

cs.clear();
cs << "Welcome to the new world!" << Cs::CursorCommand::Newline;

This goes just after the previous print stream.

Note that the cursor is automatically reset back to the top-left corner of the screen when it is cleared so the new text starts from the top-left in the same way it did at the beginning.

A cell's "value" indicates which texture tile it will draw. When the cell is clear - and the value is zero - it is using the very first tile. This texture tile should almost always be a completely transparent rectangle, as it is in the texture we are using.

You can now run the program and see the result - the first text printed is cleared and replaced by the second text, as if the first text never existed:
Final

That concludes the tutorial on the basics.


Selba Ward Tutorials


The Final Program

#include <SFML/Graphics.hpp>
#include <SelbaWard/ConsoleScreen.hpp>

int main()
{
	sf::Texture csTexture;
	if (!csTexture.loadFromFile("PATH/Windows Console ASCII.png"))
		return EXIT_FAILURE;

	sf::RenderWindow window(sf::VideoMode(800, 600), "Console Screen Basics Tutorial", sf::Style::Default);

	Cs cs;
	cs.setTexture(csTexture);
	cs.setTextureTileSize({ 8, 12 });
	cs.setNumberOfTextureTilesPerRow(16);
	cs.setMode({ 40, 22 });
	cs.setSize(cs.getPerfectSize());
	cs.setScale({ 1.f, 1.f });
	cs.setOrigin(cs.getSize() / 2.f);
	cs.setPosition(sf::Vector2f(window.getSize() / 2u));

	cs << "Hello" << Cs::CursorCommand::Newline << "World!";
	cs.clear();
	cs << "Welcome to the new world!" << Cs::CursorCommand::Newline;

	while (window.isOpen())
	{
		sf::Event event;
		while (window.pollEvent(event))
		{
			if (event.type == sf::Event::Closed)
			{
				window.close();
			}
		}

		window.clear(sf::Color(128, 128, 128));
		window.draw(cs);
		window.display();
	}

	return EXIT_SUCCESS;
}

Selba Ward Tutorials


Clone this wiki locally