c++ - 如何使用 ncurses 库让 Player 与 Monster 交互?

标签 c++ ncurses interaction roguelike

我一直在尝试使用 ncurses 库为 C++ 创建我的 roguelike 类型的游戏。在学习了许多不同的教程之后,我能够创建玩家角色、 map 、防止玩家穿墙的代码以及怪物角色的随机移动。

我遇到的下一个问题是实现一个 bool 值,这样每当玩家角色与怪物角色交互时,游戏就会退出(很像 roguelike 游戏)。但是,我似乎无法让它按照我想要的方式运行。我认为这与我为玩家和怪物设置的坐标有关,但我仍然不确定。谁能帮帮我吗?

代码如下:

#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;
}

最佳答案

我将总结一下约翰霍普金斯的评论。

这本质上是不一致的结果。您的代码在不同的函数中以不同的顺序传递参数(在 isPassable 中首先是 x,然后是 y,但在 MonsterContact 中反之亦然),并对相同的事物使用不同的名称(行和 x 相同。)

您的问题是由于您将 col, row 传递给了 MonsterContact,而您本应传递 row, col。也许你下意识地复制了之前编写 isPassable 时的参数顺序,而忘记了参数顺序是相反的。或者您暂时错误地认为 col 表示 y,row 表示 x。

始终记住尽可能保持代码的一致性,这样您就可以避免将来出现此类错误。

关于c++ - 如何使用 ncurses 库让 Player 与 Monster 交互?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40896171/

相关文章:

c++ - 构造函数中的奇怪 "candidate expects 1 argument, 0 provided"

c++ - Qt5 : Get value of item clicked in a listview

c++ - 为什么除法(?)会产生这个数字?

c++ - 如何在面板中显示用户输入

python - 是否可以将用户输入隐藏为 'sudo' 密码输入?

c++ - 在 C++ 中初始化 boolean vector 的标准方法是什么

c - Ncurses 读取小键盘键和转义

c++ - Ncurses 不滚动 stdscr,导致终端行为异常

上一年的 Stata 交互变量

interaction - 在 Vega 中拖动数据点的鼠标交互