C++ 实现俄罗斯方块

C++ 实现俄罗斯方块
一、实验介绍
1.1 实验内容
本节实验我们进行设计俄罗斯方块前的思路分析,以及介绍ncurses 库的使用方法。

1.2 实验知识点
C++ 编程基础

ncurses 库的使用

俄罗斯方块逻辑设计

1.3 实验环境
xfce 终端

g++ 编译器

ncurses 库

1.4 适合人群
本课程难度一般,适合有 C++ 编程基础,对游戏设计、逻辑分析感兴趣的同学。

1.5 代码获取
git clone https://github.com/Gamerchen/game_zero.git

二、开发准备
2.1 安装 ncurses 库
sudo apt-get update
sudo apt-get install libncurses5-dev

2.2 编译程序
编译命令要加上 -l 选项引入 ncurses 库:

g++ main.cpp -l ncurses

三、实验原理
3.1 设计前的分析
在开始程序编写之前,我们要先分析程序设计需要实现哪些功能,划分为哪些模块,在俄罗斯方块中我们首先想到的应该是显示方块,其次是方块的下落,左右移动,旋转,最后的层满消行,另外一个基本的俄罗斯方块游戏还应该有下一个方块形状的提示功能。

所以我们编程中需要解决的问题有:

显示方块

实现方块的移动

方块旋转

对层满的方块消行

提示下一个方块形状

3.2 基本图形
每个方块由四个 box 组成,从游戏框的中心位置掉落,在框内不碰撞边界和其他方块的情况下可以进行旋转。

3.3 NCURSES库的使用
简单地说,NCURSES 是一个从 System V Release 4.0 (SVr4) 中 CURSES 的克隆,这是一个可自由配置的库,完全兼容旧版本的 CURSES,是一个可以使应用程序直接控制终端屏幕显示的库。NCURSES封装了底层的终端功能,包含了一些创建窗口的函数,并且有Menu、Panel 和 Form对CURSES基础库的扩展,我们可以建立一个同时包含多窗口(multiple windows)、菜单(menus)、面板(panels)和表单(forms)的应用程序。窗口可以被独立管理,例如让它卷动(scrollability)或者隐藏。 菜单(Menus)可以让用户建立命令选项,从而方便执行命令。而窗体(Forms)允许用户建立一些简单的数据输入和显示的窗口。面板(Panels)是 NCURSES 窗口管理功能的扩展,可以用它覆盖或堆积窗口。

3.3.1 NCURSES--从Hello World程序开始
如果调用 NCURSES 库中的函数,必须在代码中加载 ncurses.h 文件( ncurses.h中已经包含stdio.h ) 例:

#include <ncurses.h>
​
int main()
{
    initscr();   //初始化,进入NCURSES模式
    printw("Hello World!"); //在虚拟屏幕上打印 Hello Wowrld!
    refresh(); //将虚拟屏幕上的内容写到显示器上,并刷新
    getch();  //等待用户输入
    endwin(); //退出NCURSES模式
    return 0;
}

在以上实例中我们介绍了 NCURSES 库中最基本函数的使用方法,函数的功能已在注释中说明,这里不再赘述。

3.3.2 窗口机制
当 NCURSES 初始化的时候,它会默认创建一个叫做 stdscr 的窗口,大小一般是 80 列,25 行(根据显示器或者显卡的不同,可能会出现不同的大小),除此之外,你还可以通过窗口系统的函数创建你自己的窗口。 举例说明,如果调用以下函数:

printw("Hi!");
refresh();

它会在stdscr上当前光标位置输出 "Hi!",调用 refresh() 函数,只更新 stdscr 上的缓冲区。

如果你已经建立了一个叫做win的窗口,想要在win窗口上输出内容,可以再普通函数前添加w,同时参数也要发生变化。

printw(string) //在stdscr的当前光标位置打印字符串string
mvprintw(y,x,string) //将字符串string打印在坐标(y,x)处
wprintw(win,string) //在窗口win的当前光标位置打印字符串string
mvwprintw(win,y,x,string) //将光标移动到窗口win的(y,x)处然后打印字符串string

相信看完上面的例子,你已经能够通过函数的命名规则看出各个函数的功能区别

3.3.3 newwin和box函数
一个窗口的建立是通过 newwin() 函数开始的,函数返回一个指向窗口的结构指针,这个指针可以被传送至一些类似于 wprintw() 这样需要窗口参数的函数中。 然而,我们创建了一个窗口却无法看见它,需要用 box() 函数在已经定义的窗口外围画上边框。 例:

