发布时间:2025-12-09 20:13:17 浏览次数:7
用户点击空白方块,沿其上、下、左、右方向寻找一个彩色方块,如果有两个或两个以上颜色一致,就将其消除。在进度条时间结束前消除足够的方块,可以进入下一关
定义Block结构体,利用Block类型的二维数组存储画面中所有小方块的信息。在startup()中将所有方块设置为红色填充、白色线条,在show()中绘制出所有方块:
#include <graphics.h>#include <conio.h>#include <stdio.h>#define BlockSize 40 // 小方块的边长#define RowNum 13 // 画面一共RowNum行#define ColNum 21 // 画面一共ColNum列struct Block{int x, y; // 在画面中的x, y坐标int i, j; // 在二维数组中的i, j下标};// 全局变量Block blocks[RowNum][ColNum];void startup(){int i, j;int width = BlockSize * ColNum;int height = BlockSize * RowNum;initgraph(width, height);setbkcolor(RGB(220, 220, 220));setfillcolor(RGB(255, 0, 0));setlinestyle(PS_SOLID, 2); // 设置线型、线宽cleardevice(); // 以背景颜色清屏BeginBatchDraw();for (i = 0; i < RowNum; i++){for (j = 0; j < ColNum; j++){blocks[i][j].x = j * BlockSize;blocks[i][j].y = i * BlockSize;blocks[i][j].i = i;blocks[i][j].j = j;}}}void show(){cleardevice();setlinecolor(RGB(255, 255, 255));int i, j;for (i = 0; i < RowNum; i++){for (j = 0; j < ColNum; j++){fillrectangle(blocks[i][j].x, blocks[i][j].y, blocks[i][j].x + BlockSize, blocks[i][j].y + BlockSize);}}FlushBatchDraw();}int main(){startup();while (1){show();}return 0;}定义colors数组记录所有可能的颜色,其中第0种为灰白色,其他为彩色:
COLORREF colors[ColorTypeNum + 1];在startup()中对colors数组进行初始化:
colors[0] = RGB(220, 220, 220);for (i = 1; i < ColorTypeNum + 1; i++){colors[i] = HSVtoRGB((i - 1) * 40, 0.6, 0.8);}在结构体Block中添加成员变量colorId:
struct Block{int x, y; // 在画面中的x, y坐标int i, j; // 在二维数组中的i, j下标int colorId; // 对应颜色下标};在startup()中对blocks初始化,设置其颜色序号为[0, ColorTypeNum]的随机数:
int t = rand() % (ColorTypeNum + 1);blocks[i][j].colorId = t;为了让空白比例更高,可以调整一下:
int t = rand() % (int(ColorTypeNum * 1.5));if (t < ColorTypeNum + 1){blocks[i][j].colorId = t;}else{blocks[i][j].colorId = 0;}在show()中绘制对应颜色的小方块:
setfillcolor(colors[blocks[i][j].colorId);fillrectangle(blocks[i][j].x + BlockSize, blocks[i][j].y + BlockSize);添加updateWithInput()函数,根据鼠标点击位置(e.x, e.y)计算点中的小方块在二维数组中的行列号(clicked_i, clicked_j)
void updateWithInput(){ExMessage e;if (peekmessage(&e)){if (e.message == WM_LBUTTONDOWN){int clicked_i = int(e.y) / BlockSize;int clicked_j = int(e.x) / BlockSize;}}}先判断被鼠标点击的方块是否为空白方块,如果不是则直接返回:
if (blocks[clicked_i][clicked_j].colorId != 0){return;}定义数组fourBlocks[4]存储上下左右4个方向找到的第一个不是空白的方块:
Block fourBlocks[4] = { blocks[clicked_i][clicked_j] }; // 初始化为点击的方块首先向上寻找,找到第一个不是空白的方块,存储到fourBlocks[4]中:
int search;for (search = 0; clicked_i - search >= 0; search++) // 向上搜索{if (blocks[clicked_i - search][clicked_j].colorId != 0){fourBlocks[0] = blocks[clicked_i - search][clicked_j];break;}}同理,向下、左、右分别找到第一个不是空白的方块:
for (search = 0; clicked_i + search < RowNum; search++) // 向下搜索{if (blocks[clicked_i + search][clicked_j].colorId != 0){fourBlocks[1] = blocks[clicked_i + search][clicked_j];break;}}for (search = 0; clicked_j - search >= 0; search++) // 向左搜索 {if (blocks[clicked_i][clicked_j - search].colorId != 0){fourBlocks[2] = blocks[clicked_i][clicked_j - search];break;}}for (search = 0; clicked_j + search < ColNum; search++){if (blocks[clicked_i][clicked_j + search].colorId != 0){fourBlocks[3] = blocks[clicked_i][clicked_j + search];break;}}进一步,遍历fourBlocks,统计对应颜色方块的个数。如果某种颜色的方块个数colorStatistics[i] >= 2,则将对应方块的颜色序号设为0:
int colorStatistics[ColorTypeNum + 1] = { 0 };for (i = 1; i <= ColorTypeNum; i++){for (j = 0; j < 4; j++){if (fourBlocks[j].colorId == i){colorStatistics[i]++;}}if (colorStatistics[i] >= 2){for (j = 0; j < 4; j++){if (fourBlocks[j].colorId == i){blocks[fourBlocks[j].i][fourBlocks[j].j].colorId = 0;}}}}首先定义绘制提示框的函数:
void drawBlockHint(int i, int j, COLORREF color, int isfill){setlinecolor(color);setfillcolor(color);if (isfill == 1) // 画填充方块{fillrectangle(blocks[i][j].x, blocks[i][j].y, blocks[i][j].x + BlockSize, blocks[i][j].y + BlockSize);}if (isfill == 0) // 画非填充的方块线框{rectangle(blocks[i][j].x, blocks[i][j].y, blocks[i][j].x + BlockSize, blocks[i][j].y + BlockSize);}}在updateWithInput()中,如果点击的是空白方块,则执行:
show(); // 先绘制其他方块drawBlockHint(clicked_i, clicked_j, RGB(100, 100, 100), 1); // 对被点击的空白方块,绘制填充灰色的空白方块如果十字区域有要消除的彩色方块,则执行:
if (fourBlocks[j].colorId == i){drawBlockHint(fourBlocks[j].i, fourBlocks[j].j, RGB(0, 0, 0), 0); // 要消除的方块绘制提示框blocks[fourBlocks[j].i][fourBlocks[j].j].colorId = 0;}添加全局变量:
float maxTime; // 游戏允许的总时长float remainTime; // 游戏剩余时长在startup()中,加大窗口高度用于显示倒计时进度条:int height = BlockSize * (RowNum + 2);在updateWithoutInput()中,定义静态变量start,每次运行时获得当前时刻now,计算程序已运行的时间duration,求出游戏剩余时间:
void updateWithoutInput(){static clock_t start = clock(); // 记录第一次运行时刻clock_t now = clock(); // 获取当前时刻double duration = double(now - start) / CLOCKS_PER_SEC; // 程序运行时间remainTime = maxTime - duration;}在show()中绘制倒计时进度条:
setlinecolor(RGB(255, 0, 0)); // 设置进度条颜色setfillcolor(RGB(255, 0, 0));fillrectangle(0, BlockSize * (RowNum + 0.2), remainTime * BlockSize * ColNum / maxTime, BlockSize * (RowNum + 0.8)); // 绘制进度条定义score记录玩家消去的方块个数,noZeroBlockNum记录游戏开始时彩色砖块的总数,设定当score >= 0.9 * noZeroBlockNum时游戏胜利:
int score;int noZeroBlockNum; // 彩色方块个数在startup()中统计彩色砖块的总数:
if (blocks[i][j].colorId != 0){noZeroBlockNum++;}在updateWithInput()中,更新十字区域消除的方块个数:
score += colorStatistics[i];在show()中,显示当前得分score:
TCHAR s[80]; // 定义字符数组setbkmode(TRANSPARENT);settextcolor(RGB(0, 0, 0));settextstyle(25, 0, _T("宋体"));swprintf_s(s, _T("当前%d分,达到%d分游戏胜利"), level, score, int(0.9 * noZeroBlockNum));outtextxy(BlockSize * (ColNum / 4.5), BlockSize * (RowNum + 1.1), s);在startup()中,随着level的增加,当前关的游戏总时长越来越短:
maxTime = 200 - level * 10;在show()中,显示当前为第几关、已得分数、得到多少分可以进入下一关:
swprintf_s(s, _T("当前第%d关,已得%d分,达到%d分进入下一关"), level, score, int(0.9 * noZeroBlockNum));在updateWithoutInput()中,如果得分达到要求,则将level加1,重新计时;否则重新开始:
if (score >= int(0.9 * noZeroBlockNum)){level++; // 进入下一关start = clock(); // 重新开始计时startup();}else if (remainTime <= 0){start = clock();startup();}