俄罗斯方块----Ubuntu终端游戏

我最近在看C++和linux,为了能够更加牢靠的掌握自己的学到的知识,所以采用写小游戏的方法来帮助自己巩固学习。在这篇代码中我用到的C++和linux知识有:
C++知识:
1. 类的创建
2. 内联函数
3. pthread线程
linux知识:
1. 进入root模式
2. 给文件增加权限
3. 查看和使用系统的外设

有三点要特别说明:
1. 本代码不适用于所有linux系统,如果照搬的话可能会运行失败。如果要保证此代码编译的程序能在另一台机器上运行,需要先查看该机器的键盘是对应哪一个event文件,并将代码中的打开event文件的名称改掉。
2. 因为打开event文件需要很高的权限,所以需要在root模式下运行
3. 要编译此程序需要在链接是加入pthread库,即编译时需要g++ -lpthread *.cpp

具体代码如下:

RussiaBlock.h

#ifndef RUSSIA_BLOCK_H
#define RUSSIA_BLOCK_H

#include <iostream>
#include <ctime>
#include <stdexcept>
#include <unistd.h>
#include <pthread.h>
#include <cstdlib>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <errno.h>
#include <linux/input.h>

using namespace std;

typedef struct Pos
{
    unsigned char x;
    unsigned char y;
} Pos;
typedef struct Block
{
    Pos  pos[4];
    bool Droping;
    short shape;
} Block;

class RussiaBlock
{
    private:
        enum {TIAN_BLOCK=0,L_BLOCK,T_BLOCK,FL_BLOCK,I_BLOCK,HI_BLOCK,Z_BLOCK,FZ_BLOCK};
        bool    gameFail;
        bool    dropToEnd;
        bool    Rotating;
        unsigned int score;
        unsigned char screenWidth;
        unsigned char screenHeight;
        Block currentBlock;
        Block nextBlock;
        unsigned char map[100][100];
    public:
        void  GameStart(void);                                  //开始游戏
        RussiaBlock(unsigned char, unsigned char = 80);
    private:
        Block TianBlock(void);          //田型方块
        void  FailNotice(void);                             //游戏失败提示
        Block LBlock(void);             //L型方块
        void  KeyOperate(void);                         //按键操作
        void  ShowScreen(void);                             //显示游戏区域
        Block CreatNewBlock(void);                          //创建一个新的方块
        void  ShowNextBlock(void);                          //显示下一个方块提示
    private:
        Block TBlock();                 //T型方块
        Block FLBlock();                //反L型方块
        Block IBlock();                 //I型方块
        Block HIBlock();                //横I型方块
        Block ZBlock();                 //Z型方块
        Block FZBlock();                //反Z型方块
        void  AutoDrop(void *);         //自动下降线程
        static void *Thread_func(void *);
        static void *Thread_Key(void *);
        void   MoveRight();             //右移
        void   MoveLeft();              //左移
        void   DropEnd();               //下降到底
        void   RotateBlock();           //旋转方块
        void   DeleteLines();           //清除游戏区域内多行内容
        bool   DropOneLine();           //下降一行
        void   DeleteOneLine();         //删除一行
        bool   AtTheEnd();              //判断是否在可降落的最低点
        inline bool ThisLineIsFull(int index)
        {
            for(int i=0;i<screenWidth;i++)
            {
                if(map[i][index] == 0)
                    return false;
            }
            return true;
        }
        inline void DeleteOneLine(int index)
        {
            for(int i=index;i>0;i--)
            {
                for(int j=0;j<screenWidth;j++)
                {
                    map[j][i] = map[j][i-1];
                }
            }
            for(int j=0;j<screenWidth;j++)
            {
                map[j][0] = 0;
            }
        }

};
#endif
RussiaBlock.cpp

#include "RussiaBlock.h"
#include <iostream>

using namespace std;