WINDOW *create_newwin(int height, int width, int starty, int startx)
{
WINDOW *local_win;
local_win = newin(height, width, starty, startx);
box(local_win, 0, 0);
wrefresh(local_win);
return local_win;
}

关于 NCURSES 库的基本使用方法就介绍到这里了,在具体使用中遇到问题仍需要查阅相关资料。

c++实现俄罗斯方块代码

#include <iostream>
#include <sys/time.h>
#include <sys/types.h>
#include <stdlib.h>
#include <ncurses.h>
#include <unistd.h>
​
using namespace std;
​
void swap(int &a, int &b){
    int t=a;
    a = b;
    b = t;
}
int getrand(int min, int max)
{
    return(min+rand()%(max-min+1));
}
​
WINDOW *create_newwin(int height,int width,int starty,int startx);
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;
int key;
​
class Piece
{
public:
    int score;
    int shape; 
    int next_shape;
​
    int head_x;
    int head_y;
​
    int size_h;
    int size_w;
​
    int next_size_h;
    int next_size_w;
​
    int box_shape[4][4];
    int next_box_shape[4][4];
​
    int box_map[30][45];
​
    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();
    //raw();
    cbreak();
    noecho();
    curs_set(0);
    keypad(stdscr,TRUE);
​
    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)
            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;i<game_win_height;i++)
        for(int j=0;j<game_win_width;j++){
            if(i==0 || i==game_win_height-1 || j==0 || j==game_win_width-1){
                box_map[i][j]=1;
            }
            else
                box_map[i][j]=0;
        }
​
    srand((unsigned)time(0));
    shape=getrand(0,6);
    set_shape(shape,box_shape,size_w,size_h);
​
    next_shape=getrand(0,6);
    set_shape(next_shape,next_box_shape,next_size_w,next_size_h);
​
    for(int i =0;i<4;i++)
        for(int j=0;j<4;j++)
            if(next_box_shape[i][j]==1){
                mvwaddch(hint_win,(hint_win_height-size_h)/2+i,(hint_win_width-size_w)/2+j,'#');
                wrefresh(hint_win);
            }
                
