1.在linux下安装ncurses库
sudo apt-get update
sudo apt-get install libncurses5-dev
2.编译时-l 选项引入 ncurses 库
g++ main.cpp -l ncurses
3.源码
#include
#include
#include
#include
#include
#include
using namespace std;
void swap(int &a, int &b){
int t=a;
a = b;
b = t;
}
int getrand(int min, int max) //得到一个(min,max)区间的随机整数
{
return(min+rand()%(max-min+1));
}
WINDOW *create_newwin(int height,int width,int starty,int startx);//调用newwin创建新窗口,并显示边框
void destory_win(WINDOW *local_win);
int game_win_height=30;
int game_win_width=45; //游戏窗口的尺寸
int hint_win_height=10;
int hint_win_width=20; //显示下一个方块形状的窗口的尺寸
WINDOW * game_win, *hint_win ,*score_win; //3个窗口的指针,游戏,下一个方块,分数
int key;
class Piece //方块类
{
public:
int score; //分数
int shape; //形状
int next_shape; //下一个方块形状
int head_x; //当前方块首个box的位置,标记位置
int head_y;
int size_h; //当前方块的size
int size_w;
int next_size_h; //下一个方块的size
int next_size_w;
int box_shape[4][4]; //当前方块的形状数组4×4,所有7种图形可以在4×4的方框中画出
int next_box_shape[4][4]; //当前方块的形状数组4×4
int box_map[30][45]; //用来标记游戏框内的每个box
bool game_over;
public:
void initial(); //初始化函数
void set_shape(int &cshape, int box_shape[][4],int &size_w, int & size_h); //设置方块形状
void score_next(); //显示下一个方块形状以及得分
void judge(); //判断是否层满
void move(); //移动函数,通过 ← → ↓ 移动
void rotate(); //旋转函数
bool isaggin(); //判断下一次行动是否越界或重合
bool exsqr(int row); //判断当前行是否空
};
int main()
{
initscr(); //屏幕初始化,并进入curses模式
//raw(); //禁止行缓冲,处理挂起、中断或退出等将直接传送给程序去处理而不产生终端信号
cbreak(); //禁止行缓冲,控制字符将被终端驱动程序解释成其它字符
noecho(); //禁止输入的字符出现在屏幕上
curs_set(0);
keypad(stdscr,TRUE); //允许使用功能键,为标准屏幕(stdscr)激活了功能键
refresh(); //刷新终端屏幕
game_win = create_newwin(game_win_height, game_win_width, 0,0); //创建游戏窗口,设置边框
wborder(game_win, '*', '*', '*', '*', '*', '*', '*', '*');
wrefresh(game_win);
hint_win = create_newwin(hint_win_height, hint_win_width, 0, game_win_width+10);//创建下一个形状提示窗口
mvprintw(0, game_win_width+10+2,"%s","Next");
refresh();
score_win = create_newwin(hint_win_height, hint_win_width, 20, game_win_width+10);//创建分数窗口
mvprintw(20, game_win_width+10+2,"%s","Score");
refresh();
Piece* pp = new Piece; //创建方块对象
pp->initial(); //初始化方块
while(1)
{
pp->move(); //移动方块
if(pp->game_over) //判断game_over参数是否等于true
break;
}
destory_win(game_win);
destory_win(hint_win);
destory_win(score_win);
delete pp;
system("clear");
int row,col;
getmaxyx(stdscr,row,col);
mvprintw(row/2,col/2 ,"%s","GAMER OVER ! \n ");
mvprintw(row/2+2,col/2-2 ,"%s","Wait 5s to return tthe erminal ! \n ");
refresh();
sleep(5);
endwin();
return 0;
}
WINDOW *create_newwin(int height, int width, int starty, int startx)
{ //参数分别是,窗口的高、宽,窗口的左上角的坐标(起始坐标)
WINDOW *local_win;
local_win = newwin(height, width, starty, startx);
box(local_win,0,0); //给新创建的窗口画上边框
wrefresh(local_win);
return local_win;
}
void destory_win(WINDOW *local_win)
{
wborder(local_win, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
wrefresh(local_win);
delwin(local_win);
}
void Piece::initial()
{
score=0;
game_over=false;
for(int i =0;ibox_shape[i][j]==1){
mvwaddch(game_win,head_y+i,head_x+j,'#');
wrefresh(game_win);
}
}
}
}
void Piece::move(){ //方块移动
fd_set set;
FD_ZERO(&set); //将文件描述符集所有位清零
FD_SET(0, &set); //将文件描述符0置位
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec= 500000; //设置超时时间为0.5s
if (select(1, &set, NULL, NULL, &timeout) == 0){ //select函数,参数1代表文件描述符范围,最大值加1。超时返回0
head_y++;
if(isaggin()){
head_y--;
for(int i=0;i=0;i--)
for(int j=0;jbox_shape[i][j]==1){
mvwaddch(game_win,head_y-1+i,head_x+j,' ');
mvwaddch(game_win,head_y+i,head_x+j,'#');
}
}
wrefresh(game_win);
}
}
if (FD_ISSET(0, &set)) {//检测到按键
while ((key = getch()) == -1) ;
if(key==KEY_LEFT){
head_x--;
if(isaggin())
head_x++; //
else{
for(int i=0; ibox_shape[i][j]==1){
mvwaddch(game_win,head_y+i,head_x+j+1,' ');
mvwaddch(game_win,head_y+i,head_x+j,'#');
}
}
wrefresh(game_win);
}
}
if(key==KEY_RIGHT){
head_x++;
if(isaggin())
head_x--;
else{
for(int i=0; i=0;j--){
if(this->box_shape[i][j]==1){
mvwaddch(game_win,head_y+i,head_x+j-1,' ');
mvwaddch(game_win,head_y+i,head_x+j,'#');
}
}
wrefresh(game_win);
}
}
if(key==KEY_DOWN){ // 按下 ↓ 键
head_y++; //方块的y坐标 +1
if(isaggin()){ //如果重合或出界,取消这次移动
head_y--;
for(int i=0;i=0;i--)
for(int j=0;jbox_shape[i][j]==1){
mvwaddch(game_win,head_y-1+i,head_x+j,' ');
mvwaddch(game_win,head_y+i,head_x+j,'#');
}
}
wrefresh(game_win);
}
}
if(key==KEY_UP)
rotate();
if(head_x+size_w+1>game_win_width)
head_x=game_win_width-size_w-1;
if(head_x<1)
head_x=1;
}
}
bool Piece::isaggin(){
for(int i=0;i game_win_height-2) //下面出界
return true;
if(head_x+j > game_win_width-2 || head_x+i-1<0) //左右出界
return true;
if(box_map[head_y+i][head_x+j]==1) //与已占用的box重合
return true ;
}
}
return false;
}
bool Piece::exsqr(int row){
for(int j=1;j=2;i--){
int s=i;
if(exsqr(i)==0){
while(s>1 && exsqr(--s)==0);
for(j=1;jnext_shape=getrand(0,6);
set_shape(next_shape,next_box_shape,next_size_w,next_size_h);
for(int i =1;i