初始化页面
# include <stdio.h> # include <graphics.h> // 欢迎界面 void welcome() { // 初始化画布 initgraph(550, 660); // 设置窗口标题 HWND window = GetHWnd(); //获取窗口 SetWindowText(window, _T("俄罗斯方块")); //设置窗口标题 // 设置文本的字体样式 setfont(40, 0, _T("微软雅黑")); //设置文字样式(0表示自适应) setcolor(WHITE); outtextxy(205, 200, _T("俄罗斯方块")); setfont(22, 0, _T("楷体")); outtextxy(150, 300, _T("适度游戏益脑,沉迷游戏伤身")); Sleep(3000); //睡眠(暂停)3000毫秒,3秒针 }
初始化游戏环境
int score = 0; // 总分 int rank = 0; //等级 // 初始化游戏场景 void initGameScene() { char str[16]; cleardevice(); setcolor(WHITE); rectangle(29, 29, 334, 633); rectangle(27, 27, 336, 635); rectangle(370, 50, 515, 195); setfont(24, 0, _T("楷体")); setcolor(LIGHTGRAY); outtextxy(405, 215, _T("下一个:")); setcolor(RED); outtextxy(405, 280, _T("分数:")); sprintf(str, "%d", score); outtextxy(415, 310, str); outtextxy(405, 375, _T("等级:")); sprintf(str, "%d", rank); outtextxy(425, 405, str); setfont(22, 0, _T("楷体")); setcolor(LIGHTBLUE); outtextxy(390, 475, _T("操作说明:")); outtextxy(390, 500, _T("↑: 旋转")); outtextxy(390, 525, _T("↓: 下降")); outtextxy(390, 550, _T("←: 左移")); outtextxy(390, 575, _T("→: 右移")); outtextxy(390, 600, _T("空格: 暂停")); }
新方块
#define BLOCK_COUNT 5 #define BLOCK_WIDTH 5 #define BLOCK_HEIGHT 5 #define UNIT_SIZE 20 //小砖块的宽度和高度 int color[BLOCK_COUNT] = { GREEN,CYAN,MAGENTA,BROWN,YELLOW }; int NextIndex = -1; int block[BLOCK_COUNT * 4][BLOCK_HEIGHT][BLOCK_WIDTH] = { // | 形方块 { 0,0,0,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,0,0,0, 0,1,1,1,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,0,0,0, 0,1,1,1,0, 0,0,0,0,0, 0,0,0,0,0 }, // L 形方块 { 0,0,0,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,1,1,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,0,0,0, 0,1,1,1,0, 0,1,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,1,1,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,0,1,0, 0,1,1,1,0, 0,0,0,0,0, 0,0,0,0,0 }, // 田 形方块 { 0,0,0,0,0, 0,1,1,0,0, 0,1,1,0,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,1,1,0,0, 0,1,1,0,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,1,1,0,0, 0,1,1,0,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,1,1,0,0, 0,1,1,0,0, 0,0,0,0,0, 0,0,0,0,0 }, // T 形方块 { 0,0,0,0,0, 0,1,1,1,0, 0,0,1,0,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,0,1,0, 0,0,1,1,0, 0,0,0,1,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,1,0,0, 0,1,1,1,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,1,0,0,0, 0,1,1,0,0, 0,1,0,0,0, 0,0,0,0,0 }, // Z 形方块 { 0,0,0,0,0, 0,1,1,0,0, 0,0,1,1,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,1,0,0, 0,1,1,0,0, 0,1,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,1,1,0,0, 0,0,1,1,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,1,0,0, 0,1,1,0,0, 0,1,0,0,0, 0,0,0,0,0 }, }; //清除右上角提示区方块 void clearBlock() { setcolor(BLACK); setfont(23, 0, "楷体"); for (int i = 0; i < BLOCK_HEIGHT; i++) { for (int j = 0; j < BLOCK_WIDTH; j++) { //"■" int x = 391 + j * UNIT_SIZE; int y = 71 + i * UNIT_SIZE; outtextxy(x, y, "■"); } } } //绘制方块 void drawBlock(int x, int y) { setcolor(color[NextIndex]); setfont(23, 0, "楷体"); for (int i = 0; i < BLOCK_HEIGHT; i++) { for (int j = 0; j < BLOCK_WIDTH; j++) { //"■" if (block[NextIndex * 4][i][j] == 1) { int x2 = x + j * UNIT_SIZE; int y2 = y + i * UNIT_SIZE; outtextxy(x2, y2, "■"); } } } } //右上角提示区显示下一个方块 void nextblock() { clearBlock(); //清除右上角区域 //随机选择一种方块 srand(time(NULL)); //使用时间函数的返回值,来作为随机种子 NextIndex = rand() % BLOCK_COUNT; drawBlock(391, 71); }
降落方块
使用访问数组来确定是否有方块
int visit[30][15], Color[30][15]; // visit[i][j] == 1 表示该位置有方块
新方块降落
int BlockIndex = -1; //当前方块的种类 //新方块降落 void newblock() { //确定即将使用的方块的类别 BlockIndex = NextIndex; //绘制刚从顶部下降的方块 drawBlock(START_X, START_Y); //让新出现的方块暂停一会,让用户识别到 Sleep(100); //0.1秒 //在右上角区域,绘制下一个方块 nextblock(); //方块降落 move(); }
方块降落
#define START_X 130 #define START_Y 30 #define KEY_UP 72 #define KEY_RIGHT 77 #define KEY_DOWN 80 #define KEY_LEFT 75 #define KEY_SPACE 32 int speed = 500; int minX = 30; int minY = 30; int markColor[30][15]; //表示对应位置的颜色 typedef enum { BLOCK_UP, BLOCK_RIGHT, BLOCK_DOWN, BLOCK_LEFT } block_dir_t; typedef enum { MOVE_DOWN, MOVE_LEFT, MOVE_RIGHT } move_dir_t; //调整下降速度 void wait(int interval) { int count = interval / 10; for (int i = 0; i < count; i++) { Sleep(10); if (kbhit()) { return; } } } //标记已到位的方块 void mark(int x, int y, int blockIndex, block_dir_t dir) { int id = blockIndex * 4 + dir; int x2 = (y - minY) / 20; int y2 = (x - minX) / 20; for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { if (block[id][i][j] == 1) { visit[x2 + i][y2 + j] = 1; markColor[x2 + i][y2 + j] = color[blockIndex]; } } } } //如果在指定位置可以向指定方向移动,就返回1, 否则就返回0 int moveable(int x0, int y0, move_dir_t moveDir, block_dir_t blockDir) { //计算当前方块的左上角在30x15的游戏区中的位置(第多少行,第多少列) int x = (y0 - minY) / UNIT_SIZE; int y = (x0 - minX) / UNIT_SIZE; int id = BlockIndex * 4 + blockDir; int ret = 1; if (moveDir == MOVE_DOWN) { for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { if (block[id][i][j] == 1 && (x + i + 1 >= 30 || visit[x + i + 1][y + j] == 1)) { ret = 0; } } } } else if (moveDir == MOVE_LEFT) { for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { if (block[id][i][j] == 1 && (y + j == 0 || visit[x + i][y + j - 1] == 1)) { ret = 0; } } } } else if (moveDir == MOVE_RIGHT) { for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { if (block[id][i][j] == 1 && (y + j + 1 >= 15 || visit[x + i][y + j + 1] == 1)) { ret = 0; } } } } return ret; } //判断当前方块是否可以转向到指定方向 //注意,此时还没有转到该方向!!! int rotatable(int x, int y, block_dir_t dir) { int id = BlockIndex * 4 + dir; int xIndex = (y - minY) / 20; int yIndex = (x - minX) / 20; if (!moveable(x, y, MOVE_DOWN, dir)) { return 0; } for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { if (block[id][i][j] == 1 && (yIndex + j < 0 || yIndex + j >= 15 || visit[xIndex + i][yIndex + j] == 1)) { return 0; } } } return 1; } //方块降落 void move() { int x = START_X; int y = START_Y; int k = 0; block_dir_t blockDir = BLOCK_UP; int curSpeed = speed; //检测游戏是否结束 failCheck(); //持续向下降落 while (1) { if (kbhit()) { int key = getch(); if (key == KEY_SPACE) { getch(); } } //清除当前方块 clearBlock(x, k, blockDir); if (kbhit()) { int key = getch(); if (key == KEY_UP) { block_dir_t nextDir = (block_dir_t)((blockDir + 1) % 4); if (rotatable(x, y + k, nextDir)) { blockDir = nextDir; } } else if (key == KEY_DOWN) { curSpeed = 50; } else if (key == KEY_LEFT) { if (moveable(x, y + k + 20, MOVE_LEFT, blockDir)) { x -= 20; } } else if (key == KEY_RIGHT) { if (moveable(x, y + k + 20, MOVE_RIGHT, blockDir)) { x += 20; //x = x + 20; } } } k += 20; //绘制当前方块 drawBlock(x, y + k, BlockIndex, blockDir); wait(curSpeed); //下降速度 //方块的“固化”处理 if (!moveable(x, y + k, MOVE_DOWN, blockDir)) { mark(x, y + k, BlockIndex, blockDir); break; } } }
检测结果
//消除第x行,并把上面的行都下移 void down(int x) { for (int i = x; i > 0; i--) { //消除第i行,第j列的方格消除 for (int j = 0; j < 15; j++) { if (visit[i - 1][j]) { visit[i][j] = 1; markColor[i][j] = markColor[i - 1][j]; setcolor(markColor[i][j]); outtextxy(20 * j + minX, 20 * i + minY, "■"); } else { visit[i][j] = 0; setcolor(BLACK); outtextxy(20 * j + minX, 20 * i + minY, "■"); } } } //清除最顶上的哪一行(就是行标为0的那一行) setcolor(BLACK); for (int j = 0; j < 15; j++) { visit[0][j] = 0; outtextxy(20 * j + minX, minY, "■"); } } //更新分数,参数lines表示消除的行数 void addScore(int lines) { char str[32]; setcolor(RED); score += lines * 10; sprintf(str, "%d", score); outtextxy(415, 310, str); } //更新等级的提示 void updateGrade() { //假设:50分一级 rank = score / 50; char str[16]; sprintf(str, "%d", rank); outtextxy(425, 405, str); //更新速度, 等级越高,速度越快,speed越小! //最慢:500, 最快是100 speed = 500 - rank * 100; if (speed <= 100) { speed = 100; } } //检查是否有行可以消除 void check() { int i, j; int clearLines = 0; for (i = 29; i >= 0; i--) { //检查第i行有没有满 for (j = 0; j < 15 && visit[i][j]; j++); //执行到此处时,有两种情况: // 1. 第i行没有满,即表示有空位 此时 j<15 // 2. 第i行已满了,此时 j>=15 if (j >= 15) { //此时,第i行已经满了,就需要消除第i行 down(i); //消除第i行,并把上面的行都下移 i++; //因为最外层的循环中有 i--, 所以我们先i++, 使得下次循环时,再把这一行检查一下 clearLines++; } } //更新分数 addScore(clearLines); //更新等级(更新等级提示,更新速度) updateGrade(); }
全部代码
info.h
#pragma once #include "block.h" #define BLOCK_COUNT 5 #define BLOCK_WIDTH 5 #define BLOCK_HEIGHT 5 int block[BLOCK_COUNT * 4][BLOCK_HEIGHT][BLOCK_WIDTH] = { // | 型方块 { 0,0,0,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,0,0,0, 0,1,1,1,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,0,0,0, 0,1,1,1,0, 0,0,0,0,0, 0,0,0,0,0 }, // L 形方块 { 0,0,0,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,1,1,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,0,0,0, 0,1,1,1,0, 0,1,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,1,1,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,0,1,0, 0,1,1,1,0, 0,0,0,0,0, 0,0,0,0,0 }, // 田 形方块 { 0,0,0,0,0, 0,1,1,0,0, 0,1,1,0,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,1,1,0,0, 0,1,1,0,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,1,1,0,0, 0,1,1,0,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,1,1,0,0, 0,1,1,0,0, 0,0,0,0,0, 0,0,0,0,0 }, // T 形方块 { 0,0,0,0,0, 0,1,1,1,0, 0,0,1,0,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,0,1,0, 0,0,1,1,0, 0,0,0,1,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,1,0,0, 0,1,1,1,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,1,0,0,0, 0,1,1,0,0, 0,1,0,0,0, 0,0,0,0,0 }, // Z 形方块 { 0,0,0,0,0, 0,1,1,0,0, 0,0,1,1,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,1,0,0, 0,1,1,0,0, 0,1,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,1,1,0,0, 0,0,1,1,0, 0,0,0,0,0, 0,0,0,0,0 }, { 0,0,0,0,0, 0,0,1,0,0, 0,1,1,0,0, 0,1,0,0,0, 0,0,0,0,0 } };
block.h
#pragma once #include <stdio.h> #include <graphics.h> #include <time.h> #include <conio.h> //kbhit()使用 #include "info.h" int score = 0; //总分 int rank = 0; //等级 #define UNIT_SIZE 20 #define START_X 130 #define START_Y 30 #define KEY_UP 72 #define KEY_RIGHT 77 #define KEY_DOWN 80 #define KEY_LEFT 75 #define KEY_SPACE 32 int speed = 500; int minX = 30; int minY = 30; typedef enum { BLOCK_UP, BLOCK_RIGHT, BLOCK_DOWN, BLOCK_LEFT } block_dir_t; typedef enum { MOVE_DOWN, MOVE_LEFT, MOVE_RIGHT } move_dir_t; int NextIndex = -1; //下一个方块的种类 int BlockIndex = -1; //当前方块的种类 int color[BLOCK_COUNT] = { GREEN, CYAN, MAGENTA, BROWN, YELLOW }; int visit[30][15]; //访问数组 int markColor[30][15]; //表示对应位置的颜色 //欢迎界面 void welcome(); //初始化游戏场景 void initGameScene(); //绘制方块 void drawBlock(int x, int y); //绘制方块: 在指定位置绘制指定方块的指定方向 void drawBlock(int x, int y, int blockIndex, block_dir_t dir); //清除指定位置指定方向的方块 //参数x: 方块的左上角的x坐标 //参数y: 方块的左上角在游戏区域内的坐标,距离游戏区域顶部的距离 void clearBlock(int x, int y, block_dir_t dir); //右上角提示区显示下一个方块 void nextblock(); //如果在指定位置可以向指定方向移动,就返回1, 否则就返回0 int moveable(int x0, int y0, move_dir_t moveDir, block_dir_t blockDir); //检测游戏是否结束 void failCheck(); //判断当前方块是否可以转向到指定方向 //注意,此时还没有转到该方向!!! int rotatable(int x, int y, block_dir_t dir); //调整下降速度 void wait(int interval); //标记已到位的方块 void mark(int x, int y, int blockIndex, block_dir_t dir); //方块降落 void move(); //新方块降落 void newblock(); //消除第x行,并把上面的行都下移 void down(int x); //更新分数,参数lines表示消除的行数 void addScore(int lines); //更新等级的提示 void updateGrade(); //检查是否有行可以消除 void check();
block.cpp
#include "block.h" int main() { welcome(); initGameScene(); //产生新方块 nextblock(); Sleep(500); //初始化访问数组 memset(visit, 0, sizeof(visit)); while (1) { newblock(); //消除满行,并更新分数和速度 check(); } system("pause"); closegraph(); return 0; } //欢迎界面 void welcome() { //初始化画布 initgraph(550, 660); //设置窗口标题 HWND window = GetHWnd(); //获取窗口 SetWindowText(window, _T("俄罗斯方块")); //设置窗口标题 //设置文本的字体样式 setfont(40, 0, _T("微软雅黑")); setcolor(WHITE); outtextxy(205, 200, _T("俄罗斯方块")); setfont(22, 0, _T("楷体")); outtextxy(150, 300, _T("适度游戏益脑,沉迷游戏伤身")); Sleep(3000); //睡眠(暂停)3000毫秒,3秒针 } //初始化游戏场景 void initGameScene() { char str[16]; //清除屏幕 cleardevice(); rectangle(27, 27, 336, 635); rectangle(29, 29, 334, 633); rectangle(370, 50, 515, 195); setfont(24, 0, _T("楷体")); setcolor(LIGHTGRAY); outtextxy(405, 215, _T("下一个")); setcolor(RED); outtextxy(405, 280, _T("分数")); sprintf(str, "%d", score); outtextxy(415, 310, str); outtextxy(405, 375, _T("等级")); sprintf(str, "%d", rank); outtextxy(425, 405, str); //操作说明 ↑ ↓ ← → setcolor(LIGHTBLUE); outtextxy(390, 475, "操作说明"); outtextxy(390, 500, "↑:旋转"); outtextxy(390, 525, "↓: 下降"); outtextxy(390, 550, "←: 左移"); outtextxy(390, 575, "→: 右移"); outtextxy(390, 600, "空格:暂停"); } //清除右上角提示区方块 void clearBlock() { setcolor(BLACK); setfont(23, 0, "楷体"); for (int i = 0; i < BLOCK_HEIGHT; i++) { for (int j = 0; j < BLOCK_WIDTH; j++) { //"■" int x = 391 + j * UNIT_SIZE; int y = 71 + i * UNIT_SIZE; outtextxy(x, y, "■"); } } } //绘制方块 void drawBlock(int x, int y) { setcolor(color[NextIndex]); setfont(23, 0, "楷体"); for (int i = 0; i < BLOCK_HEIGHT; i++) { for (int j = 0; j < BLOCK_WIDTH; j++) { //"■" if (block[NextIndex * 4][i][j] == 1) { int x2 = x + j * UNIT_SIZE; int y2 = y + i * UNIT_SIZE; outtextxy(x2, y2, "■"); } } } } //绘制方块: 在指定位置绘制指定方块的指定方向 void drawBlock(int x, int y, int blockIndex, block_dir_t dir) { setcolor(color[blockIndex]); setfont(23, 0, "楷体"); int id = blockIndex * 4 + dir; for (int i = 0; i < BLOCK_HEIGHT; i++) { for (int j = 0; j < BLOCK_WIDTH; j++) { //"■" if (block[id][i][j] == 1) { int x2 = x + j * UNIT_SIZE; int y2 = y + i * UNIT_SIZE; outtextxy(x2, y2, "■"); } } } } //清除指定位置指定方向的方块 //参数x: 方块的左上角的x坐标 //参数y: 方块的左上角在游戏区域内的坐标,距离游戏区域顶部的距离 void clearBlock(int x, int y, block_dir_t dir) { setcolor(BLACK); int id = BlockIndex * 4 + dir; y += START_Y; for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { if (block[id][i][j] == 1) { //擦除该方块的第i行的第j列 outtextxy(x + 20 * j, y + i * 20, "■"); } } } } //右上角提示区显示下一个方块 void nextblock() { clearBlock(); //清除右上角区域 //随机选择一种方块 srand(time(NULL)); //使用时间函数的返回值,来作为随机种子 NextIndex = rand() % BLOCK_COUNT; drawBlock(391, 71); } //如果在指定位置可以向指定方向移动,就返回1, 否则就返回0 int moveable(int x0, int y0, move_dir_t moveDir, block_dir_t blockDir) { //计算当前方块的左上角在30x15的游戏区中的位置(第多少行,第多少列) int x = (y0 - minY) / UNIT_SIZE; int y = (x0 - minX) / UNIT_SIZE; int id = BlockIndex * 4 + blockDir; int ret = 1; if (moveDir == MOVE_DOWN) { for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { if (block[id][i][j] == 1 && (x + i + 1 >= 30 || visit[x + i + 1][y + j] == 1)) { ret = 0; } } } } else if (moveDir == MOVE_LEFT) { for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { if (block[id][i][j] == 1 && (y + j == 0 || visit[x + i][y + j - 1] == 1)) { ret = 0; } } } } else if (moveDir == MOVE_RIGHT) { for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { if (block[id][i][j] == 1 && (y + j + 1 >= 15 || visit[x + i][y + j + 1] == 1)) { ret = 0; } } } } return ret; } //检测游戏是否结束 void failCheck() { if (!moveable(START_X, START_Y, MOVE_DOWN, BLOCK_UP)) { setcolor(WHITE); setfont(45, 0, "隶体"); outtextxy(75, 300, "GAME OVER!"); Sleep(1000); system("pause"); closegraph(); exit(0); } } //判断当前方块是否可以转向到指定方向 //注意,此时还没有转到该方向!!! int rotatable(int x, int y, block_dir_t dir) { int id = BlockIndex * 4 + dir; int xIndex = (y - minY) / UNIT_SIZE; int yIndex = (x - minX) / UNIT_SIZE; if (!moveable(x, y, MOVE_DOWN, dir)) { return 0; } for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { if (block[id][i][j] == 1 && (yIndex + j < 0 || yIndex + j >= 15 || visit[xIndex + i][yIndex + j] == 1)) { return 0; } } } return 1; } //调整下降速度 void wait(int interval) { int count = interval / 10; for (int i = 0; i < count; i++) { Sleep(10); if (kbhit()) { return; } } } //标记已到位的方块 void mark(int x, int y, int blockIndex, block_dir_t dir) { int id = blockIndex * 4 + dir; int x2 = (y - minY) / 20; int y2 = (x - minX) / 20; for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { if (block[id][i][j] == 1) { visit[x2 + i][y2 + j] = 1; markColor[x2 + i][y2 + j] = color[blockIndex]; } } } } //方块降落 void move() { int x = START_X; int y = START_Y; int k = 0; block_dir_t blockDir = BLOCK_UP; int curSpeed = speed; //检测游戏是否结束 failCheck(); //持续向下降落 while (1) { if (kbhit()) { int key = getch(); if (key == KEY_SPACE) { getch(); } } //清除当前方块 clearBlock(x, k, blockDir); if (kbhit()) { int key = getch(); if (key == KEY_UP) { block_dir_t nextDir = (block_dir_t)((blockDir + 1) % 4); if (rotatable(x, y + k, nextDir)) { blockDir = nextDir; } } else if (key == KEY_DOWN) { curSpeed = 50; } else if (key == KEY_LEFT) { if (moveable(x, y + k + 20, MOVE_LEFT, blockDir)) { x -= 20; } } else if (key == KEY_RIGHT) { if (moveable(x, y + k + 20, MOVE_RIGHT, blockDir)) { x += 20; //x = x + 20; } } } k += 20; //绘制当前方块 drawBlock(x, y + k, BlockIndex, blockDir); wait(curSpeed); //方块的“固化”处理 if (!moveable(x, y + k, MOVE_DOWN, blockDir)) { mark(x, y + k, BlockIndex, blockDir); break; } } } //新方块降落 void newblock() { //确定即将使用的方块的类别 BlockIndex = NextIndex; //绘制刚从顶部下降的方块 drawBlock(START_X, START_Y); //让新出现的方块暂停一会,让用户识别到 Sleep(100); //0.1秒 //在右上角区域,绘制下一个方块 nextblock(); //方块降落 move(); } //消除第x行,并把上面的行都下移 void down(int x) { for (int i = x; i > 0; i--) { //消除第i行,第j列的方格消除 for (int j = 0; j < 15; j++) { if (visit[i - 1][j]) { visit[i][j] = 1; markColor[i][j] = markColor[i - 1][j]; setcolor(markColor[i][j]); outtextxy(20 * j + minX, 20 * i + minY, "■"); } else { visit[i][j] = 0; setcolor(BLACK); outtextxy(20 * j + minX, 20 * i + minY, "■"); } } } //清除最顶上的哪一行(就是行标为0的那一行) setcolor(BLACK); for (int j = 0; j < 15; j++) { visit[0][j] = 0; outtextxy(20 * j + minX, minY, "■"); } } //更新分数,参数lines表示消除的行数 void addScore(int lines) { char str[32]; setcolor(RED); score += lines * 10; sprintf(str, "%d", score); outtextxy(415, 310, str); } //更新等级的提示 void updateGrade() { //假设:50分一级 rank = score / 50; char str[16]; sprintf(str, "%d", rank); outtextxy(425, 405, str); //更新速度, 等级越高,速度越快,speed越小! //最慢:500, 最快是100 speed = 500 - rank * 100; if (speed <= 100) { speed = 100; } } //检查是否有行可以消除 void check() { int i, j; int clearLines = 0; for (i = 29; i >= 0; i--) { //检查第i行有没有满 for (j = 0; j < 15 && visit[i][j]; j++); //执行到此处时,有两种情况: // 1. 第i行没有满,即表示有空位 此时 j<15 // 2. 第i行已满了,此时 j>=15 if (j >= 15) { //此时,第i行已经满了,就需要消除第i行 down(i); //消除第i行,并把上面的行都下移 i++; //因为最外层的循环中有 i--, 所以我们先i++, 使得下次循环时,再把这一行检查一下 clearLines++; } } //更新分数 addScore(clearLines); //更新等级(更新等级提示,更新速度) updateGrade(); }