​
    mvwprintw(score_win, hint_win_height/2,hint_win_width/2-2,"%d",score);
    wrefresh(score_win);
}
​
void Piece::set_shape(int &cshape, int shape[][4],int &size_w,int &size_h)
{
    int i,j;
    for(i=0;i<4;i++)
        for(j=0;j<4;j++)
            shape[i][j]=0;
    switch(cshape)
    {
        case 0: 
            size_h=1;
            size_w=4;   
            shape[0][0]=1;
            shape[0][1]=1;
            shape[0][2]=1;
            shape[0][3]=1;
            break;
        case 1:
            size_h=2;
            size_w=3;
            shape[0][0]=1;
            shape[1][0]=1;
            shape[1][1]=1;
            shape[1][2]=1;
            break;
        case 2:
            size_h=2;
            size_w=3;   
            shape[0][2]=1;
            shape[1][0]=1;
            shape[1][1]=1;
            shape[1][2]=1;
            break;
        case 3:
            size_h=2;
            size_w=3;
            shape[0][1]=1;
            shape[0][2]=1;
            shape[1][0]=1;
            shape[1][1]=1;
            break;
​
        case 4:
            size_h=2;
            size_w=3;
            shape[0][0]=1;
            shape[0][1]=1;
            shape[1][1]=1;
            shape[1][2]=1;
            break;
​
        case 5: 
            size_h=2;
            size_w=2;
            shape[0][0]=1;
            shape[0][1]=1;
            shape[1][0]=1;
            shape[1][1]=1;
            break;
​
        case 6: 
            size_h=2;
            size_w=3;
            shape[0][1]=1;
            shape[1][0]=1;
            shape[1][1]=1;
            shape[1][2]=1;
            break;
    }
​
    head_x=game_win_width/2;
    head_y=1;
​
    if(isaggin())    /* GAME OVER ! */
        game_over=true;
​
}
​
​
void Piece::rotate()
{
    int temp[4][4]={0};
    int temp_piece[4][4]={0};
    int i,j,tmp_size_h,tmp_size_w;
​
    tmp_size_w=size_w;
    tmp_size_h=size_h;
​
    for(int i=0; i<4;i++)
        for(int j=0;j<4;j++)
            temp_piece[i][j]=box_shape[i][j];
​
​
    for(i=0;i<4;i++)
        for(j=0;j<4;j++)
            temp[j][i]=box_shape[i][j];
    i=size_h;
    size_h=size_w;
    size_w=i;
    for(i=0;i<size_h;i++)
        for(j=0;j<size_w;j++)
            box_shape[i][size_w-1-j]=temp[i][j];
​
​
    if(isaggin()){
        for(int i=0; i<4;i++)
            for(int j=0;j<4;j++)
                box_shape[i][j]=temp_piece[i][j];
        size_w=tmp_size_w;
        size_h=tmp_size_h;
    }
    else{
        for(int i=0; i<4;i++)
            for(int j=0;j<4;j++){
                if(temp_piece[i][j]==1){
                    mvwaddch(game_win,head_y+i,head_x+j,' ');
                    wrefresh(game_win);
                }
            }
        for(int i=0; i<size_h;i++)
            for(int j=0;j<size_w;j++){
                if(this->box_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);
          
     struct timeval timeout;
     timeout.tv_sec = 0;
     timeout.tv_usec= 500000;
          
    if (select(1, &set, NULL, NULL, &timeout) == 0){
        head_y++;
        if(isaggin()){
            head_y--;
            for(int i=0;i<size_h;i++)
                for(int j=0;j<size_w;j++)
                    if(box_shape[i][j]==1)
                        box_map[head_y+i][head_x+j]=1;
            score_next();
        }
        else{
            for(int i=size_h-1; i>=0;i--)
                for(int j=0;j<size_w;j++){
                    if(this->box_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++; //undo
            else{
                for(int i=0; i<size_h;i++)
                    for(int j=0;j<size_w;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_RIGHT){
            head_x++;
            if(isaggin())
                head_x--;
            else{
                for(int i=0; i<size_h;i++)
                    for(int j=size_w-1;j>=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++;
            if(isaggin()){
                head_y--;
                for(int i=0;i<size_h;i++)
                    for(int j=0;j<size_w;j++)
                        if(box_shape[i][j]==1)
                            box_map[head_y+i][head_x+j]=1;
​
                score_next();
                
            }
            else{
                for(int i=size_h-1; i>=0;i--)
                    for(int j=0;j<size_w;j++){
                        if(this->box_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<size_h;i++)
        for(int j=0;j<size_w;j++){
            if(box_shape[i][j]==1){
                if(head_y+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)
                    return true ;
            }
        }
    return false;
}
​
bool Piece::exsqr(int row){
    for(int j=1;j<game_win_width-1;j++)
        if(box_map[row][j]==1)
            return true;
    return false;
}
​
void Piece::judge(){
    int i,j;
    int line=0;
    bool full;
    for(i=1;i<game_win_height-1;i++){
        full=true;
        for(j=1;j<game_win_width-1;j++){
            if(box_map[i][j]==0)
                full=false;
        }
        if(full){
            line++;
            score+=50;
            for(j=1;j<game_win_width-1;j++)
                box_map[i][j]=0;
        }
    }
    if(line!=0){
    for(i=game_win_height-2;i>=2;i--){
        int s=i;
        if(exsqr(i)==0){
            while(s>1 && exsqr(--s)==0);
            for(j=1;j<game_win_width-1;j++){
                box_map[i][j]=box_map[s][j];
                box_map[s][j]=0;
            }
        }
    }
​
    for(int i=1;i<game_win_height-1;i++)
            for(int j=1;j<game_win_width-1;j++){
                if(box_map[i][j]==1){
                    mvwaddch(game_win,i,j,'#');
                    wrefresh(game_win);
                }
                else{
                    mvwaddch(game_win,i,j,' ');
                    wrefresh(game_win);
                }
            }
    }
}           
​
void Piece::score_next(){
    score+=10;
    judge();
​
    mvwprintw(score_win, hint_win_height/2,hint_win_width/2-2,"%d",score);
    wrefresh(score_win);
​
​
    set_shape(next_shape,box_shape,size_w,size_h);
​
    this->next_shape=getrand(0,6);
    set_shape(next_shape,next_box_shape,next_size_w,next_size_h);
​
​
    for(int i =1;i<hint_win_height-1;i++)
        for(int j=1;j<hint_win_width-1;j++){
            mvwaddch(hint_win, i, j,' ');
            wrefresh(hint_win);
        }
    for(int i =0;i<4;i++)
        for(int j=0;j<4;j++)
            if(next_box_shape[i][j]==1){
                mvwaddch(hint_win,(hint_win_height-size_h)/2+i,(hint_win_width-size_w)/2+j,'#');
                wrefresh(hint_win);
        }
}

运行如下 有点low 基本功能都有

运行结果.jpg

posted @ 2018-04-11 22:43  whatiwhere  阅读(10385)  评论(0编辑  收藏  举报