很多在windows下做的,用的图形图像的库,监听键盘的线程也是封装好的,大家在看我的程序时就会发现,所有东西都是最原始的,相比较而言更原始更原汁原味一点。
接下来我把正个程序一点一点拆开与大家分享。
1:cur.h文件(我们打印图像,自然要移动光标,大家是不是对移动光标很有兴趣?马上教你怎么实现!)
1
2
3
4
5
6
7
8
9
10
11
#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文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void Cur::moveCur(const int x,const int y)
{
int i;
for(i = 0; i < y; i++)
printf("\33[2C");
for(i = 0; i < x; 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文件,屏幕上怎样打印一个小方块(各种颜色的)?然后我们就用小方块组成我们想要
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#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函数打印各种各样的点,这里就需要移动光标了!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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++对吧。)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#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 < 3; j++)
for(i = 0; i < 3; 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.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
void Gbase::printG(int color)
{
int i,j;
CubePoint p;
for(i = x; i < x+3; i++)
for(j = y; j < y+3; 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 < 3; i++)
for(j = 0; j < 3; j++)
{
b[2-j][i] = a[i][j];
}
for(i = 0; i < 3; i++)
for(j = 0; j < 3; j++)
{
a[i][j] = b[i][j];
}
}
到此为止,准备工作基本完成了,现在就可以开始处理逻辑了,我们得把程序跑在面板上
4:game.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
#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 < 24; 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 < 17; 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 < 24; i++)
{
for(int j = 0; j < 17; j++)
cout << m_penal[i][j] <<" ";
cout << endl;
}
*/
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<<"no this shape type"<
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 < 3; i++)
for(j = 0; j < 3; 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 < x + 3; i++)
for(j = y; j < y + 3; 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 < 3; i++)
{
for(j = 0; j < 3; j++)
cout<
cout<
}
*/
for(i = x; i < x + 3; i++)
for(j = y; j < y + 3; j++)
{
m_penal[i][j] += b[i-x][j-y];
if(m_penal[i][j] > 1)
{
cout<<"game over"<
//加分数统计排行榜等
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 < 24; i++)
{
for(int j = 0; j < 17; j++)
cout << m_penal[i][j] <<" ";
cout << endl;
}
*/
}
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 < 3; i++)
for(j = 0; j < 3; j++)
{
temp[2-j][i] = b[i][j];
}
//判断旋转后是否会与面板重合
for(i = 0; i < 3; i++)
{
for(j = 0; j < 3; 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 < 3; i++)
{
for(j = 0; j < 3; 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 < 3; i++)
{
for(j = 0; j < 3; 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 < 3; i++)
{
for(j = 0; j < 3; 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 < 16; 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 < 16; j++)
{
m_penal[i][j] = m_penal[i - 1][j];
}
//刷新面板
CubePoint p;
for(i = 1; i < 23; i++)
for(j = 1; j < 16; 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函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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;
}
阅读(1336) | 评论(0) | 转发(0) |