Dungeon Game In C++

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:

Example

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.

Example

#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.

Example

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.

Example

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.

Example

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:

Input Required

This code uses input(). Please provide values below: