Difference between revisions of "Complete roguelike tutorial using C++ and libtcod - part 4: field of view"

From RogueBasin
Jump to navigation Jump to search
Line 13: Line 13:


[http://roguecentral.org/doryen/data/libtcod/doc/1.5.1/html2/fov_init.html?c=false&cpp=true&cs=false&py=false&lua=false#1 TCODMap::setProperties]
[http://roguecentral.org/doryen/data/libtcod/doc/1.5.1/html2/fov_init.html?c=false&cpp=true&cs=false&py=false&lua=false#1 TCODMap::setProperties]
==Updating the Map class==
In Map.hpp we're adding a reference to a TCODMap object and we add a few helper functions along with the FOV compute function :
<span style="color:green">  bool isInFov(int x, int y) const;
    bool isExplored(int x, int y) const;
    void computeFov();</span>
    void render() const;
protected :
    Tile *tiles;
    <span style="color:green">TCODMap *map;</span>
    friend class BspListener;
Since TCODMap already contains canWalk / canSeeThrough information, we remove the canWalk field from the Tile object. In fact, we're replacing it with an "explored" field that indicates whether this tile has already been seen by the player.
struct Tile {
    <span style="color:green">bool explored; // has the player already seen this tile ?
    Tile() : explored(false) {}</span>
};
In Map.cpp, we allocate the TCODMap object in the constructor :
Map::Map(int width, int height) : width(width),height(height) {
    tiles=new Tile[width*height];
    <span style="color:green">map=new TCODMap(width,height);</span>
and delete it in the destructor :
Map::~Map() {
    delete [] tiles;
    <span style="color:green">delete map;</span>
}
The new isWall method uses the TCODMap object :
bool Map::isWall(int x, int y) const {
    return !map->isWalkable(x,y);
}
whereas the isExplored function uses our Tile array :
bool Map::isExplored(int x, int y) const {
    return tiles[x+y*width].explored;
}
And now the functions dealing with the field of view :
bool Map::isInFov(int x, int y) const {
    if ( map->isInFov(x,y) ) {
        tiles[x+y*width].explored=true;
        return true;
    }
    return false;
}
void Map::computeFov() {
    map->computeFov(engine.player->x,engine.player->y,
        engine.fovRadius);
}
We're using a fovRadius field on the engine class, this way we'll be able to dynamically change the radius.
The isInFov function does not only returns the computed value from the TCODMap object, it also updates the explored flags when a cell enters the field of view.
The dig function must also be updated to use the TCODMap object :
for (int tilex=x1; tilex <= x2; tilex++) {
    for (int tiley=y1; tiley <= y2; tiley++) {
      <span style="color:green"> map->setProperties(tilex,tiley,true,true);</span>
    }
}
In Map::render(), we define two new constants for the light colors :
static const TCODColor lightWall(130,110,50);
static const TCODColor lightGround(200,180,50);
During the map drawing phase, we use the light color for tiles in FOV and the dark color for explored tiles not in fov. Other tiles are not drawn.
for (int x=0; x < width; x++) {
    for (int y=0; y < height; y++) {
        <span style="color:green">if ( isInFov(x,y) ) {
            TCODConsole::root->setCharBackground(x,y,
                isWall(x,y) ? lightWall :lightGround );
        } else if ( isExplored(x,y) ) {
            TCODConsole::root->setCharBackground(x,y,
                isWall(x,y) ? darkWall : darkGround );</span>
        }
    }
}




[[Category:Developing]]
[[Category:Developing]]

Revision as of 17:18, 5 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.


In this fourth part, we're computing the player field of view to light only the visible part of the dungeon. We also only display the part of the dungeon that the player has explored. We're going to use the libtcod TCODMap object to compute the field of view.

libtcod functions used in this article

TCODMap::TCODMap

TCODMap::isWalkable

TCODMap::isInFov

TCODMap::computeFov

TCODMap::setProperties

Updating the Map class

In Map.hpp we're adding a reference to a TCODMap object and we add a few helper functions along with the FOV compute function :

   bool isInFov(int x, int y) const;
   bool isExplored(int x, int y) const;
   void computeFov();
   void render() const;
protected :
   Tile *tiles;
   TCODMap *map;
   friend class BspListener;

Since TCODMap already contains canWalk / canSeeThrough information, we remove the canWalk field from the Tile object. In fact, we're replacing it with an "explored" field that indicates whether this tile has already been seen by the player.

struct Tile {
   bool explored; // has the player already seen this tile ?
   Tile() : explored(false) {}
};

In Map.cpp, we allocate the TCODMap object in the constructor :

Map::Map(int width, int height) : width(width),height(height) {
   tiles=new Tile[width*height];
   map=new TCODMap(width,height);

and delete it in the destructor :

Map::~Map() {
   delete [] tiles;
   delete map;
}

The new isWall method uses the TCODMap object :

bool Map::isWall(int x, int y) const {
   return !map->isWalkable(x,y);
}

whereas the isExplored function uses our Tile array :

bool Map::isExplored(int x, int y) const {
   return tiles[x+y*width].explored;
}

And now the functions dealing with the field of view :

bool Map::isInFov(int x, int y) const {
   if ( map->isInFov(x,y) ) {
       tiles[x+y*width].explored=true;
       return true;
   }
   return false;
}

void Map::computeFov() {
   map->computeFov(engine.player->x,engine.player->y,
       engine.fovRadius);
}

We're using a fovRadius field on the engine class, this way we'll be able to dynamically change the radius.

The isInFov function does not only returns the computed value from the TCODMap object, it also updates the explored flags when a cell enters the field of view.

The dig function must also be updated to use the TCODMap object :

for (int tilex=x1; tilex <= x2; tilex++) {
   for (int tiley=y1; tiley <= y2; tiley++) {
       map->setProperties(tilex,tiley,true,true);
   }
}

In Map::render(), we define two new constants for the light colors :

static const TCODColor lightWall(130,110,50);
static const TCODColor lightGround(200,180,50);

During the map drawing phase, we use the light color for tiles in FOV and the dark color for explored tiles not in fov. Other tiles are not drawn.

for (int x=0; x < width; x++) {
   for (int y=0; y < height; y++) {
       if ( isInFov(x,y) ) {
           TCODConsole::root->setCharBackground(x,y,
               isWall(x,y) ? lightWall :lightGround );
       } else if ( isExplored(x,y) ) {
           TCODConsole::root->setCharBackground(x,y,
               isWall(x,y) ? darkWall : darkGround );
       }
   }
}