Roguelike Game in C++17
The entity and the map
Moving around in a blank world is not fun. Also, code at present has no concept of other things and creatures that could exist. So to fix that further we delve.
Goals
We have two main goals for this part.
- Use an
Entity
class, to manage information likeplayer
's state and abilities. - Use an
Map
class to setup some obstacles.
The entity class
First thing we'll do is replace move_dir
typedef, with a strongly-typed struct.
position
struct will have 2 members x
and y
. Anywhere we had move_dir
gets
replaced by position
.
Next we create an Entity
struct, this will describe our game entities. It has
3 member variables: position
, character
and color
. It also has 2 member
functions: move_by
and draw_entity
. move_by
takes an offset position and
updates entity's position
. draw_entity
takes a console object by reference
and calls console's methods to draw itself. This part we'll change in next section
as current setup is not ideal.
Now we change main
function, replace player_x
and player_y
with player
entity
object, with same position values are before while also adding character and color
to be used.
In the actions
switch block, change how the player position is updated.
And further down, below the actions
switch block, where drawing occurs, we change
the two console method calls with one player.draw_entity
call.
Refactoring for hygene
Before we go any further, we need to reorganize the code a bit. Everything is
currently in the main.cpp
. It's getting a bit crowded, and difficult to visualize
the full flow. So will we break down our program in to multiple files.
main.cpp
: start of the application remains here.console.[cpp, hpp]
: our "wrapped"tcod
console objects.game_entity.[cpp, hpp]
: entity class lives here.
The concept here is, right now we are directly using tcod
functions and objects.
We want to clean up that usage a bit, make it more "safer". tcod
's root console
methods are exposed as static member functions. And one has to know the exact order
to call some of them in. So in order to not memorize or constantly check the documentation
we wrap those, as we use them, in console_root
class.
console_root
when initialized, will ensure that root console exists, and ensure that
TCOD_quit
will get called on exit. It will also expose methods which wrap functionality
we use, e.g. toggle_fullscreen
.
console_layer
is another class that is in console.cpp|.hpp
, this wraps tcod
's
offscreen buffer. It also has draw
method, which will take an entity
object and
draw it out to contained offscreen buffer.
game_entity
at this moment it only has 3 member variables and 1 method. Member
variables describe where and how entity is to be drawn. Method allows owner of
entity to move it by a specific offset position.
Beginning of a map
Refactoring done, time to move on to second goal for this section, creating a map/level structure. This will represent the movement area for the player. As well as, places player can collide with. Collidable area will be colored differently from regular ground area.
Each cell
in our map will be represented by a tile
data structure. We'll hold each
tile
in a game_map
structure in a std::vector
. game_map
knows size of the
movement area via width
and height
. is_blocked
method will take a position
arguement and return true
if that location has a blocking tile
.
We add 2 free functions generate_map
and draw_map
. You can probably guess what each
of these functions does. Both will get called by main
function. Before our main game
loop, we call generate_map
, and before drawing the player we call draw_map
.
To prevent the player from going on top of blocking tile
, we add check before
player.move_by
and call game_map.is_blocked
with potential value of where player
will be. If is_blocked
return false, player can move to that location.

Refactor part 2: the refactoring
Once again, code has gotten a bit hairy ಠ╭╮ಠ
. So it's time to clean up again.
We have a good idea of how the map is to be generated, and how collisions will
work. It is now an exercise to clean up this working code into something that
still works but is manageable. This is circle of programming.
This time around I am moving the code input handling
code out, on top of moving
tile
, game_map
and generating
and drawing
functions as well as pulling out
actions
functionality.
By the end of this set of refactoring activity, the project will have many files.
We need to make sure that CMake is aware of them, which means adding each to
target_sources
in src\CMakeLists.txt
. Over time, this list will get larger
but not that much more larger.

Links
╣ GitHub Repo ╠═══
╣ Home ╠═══
╣ Prev: Console and moving around ╠═══
╣ Next: Dungeon generation ╠═══