上次我们已经实现了游戏基本的框架,现在我们来创建地图。随机地图是Rogue游戏的生命力所在。我们采取的算法是随机创建房间,然后用走廊将它们连起来。
Makefile:
objects = main.o makemap.o
rogue:$(objects)
g++ $(objects) -o rogue -lncurses
makemap.o:makemap.cpp
g++ -c makemap.cpp
main.o:main.cpp
g++ -c main.cpp
clean:
rm -rf *.o rogue
main.cpp:
#include <curses.h>
#define EMPTY 0
#define ME 1
#define WALL 2
#include <stdlib.h>
static char symbol[] = {'.', '@', '#'};
static const int m_w = 90;
static const int m_h = 22;
static const int offset_x = 5;
static const int offset_y = 2;
static int **map;
void MakeMap(int _w, int _h, int **_map);
void drawMap()
{
for (int i = 0;i < m_w;++i)
for (int j = 0;j < m_h;++j)
mvaddch(j + offset_y, i + offset_x, symbol[map[j][i]]);
}
class human
{
int x;
int y;
int kind;
public:
human(int _kind);
void Move(int _dir);
void ShowMove(int fx, int fy, int tx, int ty);
};
human::human(int _kind)
{
kind = _kind;
do
{
x = rand() % m_w;
y = rand() % m_h;
}while(map[y][x] != 0);
mvaddch(y + offset_y, x + offset_x, symbol[kind]);
refresh();
}
void human::Move(int _dir)
{
int dir_x[4] = {-1, 0, 1, 0};
int dir_y[4] = {0, 1, 0, -1};
int old_x = x;
int old_y = y;
x += dir_x[_dir];
y += dir_y[_dir];
if (map[y][x] == WALL)
{
x = old_x;
y = old_y;
return;
}
ShowMove(old_x, old_y, x, y);
move(0, 0);
refresh();
}
void human::ShowMove(int fx, int fy, int tx, int ty)
{
mvaddch(fy + offset_y, fx + offset_x, symbol[EMPTY]); //EMPTY
mvaddch(ty + offset_y, tx + offset_x, symbol[this->kind]);
}
int main()
{
initscr();
clear();
noecho();
curs_set(0);
mvprintw(0, 0, "My Rogue\na/left w/up s/down d/right q/Exit");
map = new int*[m_h];
for (int i = 0;i < m_h;++i)
map[i] = new int[m_w];
MakeMap(m_w, m_h, map);
drawMap();
human me(ME);
while(1)
{
char order = getch();
if (order == 'q') break;
switch(order)
{
case 'a': me.Move(0);break;
case 's': me.Move(1);break;
case 'd': me.Move(2);break;
case 'w': me.Move(3);break;
}
}
for (int i = 0;i < m_h;++i)
delete []map[i];
delete []map;
endwin();
return 0;
}
makemap.cpp
#include <stdlib.h>
#include <time.h>
#define ROOM_MIN_W 5
#define ROOM_MIN_H 4
#define ROOM_MAX_W 10
#define ROOM_MAX_H 7
#define ROOM_NUM 10
#define MAX_TRY 300
class room
{
public:
int x;
int y;
int w;
int h;
bool TryCreateRoom(int _w, int _h, int **map)
{
do
w = rand() % (ROOM_MAX_W + 1);
while(w < ROOM_MIN_W);
do
h = rand() % (ROOM_MAX_H + 1);
while(h < ROOM_MIN_H);
x = rand() % (_w + 1);
y = rand() % (_h + 1);
if (x + w > _w || y + h > _h)
return false;
for (int i = x;i < x + w;++i)
for (int j = y;j < y + h;++j)
{
if (map[j][i] != 2 || i == 0 || i == _w-1 || j == 0 || j == _h-1)
return false;
}
return true;
}
bool CreateRoom(int _w, int _h, int **map)
{
for (int i = 0;i < MAX_TRY;++i)
if (TryCreateRoom(_w, _h, map))
{
for (int ii = x;ii < x + w;++ii)
for (int jj = y;jj < y + h;++jj)
map[jj][ii] = 0;
return true;
}
return false;
}
};
void MakePassageWay(int fx, int fy, int tx, int ty, int **map)
{
for (int i = 0;i <= tx || i <= fx;++i)
if (map[fy][i] == 2
&& ((i <= tx && i >= fx)||(i >= tx && i <= fx)))
map[fy][i] = 0;
for (int i = 0;i <= ty || i <= fy;++i)
if (map[i][tx] == 2
&& ((i <= ty && i >= fy)||(i >= ty && i <= fy)))
map[i][tx] = 0;
}
void LinkRoom(room *_r1, room *_r2, int **map)
{
MakePassageWay(_r1->x, _r1->y, _r2->x, _r2->y, map);
}
void MakeMap(int _w, int _h, int **map)
{
srand((unsigned)time(NULL));
for (int i = 0;i < _w;++i)
for (int j = 0;j < _h;++j)
map[j][i] = 2;
room r[ROOM_NUM];
r[0].CreateRoom(_w, _h, map);
for (int i = 1;i < ROOM_NUM;++i)
if (r[i].CreateRoom(_w, _h, map))
LinkRoom(&r[i-1], &r[i], map);
//LinkRoom(&r1, &r2, map);
return;
}
运行结果: