您的位置:首页 > 运维架构 > Linux

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

2016-07-10 14:55 781 查看
我最近在看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






内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息