linux俄罗斯方块程序,Linux下俄罗斯方块程序设计(c++)

f8e997fe648f6050f30039f22667dd8e.png

github地址:https://github.com/fanux/tetris

很多在windows下做的,用的图形图像的库,监听键盘的线程也是封装好的,大家在看我的程序时就会发现,所有东西都是最原始的,相比较而言更原始更原汁原味一点。

接下来我把正个程序一点一点拆开与大家分享。

1:cur.h文件(我们打印图像,自然要移动光标,大家是不是对移动光标很有兴趣?马上教你怎么实现!)#ifndef CUR_H_

#define CUR_H_

#include

using namespace std;

class Cur{

public:

void saveCur();             //保存光标位置

void moveCur(const int x,const int y);  //移动光标位置到(x,y)坐标

void resumeCur();           //恢复光标位置

};

#endif

实现cur.cpp文件void Cur::moveCur(const int x,const int y)

{

int i;

for(i = 0; i 

printf("\33[2C");

for(i = 0; i 

printf("\33[1B");

}

void Cur::saveCur()

{

//save cur and move to destination

printf("\33[s");

}

void Cur::resumeCur()

{

printf("\33[u");

}

是不是移动光标比想象中的简单的多?这样封装起来一旦你的程序中想把光标移到哪就只需要搞一个Cur对象,然后就想在哪打印就在哪打印了。用起来很方便,而且还可以用在其它程序中。

2:cubePoint.h文件,屏幕上怎样打印一个小方块(各种颜色的)?然后我们就用小方块组成我们想要#ifndef CUBEPOINT_H_

#define CUBEPOINT_H_

#include

#include "cur.h"

using namespace std;

enum color{

CLEAR = 0,

BLACK = 30,

RED,

GREEN,

YELLOW,

BLUE,

PURPLE,

DEEP_GREEN,

WHITE

};

/*

* 每个点显然有个坐标值

* 每个点有一个颜色

*/

class CubePoint{

protected:

int color;

int x;

int y; //每个方格点有颜色属性,坐标属性

public:

CubePoint()

{

color = CLEAR;

x = 0;

y = 0;

}

CubePoint(int a,int b,int c)

{

color = a;

x = b;

y = c;

}

void setLocate(const int x,const int y){this->x = x;this->y = y;}

void setColor(const int color){this->color = color;}

int getColor(){return color;}

void getLocate(int&x,int &y){x = this->x;y = this->y;}

//打印点的方法

void printPoint();

};

#endif

实现cubePoint.cpp  我们同样是使用强大的printf函数打印各种各样的点,这里就需要移动光标了!void CubePoint::printPoint()

{

Cur cur;

cur.saveCur();

cur.moveCur(x,y);

switch(color)

{

case BLACK     :printf("\033[40;30m  \033[0m");break;

case RED       :printf("\033[41;31m  \033[0m");break;

case GREEN     :printf("\033[42;32m  \033[0m");break;

case YELLOW    :printf("\033[43;33m  \033[0m");break;

case BLUE      :printf("\033[44;34m  \033[0m");break;

case PURPLE    :printf("\033[45;35m  \033[0m");break;

case DEEP_GREEN:printf("\033[46;36m  \033[0m");break;

case WHITE     :printf("\033[47;37m  \033[0m");break;

case CLEAR     :printf("\033[8m  ");

default:

break;

}

cur.resumeCur();

}

可能很多人没这样用过printf函数吧,赶紧去试试!最后一个CLEAR是擦出,也放到一起了,使用起来也方便~

3:图形工厂闪亮登场!graph.h我每种方块是用一个3X3的数组保存的(所以我的长条形状只有三格长度,不是为了做游戏而做游戏,咱的目的是实现功能,从而更好的了解c++对吧。)#include 

using namespace std;

#include 

#include "cubePoint.h"

#include 

#define DOWN 0

#define LEFT 1

#define RIGHT 2

class Gbase{

protected:

int x;

int y;  //a[0][0]的位置

int a[3][3];

public:

Gbase(){

int i,j;

x = 0;

y = 0;

for(j = 0; j 

for(i = 0; i 

a[i][j] = 0;

}

int move(int dir);

virtual int roll();

virtual void draw(){}

void setLocate(int a,int b){x = a;y = b;}

void getLocate(int* a,int* b){*a = x;*b = y;}

void printG(int color);

//获取数组首地址

void* getArray(){return (void*)a;}

};

class Zgraph : public Gbase{

public:

void draw(){

a[0][0] = 1;

a[0][1] = 1;

a[0][2] = 0;

a[1][0] = 0;

a[1][1] = 1;

a[1][2] = 1;

a[2][0] = 0;

a[2][1] = 0;

a[2][2] = 0;

}

};

class Tgraph : public Gbase{

public:

void draw(){

a[0][0] = 1;

a[0][1] = 1;

a[0][2] = 1;

a[1][0] = 0;

a[1][1] = 1;

a[1][2] = 0;

a[2][0] = 0;

a[2][1] = 0;

a[2][2] = 0;

}

};

class Ograph : public Gbase{

public:

void draw(){

a[0][0] = 1;

a[0][1] = 1;

a[0][2] = 0;

a[1][0] = 1;

a[1][1] = 1;

a[1][2] = 0;

a[2][0] = 0;

a[2][1] = 0;

a[2][2] = 0;

}

virtual int roll(){};

};

class Igraph : public Gbase{

public:

void draw(){

a[0][0] = 0;

a[0][1] = 1;

a[0][2] = 0;

a[1][0] = 0;

a[1][1] = 1;

a[1][2] = 0;

a[2][0] = 0;

a[2][1] = 1;

a[2][2] = 0;

}

};

class Lgraph : public Gbase{

public:

void draw(){

a[0][0] = 0;

a[0][1] = 1;

a[0][2] = 0;

a[1][0] = 0;

a[1][1] = 1;

a[1][2] = 0;

a[2][0] = 0;

a[2][1] = 1;

a[2][2] = 1;

}

};

class Context

{

private:

Gbase* gbase;

public:

~Context()

{

delete gbase;

}

Context(char cType)

{

switch(cType)

{

case 'Z':

gbase = new Zgraph();

break;

case 'T':

gbase = new Tgraph();

break;

case 'O':

gbase = new Ograph();

break;

case 'I':

gbase = new Igraph();

break;

case 'L':

gbase = new Lgraph();

break;

default:

printf("no %c type\n",cType);

break;

}

}

int move(int dir){return gbase->move(dir);}

int roll(){return gbase->roll();}

void draw(){gbase->draw();}

void setLocate(int a,int b){gbase->setLocate(a,b);}

void getLocate(int *a,int* b){gbase->getLocate(a,b);}

void* getArray(){gbase->getArray();}

void printG(int color){gbase->printG(color);}

};

这里用了一个图形的基类Gbase然后五个方块就五个子类(所以你自己想添加新的形状就去继承就可以了)外加一个Context类,这就是一个类似工厂的玩意儿,当然这里还使用到了策略模式。这样我们在处理逻辑的时候就可以将Context类作为接口,不需要关心什么基类子类了,用起来更方便。

实现很简单graph.cppvoid Gbase::printG(int color)

{

int i,j;

CubePoint p;

for(i = x; i 

for(j = y; j 

{

if(a[i - x][j - y] == 1)

{

p.setLocate(i,j);

p.setColor(color);

p.printPoint();

}

}

}

int Gbase::move(int dir)

{

switch(dir)

{

case DOWN:x++;break;

case LEFT:y--;break;

case RIGHT:y++;break;

default:

break;

}

return 0;

}

int Gbase::roll()

{

int i,j;

int b[3][3];

for(i = 0; i 

for(j = 0; j 

{

b[2-j][i] = a[i][j];

}

for(i = 0; i 

for(j = 0; j 

{

a[i][j] = b[i][j];

}

}

到此为止,准备工作基本完成了,现在就可以开始处理逻辑了,我们得把程序跑在面板上

4:game.h#include "graph.h"

class Game

{

private:

int m_penal[24][17];

Context* m_graph;

int x;

int y;//当前方块的位置,方块移动或者旋转成功后才可以设置这个值

private:

//恢复设置(方块会探索下一个位置是否合法,不合法需恢复面板)

bool recoverPenal();

//是否着陆(是否碰到下边)

bool isAttachBottom();

//是否碰到左边

bool isAttachLeft();

//是否碰到右边

bool isAttachRight();

//随机获取方块形状

char getShape();

//用方块数组给面板数组赋值

bool setPenal();

//方块动过后要把遗留面板信息擦除

bool erasePenal();

public:

Game();

//随机创建方块的方法

void createCube();

//移动的方法,移动的过程中对m_penal的改变

void move(int dir);

//旋转的方法。。。

void roll();

//方块停止

void stop();

//擦除满行

void erase();

//擦除完上面的图形整块坠落

void down(int level);

};

实现:要处理的逻辑还是比较多的,但是基本看代码就能看懂,我就直接贴上去了

game.cpp#define PENAL_SIZE (17*24*sizeof(int))

#define CUBE_SIZE (3*3*sizeof(int))

Game::Game()

{

m_graph = NULL;

x = 1;

y = 7;

CubePoint p;

int i;

memset((void*)m_penal,0,PENAL_SIZE);

for(i = 0; i 

{

p.setLocate(i,0);

p.setColor(BLUE);

p.printPoint();

p.setLocate(i,16);

p.setColor(BLUE);

p.printPoint();

m_penal[i][0] = 1;

m_penal[i][16] = 1;

}

for(i = 0; i 

{

p.setLocate(23,i);

p.setColor(BLUE);

p.printPoint();

p.setLocate(0,i);

p.setColor(RED);

p.printPoint();

m_penal[23][i] = 1;

m_penal[0][i] = 1;

}

/*测试面板值是否正常

for(i = 0; i 

{

for(int j = 0; j 

cout <

cout <

}

*/

fflush(stdout);

}

char Game::getShape()

{

Rand r;

char ch;

switch(r.randNum(1,6))

{

case 1:ch = 'Z';break;

case 2:ch = 'T';break;

case 3:ch = 'O';break;

case 4:ch = 'I';break;

case 5:ch = 'L';break;

default:

cout<

ch = '\0';

break;

}

return ch;

}

bool Game::erasePenal()

{

int i,j;

int b[3][3] = {0};  //获取方块数组

m_graph->printG(CLEAR);

memcpy(b,m_graph->getArray(),CUBE_SIZE);

for(i = 0; i 

for(j = 0; j 

{

m_penal[i + x][j + y] -= b[i][j];

}

return true;

}

bool Game::recoverPenal()

{

int i,j;

int b[3][3] = {0};  //获取方块数组

memcpy(b,m_graph->getArray(),CUBE_SIZE);

for(i = x; i 

for(j = y; j 

{

m_penal[i][j] += b[i-x][j-y];

}

return true;

}

bool Game::setPenal()

{

int i,j;

int b[3][3] = {0};  //获取方块数组

m_graph->getLocate(&x,&y);

memcpy(b,m_graph->getArray(),CUBE_SIZE);

/*测试取到方块数组是否正常

for(i = 0;i 

{

for(j = 0; j 

cout<

cout<

}

*/

for(i = x; i 

for(j = y; j 

{

m_penal[i][j] += b[i-x][j-y];

if(m_penal[i][j] > 1)

{

cout<

//加分数统计排行榜等

system("stty icanon echo");

exit(0);

}

}

return true;

}

void Game::createCube()

{

m_graph = new Context(getShape());

m_graph->draw();

m_graph->setLocate(1,7);

setPenal();

m_graph->printG(YELLOW);

/*

for(int i = 0; i 

{

for(int j = 0; j 

cout <

cout <

}

*/

}

void Game::move(int dir)

{

erasePenal();

switch(dir)

{

case DOWN:

if(false == isAttachBottom())

{

m_graph->move(DOWN);

setPenal();

m_graph->printG(YELLOW);

}

else

{

recoverPenal();

m_graph->printG(YELLOW);

erase();

stop();

}

break;

case LEFT:

if(false == isAttachLeft())

{

m_graph->move(LEFT);

setPenal();

m_graph->printG(YELLOW);

}

else

{

recoverPenal();

m_graph->printG(YELLOW);

}

break;

case RIGHT:

if(false == isAttachRight())

{

m_graph->move(RIGHT);

setPenal();

m_graph->printG(YELLOW);

}

else

{

recoverPenal();

m_graph->printG(YELLOW);

}

break;

default:

break;

}

}

void Game::roll()

{

//取出方块的值,先放到一个数组中

int i,j;

int flag = 0;

int b[3][3] = {0};  //获取方块数组

int temp[3][3] = {0};

m_graph->getLocate(&x,&y);

memcpy(b,m_graph->getArray(),CUBE_SIZE);

erasePenal();

//旋转数组

for(i = 0; i 

for(j = 0; j 

{

temp[2-j][i] = b[i][j];

}

//判断旋转后是否会与面板重合

for(i = 0; i 

{

for(j = 0; j 

{

if (temp[i][j] == 1 && m_penal[x + i][y + j] == 1)

{

flag = 1;

break;

}

}

if(flag == 1)

break;

}

//如果不重合则旋转方块,设置面板的值

if(flag == 0)

{

m_graph->roll();

}

setPenal();

m_graph->printG(YELLOW);

}

void Game::stop()

{

delete m_graph;

createCube();

}

bool Game::isAttachBottom()

{

int i,j;

int cube_x,cube_y;

int b[3][3] = {0};  //获取方块数组

int flag = false;

m_graph->getLocate(&cube_x,&cube_y);

memcpy(b,m_graph->getArray(),CUBE_SIZE);

for(i = 0; i 

{

for(j = 0; j 

{

if (b[i][j] == 1 && m_penal[i + cube_x + 1][j + cube_y] == 1)

{

flag = true;

break;

}

}

if (flag == true)

break;

}

return flag;

}

bool Game::isAttachLeft()

{

int i,j;

int cube_x,cube_y;

int b[3][3] = {0};  //获取方块数组

int flag = false;

m_graph->getLocate(&cube_x,&cube_y);

memcpy(b,m_graph->getArray(),CUBE_SIZE);

for(i = 0; i 

{

for(j = 0; j 

{

if (b[i][j] == 1 && m_penal[i + cube_x][j + cube_y - 1] == 1)

{

flag = true;

break;

}

}

if (flag == true)

break;

}

return flag;

}

bool Game::isAttachRight()

{

int i,j;

int cube_x,cube_y;

int b[3][3] = {0};  //获取方块数组

int flag = false;

m_graph->getLocate(&cube_x,&cube_y);

memcpy(b,m_graph->getArray(),CUBE_SIZE);

for(i = 0; i 

{

for(j = 0; j 

{

if (b[i][j] == 1 && m_penal[i + cube_x][j + cube_y + 1] == 1)

{

flag = true;

break;

}

}

if (flag == true)

break;

}

return flag;

}

void Game::erase()

{

int i,j;

int flag = 0;

for(i = 22; i > 0; i--)

{

for(j = 1; j 

{

if(m_penal[i][j] == 0)

{

flag = 1;

}

}

if(flag == 0)

{

//该行上面的图形整体坐落

down(i);

i++;

}

flag = 0;

}

}

void Game::down(int level)

{

int i,j;

int flag = 1;

for(i = level; i > 1; i--)

for(j = 1; j 

{

m_penal[i][j] = m_penal[i - 1][j];

}

//刷新面板

CubePoint p;

for(i = 1; i 

for(j = 1; j 

{

if(m_penal[i][j] == 1)

{

p.setLocate(i,j);

p.setColor(YELLOW);

p.printPoint();

}

if(m_penal[i][j] == 0)

{

p.setLocate(i,j);

p.setColor(CLEAR);

p.printPoint();

}

}

}

5:main函数:void* listenKey(void *key)

{

char* key_;

key_ = (char*)key;

while(1)

{

system("stty -icanon -echo");

*key_ = getchar();

system("stty icanon echo");

}

}

int main()

{

pthread_t t1;

char key;

system("clear");

Game g;

g.createCube();

key = 's';

pthread_create(&t1,NULL,listenKey,(void*)(&key));

while(1)

{

fflush(stdout);

usleep(500000);

switch(key)

{

case 's':

g.move(DOWN);break;

case 'a':

g.move(LEFT);key = 's';break;

case 'd':

g.move(RIGHT);key = 's';break;

case 'w':

g.roll();key = 's';break;

default:

g.move(DOWN);break;

}

g.move(DOWN);

}

return 0;

}

这里要注意看我是怎么设置无输入缓存的!很多人无法做出来就是卡在这了(stty -icanon -echo)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值