RussiaBlock::RussiaBlock(unsigned char width, unsigned char height)
{
    gameFail = false;
    screenWidth = width;
    screenHeight= height;
    score       = 0;
    for(int i=0;i != 100;i++)
        for(int j=0;j!=100;j++)
        {
            map[i][j] = 0;
        }
    srand(time(0));
    nextBlock = CreatNewBlock();
    Rotating = false;
}
Block RussiaBlock::CreatNewBlock(void)
{
    short blockShape = 0;
    blockShape = (short)(rand()%8);
    Block newBlock;
    switch(blockShape)
    {
        case 0: newBlock = TianBlock();break;
        case 1: newBlock = LBlock();break;
        case 2: newBlock = TBlock();break;
        case 3: newBlock = FLBlock();break;
        case 4: newBlock = IBlock();break;
        case 5: newBlock = HIBlock();break;
        case 6: newBlock = ZBlock();break;
        case 7: newBlock = FZBlock();break;
    }
    newBlock.shape = blockShape;
    return newBlock;
}
void RussiaBlock::ShowScreen()
{
    system("clear");
    for(int i=0;i<screenWidth+2;i++)
        cout << "_";
    cout <<endl;
    for(int i(0);i<screenHeight;i++)
    {
        cout << "|";
        for(int j(0);j<screenWidth;j++)
        {
            if(map[j][i] == 0) cout<<" ";
            else if(map[j][i] == 1 || map[j][i] == 2) cout<<"#";
            else cout<<map[j][i];
        }
        cout << "|";
        cout<<endl;
    }
    for(int i=0;i<screenWidth+2;i++)
        cout << "-" ;
    cout << endl;
    ShowNextBlock();
    cout << "score:" << score<<endl;
}
void RussiaBlock::ShowNextBlock(void)
{
    bool have = false;
    for(int r=0;r<4;r++)
    {
        for(int c=0;c<4;c++)
        {
            have = false;
            for(int blk=0;blk<4;blk++)
            {
                if(nextBlock.pos[blk].x == c&& nextBlock.pos[blk].y == r)
                {
                    have = true;
                    cout << "#";
                }
            }
            if(have==false) cout<<" ";
        }
        cout << endl;
    }
}
void RussiaBlock::GameStart(void)
{
    pthread_t id_auto,id_key;
    try
    {
        int ret = pthread_create(&id_auto,NULL,&Thread_func,this);
        if(ret != 0) throw runtime_error("start game fail");
        ret = pthread_create(&id_key,NULL,&Thread_Key,this);
        if(ret != 0) throw runtime_error("start game fail");
    }
    catch(runtime_error err)
    {
        cout << err.what() <<endl;
        return;
    }
    gameFail = false;
    while(!gameFail)
    {
        dropToEnd = false;
        currentBlock = nextBlock;
        nextBlock = CreatNewBlock();
        for(int i=0;i<4;i++)
        {
            currentBlock.pos[i].x += (screenWidth/2);
            map[currentBlock.pos[i].x][currentBlock.pos[i].y] = 1;
        }
        while(!dropToEnd)
        {
            if(AtTheEnd())
            {
                dropToEnd = true;
                for(int i=0;i<4;i++)
                    map[currentBlock.pos[i].x][currentBlock.pos[i].y] = 2;
                DeleteLines();
            }
        }
        for(int i=0;i<screenWidth;i++)
        {
            if(map[i][0] == 2)
            {
                gameFail = true;
                break;
            }
        }
    }
    pthread_join(id_auto,NULL);
    pthread_join(id_key,NULL);
    FailNotice();
}
bool RussiaBlock::AtTheEnd(void)
{
    for(int i=0;i<4;i++)
    {
        if(map[currentBlock.pos[i].x][currentBlock.pos[i].y + 1] == 2|| currentBlock.pos[i].y ==screenHeight - 1)
            return true;
    }
    return false;
}
void RussiaBlock::FailNotice(void)
{
    string failStr("Game Over!");
    for(int i=0;i!=failStr.size();i++)
    {
        map[i][screenHeight/2] = failStr[i];
    }
    ShowScreen();
}
void RussiaBlock::KeyOperate(void)
{
    struct input_event ev_key;
    int btn_fd = open("/dev/input/event3",O_RDWR);
    if(btn_fd < 0)
    {
        cerr << btn_fd <<endl;
        cerr << "Game initial fail!" << endl;
        return;
    }
    while(!gameFail)
    {
        int count = read(btn_fd,&ev_key,sizeof(struct input_event));
        //for(int i=0;i<(int)count/sizeof(struct input_event);i++)
        if(EV_KEY == ev_key.type && ev_key.value == 1)
        {
            switch(ev_key.code)
            {
                case KEY_A:MoveLeft();break;
                case KEY_S:DropEnd();break;
                case KEY_D:MoveRight();break;
                case KEY_W:RotateBlock();break;
            }
        }
        ShowScreen();
    }
    close(btn_fd);
}
void RussiaBlock::DeleteLines(void)
{
    for(int i=0;i<screenHeight;i++)
    {
        if(ThisLineIsFull(i))
        {
            DeleteOneLine(i);
            score++;
        }
    }
}
void RussiaBlock::DropEnd(void)
{
    bool getEnd = false;
    while(1)
    {
        for(int i=0;i<4;i++)
        {
            if(map[currentBlock.pos[i].x][currentBlock.pos[i].y + 1] == 2|| currentBlock.pos[i].y ==screenHeight - 1)
            {
                getEnd = true;
                break;
            }
        }
        if(!getEnd)
        {
            for(int i=0;i<4;i++)
            {
                map[currentBlock.pos[i].x][currentBlock.pos[i].y] = 0;
                currentBlock.pos[i].y++;
                map[currentBlock.pos[i].x][currentBlock.pos[i].y] = 1;
            }
        }
        else break;
    }
}
void RussiaBlock::MoveRight(void)
{
    for(int i=0;i<4;i++)
    {
        if(currentBlock.pos[i].x + 1 == screenWidth || map[currentBlock.pos[i].x+1][currentBlock.pos[i].y] == 2)
        {
            return ;
        }
    }
    for(int i=0;i<4;i++)
    {
        map[currentBlock.pos[i].x][currentBlock.pos[i].y] = 0;
        currentBlock.pos[i].x++;
    }
    for(int i=0;i<4;i++)
        map[currentBlock.pos[i].x][currentBlock.pos[i].y] = 1;


}
void RussiaBlock::MoveLeft(void)
{
    for(int i=0;i<4;i++)
    {
        if(currentBlock.pos[i].x - 1 < 0 || map[currentBlock.pos[i].x-1][currentBlock.pos[i].y] == 2)
        {
            return ;
        }
    }
    for(int i=0;i<4;i++)
    {
        map[currentBlock.pos[i].x][currentBlock.pos[i].y] = 0;
        currentBlock.pos[i].x--;
        map[currentBlock.pos[i].x][currentBlock.pos[i].y] = 1;
    }

}
void RussiaBlock::RotateBlock(void)
{
    short blockShape = currentBlock.shape;
    if(blockShape == TIAN_BLOCK) return;
    if(blockShape == I_BLOCK)
    {
        Pos pos[4] = {0};
        for(int i=0;i<4;i++)
        {
            pos[i].y = currentBlock.pos[2].y;
            pos[i].x = currentBlock.pos[2].x + i-1;
        }
        for(int i=0;i<4;i++)
        {
            if(map[pos[i].x][pos[i].y] == 2 || pos[i].y >= screenHeight || pos[i].y < 0 || pos[i].x >= screenWidth || pos[i].x < 0) return ;
        }
        for(int i=0;i<4;i++)
        {
            map[currentBlock.pos[i].x][currentBlock.pos[i].y] = 0;
            currentBlock.pos[i] = pos[i];
            map[currentBlock.pos[i].x][currentBlock.pos[i].y] = 1;
        }
        currentBlock.shape = HI_BLOCK;
        return ;
    }
    if(blockShape == HI_BLOCK)
    {
        Pos pos[4] = {0};
        for(int i=0;i<4;i++)
        {
            pos[i].x = currentBlock.pos[1].x;
            pos[i].y = currentBlock.pos[1].y + i-1;
        }
        for(int i=0;i<4;i++)
        {
            if(map[pos[i].x][pos[i].y] == 2 || pos[i].y >= screenHeight || pos[i].y < 0 || pos[i].x >= screenWidth || pos[i].x < 0) return ;
        }
        for(int i=0;i<4;i++)
        {
            map[currentBlock.pos[i].x][currentBlock.pos[i].y] = 0;
            currentBlock.pos[i] = pos[i];
            map[currentBlock.pos[i].x][currentBlock.pos[i].y] = 1;
        }
        currentBlock.shape = I_BLOCK;
        return ;
    }
    unsigned char maxX = currentBlock.pos[0].x,maxY = currentBlock.pos[0].y,minX = currentBlock.pos[0].x, minY = currentBlock.pos[0].y;
    for(int i=1;i<4;i++)
    {
        if(maxX < currentBlock.pos[i].x) maxX = currentBlock.pos[i].x;
        if(minX > currentBlock.pos[i].x) minX = currentBlock.pos[i].x;
        if(maxY < currentBlock.pos[i].y) maxY = currentBlock.pos[i].y;
        if(minY > currentBlock.pos[i].y) minY = currentBlock.pos[i].y;
    }
    unsigned char X = ((maxX-minX) == 2)?maxX-1:maxX;           
    unsigned char Y = ((maxY-minY) == 2)?maxY-1:maxY;
    unsigned char arr[3][3] = {0};

    short arrX=0,arrY=0;
    for(int i=Y-1;i<=Y+1;i++)
    {
        arrX = 0;
        for(int j=X-1;j<=X+1;j++)
        {
            arr[arrX++][arrY] = map[j][i];
            if(map[j][i] == 2) return ;
        }
        arrY++;
    }
    //转置并换行
    for(int i=0;i<3;i++)
    {
        for(int j = 0;j<=i;j++)
        {
            unsigned char temp = arr[j][i];
            arr[j][i] = arr[i][j];
            arr[i][j] = temp;
        }
    }
    for(int j=0;j<3;j++)
    {
        unsigned char temp = arr[j][0];
        arr[j][0] = arr[j][2];
        arr[j][2] = temp;
    }
    arrY = 0;
    int index = 0;
    for(int i=Y-1;i<=Y+1;i++)
    {
        arrX = 0;
        for(int j=X-1;j<=X+1;j++)
        {
            map[j][i] = arr[arrX++][arrY];
            if(map[j][i] == 1)
            {
                currentBlock.pos[index].x = j;
                currentBlock.pos[index++].y = i;
            }
        }
        arrY++;
    }
}
Block RussiaBlock::TianBlock(void)
{
    Block NewBlock = {0};
    NewBlock.pos[0].x = 0;
    NewBlock.pos[0].y = 0;
    NewBlock.pos[1].x = 1;
    NewBlock.pos[1].y = 0;
    NewBlock.pos[2].x = 0;
    NewBlock.pos[2].y = 1;
    NewBlock.pos[3].x = 1;
    NewBlock.pos[3].y = 1;
    return NewBlock;
}

