0

I've been trying to create my roguelike type of game for C++ using the ncurses library. After following many different tutorials, I am able to create the Player character, the map, the code to prevent the Player from going through walls and the random movements for the Monster character.

The next problem I'm encountering is implementing a boolean so whenever the Player character interacts with the Monster character, the game will quit (much like the roguelike games). However, I can't seem to get it to function the way I wanted. I think it has to do with the coordinates that I have set for the Player and the Monster but I'm still not sure. Can anyone help me out please?

Here is the code:

#include <iostream>
#include <ncurses.h>

#define MAP_WIDTH 22
#define MAP_HEIGHT 15

#define TILE_FLOOR 0
#define TILE_WALL 1

int PlayerX, PlayerY;

void erase (int y, int x) {
    mvaddch(y, x, '.');
}

int nMapArray[MAP_HEIGHT][MAP_WIDTH] = {
    { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
    { 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
    { 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
    { 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
    { 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
    { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1 },
    { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
    { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
    { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
    { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
    { 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
    { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1 },
    { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1 },
    { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1 },
    { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
};

bool IsPassable (int nMapX, int nMapY) {            //prevents from walking into walls

    if (nMapX < 0 || nMapX >= MAP_WIDTH || nMapY < 0 || nMapY >= MAP_HEIGHT)
        return false;

    int nTileValue = nMapArray[nMapY][nMapX];

    if( nTileValue == TILE_FLOOR) {
        return true;
    }

    return false;
}

class Monster {
public:
    void Appearance(char monster) {
        this->Monster = monster;
    }

    void SetPos(int x, int y) {
        this->PosX = x;
        this->PosY = y;
    }

    void Movement(int &MonsX, int &MonsY) {
        int x = (rand() % 3 - 1);
        int y = (rand() % 3 - 1);

        if (IsPassable(this->PosX+x, this->PosY+y)) {
            erase(PosY, PosX);
            MonsX = this->PosX += x;
            mvaddch(this->PosY, MonsX, this->Monster);
            refresh();

            erase(PosY, PosX);
            MonsY = this->PosY += y;
            mvaddch(MonsY, this->PosX, this->Monster);
            refresh();
        }
    }


protected:
    int PosX;
    int PosY;
    char Monster;
};

bool MonsterContact (int nMapY, int nMapX, int x, int y) {


    if (nMapArray[nMapY][nMapX] == nMapArray[y][x]) {
        return true;
    }

    return false;
}

void map() {
    for (int y = 0; y < MAP_HEIGHT; y++) {          //loops to print the map

        move(y,0);

        for (int x = 0; x < MAP_WIDTH; x++) {
            switch (nMapArray[y][x]) {
                case TILE_FLOOR:
                    printw(".");
                    break;

                case TILE_WALL:
                    printw("#");
                    break;
            }
        }
    }
};

void init() {               //starts the ncurses screen.
    initscr();
    clear();
    noecho();
    raw();
    keypad(stdscr, TRUE);
    curs_set(0);
}

void game_loop (char Player, int row, int col, int ch) {

    Monster npc;
    npc.SetPos(7, 8);
    npc.Appearance('g');
    int MonsX,MonsY;

    mvaddch(row,col, Player);                   //player movement
    refresh();

    while(true) {

        npc.Movement(MonsX, MonsY);

        ch = getch();

        switch (ch) {

            case 'w':
                if (IsPassable(col, row-1)) {
                erase(row,col);
                row = row - 1;
                mvaddch(row, col, Player);
                    refresh();
                }

                if (MonsterContact(col, row, MonsX, MonsY)) {
                    return();
                }
                break;

            case 's':
                if (IsPassable(col, row+1)) {
                erase(row, col);
                row = row + 1;
                mvaddch(row, col, Player);
                    refresh();
                }

                if (MonsterContact(col, row, MonsX, MonsY)) {
                    return();
                }

                break;

            case 'a':
                if (IsPassable(col-1, row)) {
                erase(row,col);
                col = col - 1;
                mvaddch(row, col, Player);
                    refresh();
                }

                if (MonsterContact(col, row, MonsX, MonsY)) {
                    return();
                }

                break;

            case 'd':
                if (IsPassable(col+1, row)) {
                erase(row,col);
                col = col + 1;
                mvaddch(row,col, Player);
                    refresh();
                }

                if (MonsterContact(col, row, MonsX, MonsY)) {
                    return();
                }

                break;

            case 'q':
                return;

            default:
                break;
        }

    }
}

int main(int argc, const char * argv[]) {

    PlayerX = 2, PlayerY = 1;        //Player initial position.
    char Player = '@';

    init();                     //starts the ncurses screen.

    printw("Press any key to start the game");
    int ch = getch();
    clear();

    map();
    game_loop(Player, PlayerY, PlayerX, ch);

    endwin();

    return 0;
}
RyAaren
  • 1
  • 1
  • I noticed that you define `MonsterContact` with the parameters taking `mapy` before `mapx`, but `IsPassable` takes `mapx` before `mapy`, but when you call the two of them next to each other, you're passing `col` and `row` in the same order. This may be the cause of the problem. You should really take care to define all your functions to take coordinates in the same order (probably matching the order that ncurses takes them) so this kind of confusion can be avoided. – jonhopkins Nov 30 '16 at 19:18

1 Answers1

1

I'll sum up what jonhopkins commented on.

This is essentially a result of inconsistency. Your code passes arguments in different orders in different functions (first x, then y in isPassable, but vice versa in MonsterContact), and uses different names for the same things (row and x are the same.)

Your problem is caused by the fact that you passed col, row into MonsterContact, when you should have passed row, col. Perhaps you subconsciously copied the order of arguments from when you wrote isPassable a little earlier, forgetting that the order of arguments is reversed. Or you momentarily mistakenly thought that col meant y and row meant x.

Always remember to keep your code as consistent as possible, and you can avoid these sorts of mistakes in the future.

Anonymous1847
  • 2,568
  • 10
  • 16