我最近在看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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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;iif(map[i][index] == 0)
return false;
}
return true;
}
inline void DeleteOneLine(int index)
{
for(int i=index;i>0;i--)
{
for(int j=0;jmap[j][i] = map[j][i-1];
}
}
for(int j=0;jmap[j][0] = 0;
}
}
};
#endif
RussiaBlock.cpp
#include "RussiaBlock.h"
#include
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;i2;i++)
cout << "_";
cout <for(int i(0);i"|";
for(int j(0);jif(map[j][i] == 0) cout<<" ";
else if(map[j][i] == 1 || map[j][i] == 2) cout<<"#";
else cout<<map[j][i];
}
cout << "|";
cout<for(int i=0;i2;i++)
cout << "-" ;
cout << endl;
ShowNextBlock();
cout << "score:" << score<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() <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;iif(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 <"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;iif(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
#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