Difference between revisions of "Complete roguelike tutorial using C++ and libtcod - part 7: the GUI"

From RogueBasin
Jump to navigation Jump to search
m (spacing)
Line 18: Line 18:


[http://roguecentral.org/doryen/data/libtcod/doc/1.5.2/html2/console_print.html?c=false&cpp=true&cs=true&py=false&lua=true#5 TCODConsole::printEx]
[http://roguecentral.org/doryen/data/libtcod/doc/1.5.2/html2/console_print.html?c=false&cpp=true&cs=true&py=false&lua=true#5 TCODConsole::printEx]


==A shiny health bar==
==A shiny health bar==

Revision as of 19:24, 7 October 2015

Complete roguelike tutorial using C++ and libtcod
-originally written by Jice
Text in this tutorial was released under the Creative Commons Attribution-ShareAlike 3.0 Unported and the GNU Free Documentation License (unversioned, with no invariant sections, front-cover texts, or back-cover texts) on 2015-09-21.


After the longish article 6 about melee fighting, we're going to take a break and do something easier.

  • First, we're going to slightly improve the player health bar with some visual fluff.
  • We will also move the game log from the standard output to the game window.
  • Finally, we will start to use the mouse and implement a mouse look feature to display information about what is under the mouse cursor.

These are three very distinct features but for the sake of simplicity, we will stuff everything in a single Gui class (for Graphical User Interface).

libtcod functions used in this article

TCODConsole::TCODConsole

TCODConsole::blit

TCODConsole::rect

TCODConsole::printEx

A shiny health bar

To make it easier to change the GUI position, we're going to render everything on an offscreen console. So let's create a Gui header with everything we need :

Gui.hpp

class Gui {
public :
   Gui();
   ~Gui();
   void render();

protected :
   TCODConsole *con;

   void renderBar(int x, int y, int width, const char *name,
       float value, float maxValue, const TCODColor &barColor,
       const TCODColor &backColor);
};

We use a constructor to allocate the GUI console, a destructor to delete it. The render function will be called by the Engine and will use the renderBar utility to draw the health bar. Before we start the implementation, let's update the Engine :

Engine.hpp :

int screenWidth;
int screenHeight;
Gui *gui;

Engine(int screenWidth, int screenHeight);

We could have used a non pointer field :

Gui gui;

but as you will see below, we need engine.screenHeight to be initialized when the constructor of Gui is called. That's why we're allocating the Gui field dynamically :

Engine constructor :

map = new Map(80,43);
gui = new Gui();

We're going to use 7 lines for the GUI : one for the mouse look description and 6 for the log. That's why we slightly reduced the map's height from 45 cells to 43.

Of course, don't forget to delete gui in the Engine's destructor :

Engine::~Engine() {
   actors.clearAndDelete();
   delete map;
   delete gui;
}

and call gui->render() in the Engine::render method :

Engine::render :

player->render();
// show the player's stats
gui->render();

Ok now we can start the GUI implementation.

static const int PANEL_HEIGHT=7;
static const int BAR_WIDTH=20;

PANEL_HEIGHT is the height of the GUI console. BAR_WIDTH the width of the player health bar.

The constructor allocates the console, the destructor deletes it :

Gui::Gui() {
   con = new TCODConsole(engine.screenWidth,PANEL_HEIGHT);
}

Gui::~Gui() {
   delete con;
}

First, the render function fills the console with black (to erase the content that was drawn in the previous frame) :

void Gui::render() {
   // clear the GUI console
   con->setDefaultBackground(TCODColor::black);
   con->clear();

Then we draw the health bar using the renderBar function :

// draw the health bar
renderBar(1,1,BAR_WIDTH,"HP",engine.player->destructible->hp,
   engine.player->destructible->maxHp,
   TCODColor::lightRed,TCODColor::darkerRed);

And finally, we blit the console on the game window :

// blit the GUI console on the root console
TCODConsole::blit(con,0,0,engine.screenWidth,PANEL_HEIGHT,
   TCODConsole::root,0,engine.screenHeight-PANEL_HEIGHT);

And now the most important : the renderBar function.

void Gui::renderBar(int x, int y, int width, const char *name,
   float value, float maxValue, const TCODColor &barColor,
   const TCODColor &backColor) {

First, we're filling the bar with the background color :

// fill the background
con->setDefaultBackground(backColor);
con->rect(x,y,width,1,false,TCOD_BKGND_SET);

Then we're computing how much of the bar should be filled with the bar color :

int barWidth = (int)(value / maxValue * width);
if ( barWidth > 0 ) {
   // draw the bar
   con->setDefaultBackground(barColor);
   con->rect(x,y,barWidth,1,false,TCOD_BKGND_SET);
}

We're also writing the values on top of the bar, using the printEx function to center the text :

   // print text on top of the bar
   con->setDefaultForeground(TCODColor::white);
   con->printEx(x+width/2,y,TCOD_BKGND_NONE,TCOD_CENTER,
       "%s : %g/%g", name, value, maxValue);
}