Dungeon games are one of the oldest genres in the world of gaming, getting a player through levels within dungeon-like areas with fights against enemies, gathering items, solving puzzles, and finally achieving a goal of a final boss or escaping a dungeon. The genre also readily integrates elements of exploration and strategy along with resource management.
In this article, we will discuss the implementation of a basic dungeon game using C++ . Also, topics covered include but are not limited to creating the game environment, how to manipulate the player's movement, implementation of enemies, and the inclusion of game mechanics like health points and inventory. By the end, we will have a simple text-based dungeon game implemented in C++.
Overview of the Game
In this dungeon game, a completely random dungeon is generated for the player's starting point. The objective is to explore the dungeon, avoid traps, fight enemies, and find the treasure to win. The code will be written in C++ using OOP principles.
Main features of this dungeon game:
- Random dungeon generation
- Player movement (up, down, left, right)
- Enemies that move and attack
- Player health points and enemies' health points
- Finding treasure for the win
Dungeon Setup
A dungeon is actually a grid where different cells may accommodate various things like walls, space, enemies, or the player. In order to present the dungeon grid, we will make use of a 2D array . Now, for C++, a 2D array can be declared as:
const int width = 10;
const int height = 10;
char dungeon[height][width];
Each element of this array will represent a part of the dungeon. For example:
- 'P' for the player
- 'E' for enemies
- 'T' for the treasure
- '#' for walls
- '.' for empty space
We will randomize the dungeon with walls and open space. Players and treasures will be placed randomly on the map.
Definition of the Player Class
We define the Player class, which will be responsible for all properties and actions concerning the players. Generally, the player has attributes including health, position, and inventory.
#include <iostream>
#include <cstdlib>
#include <ctime>
const int height = 10; // Define dungeon height
const int width = 10;
class Player {
public:
int x, y; // Player's position in the dungeon
int health; // Player's health points
Player(int startX, int startY) {
x = startX;
y = startY;
health = 100; // Starting health
}
void move(char direction) {
switch(direction) {
case 'w': // Move up
y--;
break;
case 's': // Move down
y++;
break;
case 'a': // Move left
x--;
break;
case 'd': // Move right
x++;
break;
}
}
void takeDamage(int damage) {
health -= damage;
}
bool isAlive() {
return health > 0;
}
};
It is a class that allows the player to move through space using WASD keys , take some damage from the enemies or traps, and give us a check if the player is still alive based on his health points.
Define a class Enemy:
Now, we will also define an Enemy class, which will represent enemies inside the dungeon. Enemies are going to be pretty just like the player but with different behavior. They will randomly move around inside the dungeon and attack the player if they are within range of him.
class Enemy {
public:
int x, y; // Enemy's position
int health; // Enemy's health
Enemy(int startX, int startY) {
x = startX;
y = startY;
health = 50; // Enemies have less health than the player
}
void moveRandom() {
int direction = rand() % 4;
switch(direction) {
case 0: x--; break; // Move left
case 1: x++; break; // Move right
case 2: y--; break; // Move up
case 3: y++; break; // Move down
}
}
void takeDamage(int damage) {
health -= damage;
}
bool isAlive() {
return health > 0;
}
};
The enemies will move around randomly. If it bumps into a player, it will strike. This behavior of the enemy can be extended to make them intelligent as well. However, for this example, we keep it simple and let them just move around randomly.
Generating the dungeon
Now, let's create a simple dungeon, including walls, free areas, enemies and treasure. We'll place the player at a known position in the beginning. We'll update the dungeon as the player and the enemy move around.
void generateDungeon(char dungeon[height][width], Player &player, Enemy &enemy) {
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
dungeon[i][j] = (rand() % 10 < 2) ? '#' : '.'; // 20% chance of a wall
}
}
dungeon[player.y][player.x] = 'P';
dungeon[enemy.y][enemy.x] = 'E';
int treasureX = rand() % width;
int treasureY = rand() % height;
dungeon[treasureY][treasureX] = 'T';
}
This function generates a random dungeon, places the player and enemy at their assigned positions and subsequently places the treasure randomly somewhere.
Game Loop
The game loop moves the player and the actions of the enemies and updates the state of the game on each turn. We will deal with the player's inputs and update the game accordingly.
void gameLoop(char dungeon[height][width], Player &player, Enemy &enemy) {
bool gameRunning = true;
while (gameRunning) {
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
std::cout << dungeon[i][j] << " ";
}
std::cout << std::endl;
}
char move;
std::cin >> move;
dungeon[player.y][player.x] = '.';
player.move(move);
dungeon[player.y][player.x] = 'P';
if (dungeon[player.y][player.x] == 'T') {
std::cout << "You found the treasure! You win!" << std::endl;
gameRunning = false;
break;
}
dungeon[enemy.y][enemy.x] = '.';
enemy.moveRandom();
dungeon[enemy.y][enemy.x] = 'E';
if (player.x == enemy.x && player.y == enemy.y) {
player.takeDamage(10); // Player takes damage
enemy.takeDamage(10); // Enemy takes damage
std::cout << "You fought an enemy!" << std::endl;
if (!player.isAlive()) {
std::cout << "You died. Game over!" << std::endl;
gameRunning = false;
}
if (!enemy.isAlive()) {
std::cout << "You defeated the enemy!" << std::endl;
dungeon[enemy.y][enemy.x] = '.';
}
}
}
}
int main() {
srand(time(0)); // Seed for random number generation
char dungeon[height][width];
Player player(1, 1); // Starting position of the player
Enemy enemy(2, 2); // Starting position of the enemy
generateDungeon(dungeon, player, enemy);
gameLoop(dungeon, player, enemy);
return 0;
}
Output: