-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.cpp
377 lines (375 loc) · 8.14 KB
/
main.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
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
/*备忘录:
* 170注释了一行代码
*/
#include"block.h"
#include"wall.h"
#include<Windows.h>//引入system(),Sleep()
#include<conio.h>//引入_kbhit(),_getch()函数
#include<ctime>//引入time()函数
#include<cstdlib>//引入rand(),srand()函数
using namespace std;
void hideCursor()
{
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
GetConsoleCursorInfo(hOut, &cci);
cci.bVisible = FALSE;
SetConsoleCursorInfo(hOut, &cci);
}
Block* newBlock(bool cmd)
{
srand(time(NULL));
switch (rand() % 7)
{
case 0:
return new Square(cmd);
case 1:
return new Stick(cmd);
case 2:
return new LeftCane(cmd);
case 3:
return new RightCane(cmd);
case 4:
return new LeftLightning(cmd);
case 5:
return new RightLightning(cmd);
case 6:
return new Hill(cmd);
}
}
//由于设置难度等级和难度时间的代码冗长,这里专门封装成函数,使主函数代码简洁,结构清晰
void setLevel(short point,short& level)
{
if (point < 120)
level = 1;
else if (point < 500)
level = 2;
else if (point < 1000)
level = 3;
else if (point < 2000)
level = 4;
else if (point < 4000)
level = 5;
else if (point < 8000)
level = 6;
else if (point < 15000)//放缓
level = 7;
else if (point < 20000)
level = 8;
else if (point < 28000)
level = 9;
else if (point < 32000)
level = 10;
}
void setDifficultTime(short level, int& difficultTime)
{
switch (level)
{
case 2:
difficultTime = 235;
break;
case 3:
difficultTime = 215;
break;
case 4:
difficultTime = 180;
break;
case 5:
difficultTime = 150;
break;
case 6:
difficultTime = 120;
break;
case 7:
difficultTime = 105;
break;
case 8:
difficultTime = 95;
break;
case 9:
difficultTime = 80;
break;
case 10:
difficultTime = 70;
break;
}
}
/*俄罗斯方块游戏内用到的公式
* point = level * 5 * 消除行数
*/
//Sleep()函数内参数
int reactionTime = 10;//反应时间
int difficultyTime = 300;//难度时间
int animationTime = 80;//动画时间
int flowTime = 30;//方块移动下落时适当停顿的节奏感时间
//算分公式:行数*10 后续可考虑再把速度加入进去
int main()
{
//-------------------------------------------------------------------------------------搭建游戏界面
system("mode con cols=60 lines=38");//控制台大小
system("title 俄罗斯方块");//控制台标题
hideCursor();//隐藏光标
Wall framework(5, 56, 3, 30);//游戏界面框
gotoxy(15, 3);
cout << "Welcome To The NINJA88888 World";//水印
Wall displayBox(11, 34, 6, 27);//游戏显示框
//铺设游戏背景
for (short i = 7; i < 27; i++)
{
gotoxy(13, i);
cout << "□□□□□□□□□□";
}
Block::setWall(displayBox);//将游戏显示框的信息赋值给Block类的静态成员
//储存已销行数
short erasedLine = 0;
//储存得分
short point = 0;
gotoxy(39, 7);
cout << "得分";
gotoxy(48, 9);
cout << point;
//储存已消行数
short line = 0;
gotoxy(39, 11);
cout << "已消行数";
gotoxy(48, 13);
cout << line;
//储存难度等级
short level = 1;
gotoxy(39, 15);
cout << "难度等级";
gotoxy(48, 17);
cout << level;
gotoxy(39, 19);
cout << "下个方块";
gotoxy(43, 21);
cout << "□□□□";
gotoxy(43, 22);
cout << "□□□□";
//打印游戏按键提示
gotoxy(15, 32);
cout << "(↑)旋转";
gotoxy(9, 34);
cout << "(←)左移 (→)右移";
gotoxy(15, 36);
cout << "(↓)下移";
gotoxy(35, 32);
cout << "(P)暂停 (R)重新开始";
gotoxy(40, 35);
cout << "(空格)落地";
//-------------------------------------------------------------------------------------游戏内容
char cmd = ' ';//储存用户输入命令
Block* block = newBlock(true);//储存当前方块
Block* preblock = newBlock(false);//储存下一个方块
preblock->print(Coordinate(43, 21));//游戏刚开始时先提示下个方块
//-------------------------------------------游戏主体
newGame:
while (1)
{
playing:
for (short i = 0; i < 5; i++)//最多处理三次用户键入
{
if (_kbhit())
{
cmd = _getch();
switch (cmd)
{
case ' ':
block->translation(' ');
goto computing;//直接进入处理
case 'p'://包括大写和小写
case 'P':
gotoxy(39, 24);
cout << "(游戏暂停中)";
while (1)//这里建立一个死循环,仅在用户按下按键,且键入为p时结束循环
{
if (_kbhit())
{
cmd = _getch();
if (cmd == 'p' || cmd == 'P')//包括大写和小写
{
break;
}
}
}
gotoxy(39, 24);
cout << " ";
break;
case -32://方向键情况
switch (cmd = _getch())
{
case 75:
block->translation('a');
Sleep(3 * flowTime);
break;
case 72:
block->rotation();
Sleep(3 * flowTime);
break;
case 77:
block->translation('d');
Sleep(3 * flowTime);
break;
case 80:
for (short i = 0; i < 3; i++)//一口气下落三次
{
if (!block->crash())
{
Sleep(flowTime);//限制下落速度,给用户顿挫感
block->fall();
}
}
break;
}
break;
}
}
}
computing:
while (_kbhit())
{
_getch();
}
//键入循环结束后,统一执行下面代码,不碰撞则下落,碰撞则进行融合等操作
if (!block->crash())//不碰撞
{
Sleep(difficultyTime);//控制下落速度,控制难度
block->fall();
}
else//发生碰撞
{
if (block->isOver())
{
break;//唯一游戏内容退出口
}
if (cmd != ' ')//如果是空格指令下来的,则不执行下面代码
{
for (int i = 0; i < 10; i++)//判断是碰撞后允许至多5次平移
{
Sleep(3 * reactionTime);//给用户键入反应时间,这里给更多时间反应
if (_kbhit())
{
cmd = _getch();
if (cmd == -32)
{
cmd = _getch();
switch (cmd)
{
case 75:
block->translation('a');
break;
case 77:
block->translation('d');
break;
}
}
}
}
if (!block->crash())//如果结果刚刚的平移后,方块不会发生碰撞了,则转移到键入时代码
{
goto playing;
}
}
//这里的顺序很有讲究,必须按先融合,再刷新,最后删方块的顺序执行代码
block->mix();
//刷新已消行数
erasedLine = block->eraseLine();
//刷新分数
point += level * 10 * erasedLine;
gotoxy(48, 9);
cout << point;
//刷新已消行数
line += erasedLine;
gotoxy(48, 13);
cout << line;
//依据分数刷新等级
setLevel(point, level);
gotoxy(48, 17);
cout << level;
//刷新难度时间
setDifficultTime(level, difficultyTime);
delete block;//删除方块
block = preblock;
block->print();
preblock = newBlock(false);
preblock->print(Coordinate(43, 21));
}
}
//-------------------------------------------------------------------------------------游戏结束
//清理上局内容
//分数等变量会在上面重新赋值,故不需要在这里刷新
delete block;
delete preblock;
Block::resetGround();
for (int lines = 26; lines > 6; lines--)//游戏结束动画
{
gotoxy(13, lines);
cout << "■■■■■■■■■■";
Sleep(animationTime);
}
for (int lines = 7; lines < 27; lines++)//游戏结束动画
{
gotoxy(13, lines);
cout << "□□□□□□□□□□";
Sleep(animationTime);
}
//改变部分游戏画面
gotoxy(39, 7);
cout << "上局最终得分";
gotoxy(19, 16);
cout << "游戏结束";
while (1)//这里建立一个死循环,仅在用户按下按键,且键入为r时结束循环
{
Sleep(reactionTime);
if (_kbhit())
{
cmd = _getch();
if (cmd == 'r' || cmd == 'R')//包括大写和小写
{
break;//进入准备新一轮阶段
}
}
}
//收拾画面,为新一轮做好准备
//先收拾画面
gotoxy(39, 7);
cout << " ";
for (short i = 7; i < 27; i++)
{
gotoxy(13, i);
cout << "□□□□□□□□□□";
}
//再收拾变量
//分数
point = 0;
gotoxy(39, 7);
cout << "得分";
gotoxy(48, 9);
cout << " ";//收拾上局残余的数字
gotoxy(48, 9);
cout << point;
//已消行数
line = 0;
gotoxy(48, 13);
cout << " ";//收拾上局残余的数字
gotoxy(48, 13);
cout << line;
//难度等级
level = 1;
gotoxy(48, 17);
cout << " ";//收拾上局残余的数字
gotoxy(48, 17);
cout << level;
gotoxy(39, 19);
cout << "下个方块";
gotoxy(43, 21);
cout << "□□□□";
gotoxy(43, 22);
cout << "□□□□";
//最后准备好方块
block = newBlock(true);
preblock = newBlock(false);
preblock->print(Coordinate(43, 21));
goto newGame;
return 0;
}