Block RussiaBlock::LBlock(void)
{
    Block NewBlock = {0};
    NewBlock.pos[0].x = 0;
    NewBlock.pos[0].y = 0;
    NewBlock.pos[1].x = 0;
    NewBlock.pos[1].y = 1;
    NewBlock.pos[2].x = 0;
    NewBlock.pos[2].y = 2;
    NewBlock.pos[3].x = 1;
    NewBlock.pos[3].y = 2;
    return NewBlock;
}
Block RussiaBlock::TBlock(void)
{
    Block NewBlock = {0};
    NewBlock.pos[0].x = 0;
    NewBlock.pos[0].y = 0;
    NewBlock.pos[1].x = 1;
    NewBlock.pos[1].y = 0;
    NewBlock.pos[2].x = 2;
    NewBlock.pos[2].y = 0;
    NewBlock.pos[3].x = 1;
    NewBlock.pos[3].y = 1;
    return NewBlock;
}
Block RussiaBlock::FLBlock(void)
{
    Block NewBlock = {0};
    NewBlock.pos[0].x = 0;
    NewBlock.pos[0].y = 0;
    NewBlock.pos[1].x = 1;
    NewBlock.pos[1].y = 0;
    NewBlock.pos[2].x = 2;
    NewBlock.pos[2].y = 0;
    NewBlock.pos[3].x = 2;
    NewBlock.pos[3].y = 1;
    return NewBlock;
}
Block RussiaBlock::IBlock(void)
{
    Block NewBlock = {0};
    NewBlock.pos[0].x = 0;
    NewBlock.pos[0].y = 0;
    NewBlock.pos[1].x = 0;
    NewBlock.pos[1].y = 1;
    NewBlock.pos[2].x = 0;
    NewBlock.pos[2].y = 2;
    NewBlock.pos[3].x = 0;
    NewBlock.pos[3].y = 3;
    return NewBlock;
}
Block RussiaBlock::HIBlock(void)
{
    Block NewBlock = {0};
    NewBlock.pos[0].x = 0;
    NewBlock.pos[0].y = 0;
    NewBlock.pos[1].x = 1;
    NewBlock.pos[1].y = 0;
    NewBlock.pos[2].x = 2;
    NewBlock.pos[2].y = 0;
    NewBlock.pos[3].x = 3;
    NewBlock.pos[3].y = 0;
    return NewBlock;
}
Block RussiaBlock::ZBlock(void)
{
    Block NewBlock = {0};
    NewBlock.pos[0].x = 0;
    NewBlock.pos[0].y = 0;
    NewBlock.pos[1].x = 1;
    NewBlock.pos[1].y = 0;
    NewBlock.pos[2].x = 1;
    NewBlock.pos[2].y = 1;
    NewBlock.pos[3].x = 2;
    NewBlock.pos[3].y = 1;
    return NewBlock;
}
Block RussiaBlock::FZBlock(void)
{
    Block NewBlock = {0};
    NewBlock.pos[0].x = 1;
    NewBlock.pos[0].y = 0;
    NewBlock.pos[1].x = 2;
    NewBlock.pos[1].y = 0;
    NewBlock.pos[2].x = 0;
    NewBlock.pos[2].y = 1;
    NewBlock.pos[3].x = 1;
    NewBlock.pos[3].y = 1;
    return NewBlock;
}
void *RussiaBlock::Thread_func(void *param)
{
    RussiaBlock *p = (RussiaBlock *)param;
    p->AutoDrop(NULL);
}
void RussiaBlock::AutoDrop(void *ptr)
{
    while(!gameFail)
    {
        int tim = time(0);
        while(tim == time(0)) ;
        DropOneLine();
        ShowScreen();
    }
}
bool RussiaBlock::DropOneLine(void)
{
    for(int i=0;i<4;i++)
    {
        if(map[currentBlock.pos[i].x][currentBlock.pos[i].y + 1] ==2 ||currentBlock.pos[i].y == screenHeight -1)
        {
            return false;
        }
    }
    for(int i=0;i<4;i++)
    {
        map[currentBlock.pos[i].x][currentBlock.pos[i].y] = 0;
        currentBlock.pos[i].y++;
    }
    for(int i=0;i<4;i++)
        map[currentBlock.pos[i].x][currentBlock.pos[i].y] = 1;
    return true;
}
void *RussiaBlock::Thread_Key(void *param)
{
    RussiaBlock *p = (RussiaBlock *)param;
    p->KeyOperate();
}
main.cpp

#include <iostream>
#include "RussiaBlock.h"

using namespace std;

int main()
{
    RussiaBlock blk(10,10);
    blk.GameStart();
    return 0;
}
makefile

RussiaBlock: main.o RussiaBlock.o
    g++ -lpthread main.o RussiaBlock.o -o RussiaBlock
main.o: main.cpp RussiaBlock.h
    g++ -c main.cpp
RussiaBlock.o: RussiaBlock.cpp
    g++ -c RussiaBlock.cpp

这里写图片描述
这里写图片描述
这里写图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值