当前位置: 首页 > news >正文

C语言扫雷游戏

(1)初始化二维数组


#include<stdio.h>
#include<graphics.h>//包含图形库头文件
#define ROW 10 //行
#define COL 10 //列  
int map[ROW][COL];//初始化数据
void GameInit()
{for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){map[i][k] = 0;}}
}//打印二维数组
void show()
{for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){printf("%2d ", map[i][k]);}putchar('\n');}
}int main()
{GameInit();show();
}

(2)埋雷

在这里插入图片描述
玩法规则:例如以上绿色九宫格,中间数字为1,表示这个九宫格存在一颗雷。【由于该数字形成的九宫格只有左上角没被翻开,那么左上角必定是雷】

//埋雷 -1:表示此处有雷 【总共10个雷】
for (int i = 0; i < ROW; ) {int r = rand() % 10;int c = rand() % 10;if (map[r][c]==0){map[r][c] = -1;i++;//只有成功埋雷才算数,确保10个雷}}

在这里插入图片描述

  • 对雷周围的数字进行设置【把以雷为中心的九宫格的数据都加上1,除了雷之外】
//把以雷为中心的九宫格的数据都加上1,除了雷之外
for (int i = 0; i < ROW; i++)
{for (int k = 0; k < COL; k++){//如果当前位置是雷if (map[i][k]==-1){//九宫格for (int r = i - 1; r <= i + 1; r++){for (int c = k - 1; c <= k + 1; c++){//判断是否越界if (r >= 0 && r < ROW && c >= 0 && c < COL && map[r][c] != -1){map[r][c]++;}}}}}
}

在这里插入图片描述

  • 完整代码:

#include<stdio.h>
#include<graphics.h>//包含图形库头文件
#include<stdlib.h>
#include<time.h>
#define ROW 10 //行
#define COL 10 //列  
int map[ROW][COL];//初始化数据
void GameInit()
{srand((unsigned int)time(NULL));//设置随机数种子for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){map[i][k] = 0;}}//埋雷 -1:表示此处有雷 【总共10个雷】for (int i = 0; i < ROW; ) {int r = rand() % 10;int c = rand() % 10;if (map[r][c]==0){map[r][c] = -1;i++;//只有成功埋雷才算数,确保10个雷}}//把以雷为中心的九宫格的数据都加上1,除了雷之外for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){//如果当前位置是雷if (map[i][k]==-1){//九宫格for (int r = i - 1; r <= i + 1; r++){for (int c = k - 1; c <= k + 1; c++){//判断是否越界if (r >= 0 && r < ROW && c >= 0 && c < COL && map[r][c] != -1){map[r][c]++;}}}}}}
}//打印二维数组
void show()
{for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){printf("%2d ", map[i][k]);}putchar('\n');}
}int main()
{GameInit();show();
}

(3)贴图【把矩阵数字贴上对应图片】

  • 假设随机生成的矩阵地图如下,我们的目标是将“-1”对应的位置粘贴上雷的图片
    在这里插入图片描述
    在这里插入图片描述
  • 创建窗口
// 创建窗口:一行有十张图片每张图片40px
initgraph(IMG_SIZE * ROW, IMG_SIZE * COL);
  • 引入图片(GameInit函数中添加)

【加载位于程序当前目录下image文件夹中的.jpg图像文件, //并将这些图像按照它们的编号依次存储在img数组中】

	//加载图片(赋值)for (int i = 0; i < IMAGENUM; i++){char file[20] = "";sprintf(file, "./image/%d.jpg", i);loadimage(&img[i], file, IMG_SIZE, IMG_SIZE);}
  • GameDraw 绘画函数

使用 双缓冲(Double Buffering) 双缓冲技术可以完全消除闪烁。

  • 其原理是:先在一个“隐藏的缓冲区”中绘制画面。 绘制完成后,一次性将整个画面“贴”到屏幕上。
//绘制界面
void GameDraw()
{BeginBatchDraw();//开始双缓冲【开始批量绘制】for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){if (map[i][k] == -1){putimage(k* IMG_SIZE, i * IMG_SIZE, &img[9]);}else {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[map[i][k]]);}}}EndBatchDraw();//结束双缓冲【结束批量绘制(一次性显示到屏幕)】
}
  • 完整代码:
#include<stdio.h>//标准输入输出库,用于printf等函数。
#include<graphics.h>//包含图形库头文件
#include<stdlib.h>//标准库,主要用于srand、rand等函数。
#include<time.h>//时间库,用于获取当前时间作为随机数种子。
#define _CRT_SECURE_NO_WARNINGS//关闭安全警告,防止sprintf等函数报错
#define ROW 10 //行
#define COL 10 //列 
#define IMAGENUM 12 //图片数量
#define IMG_SIZE 50 //图片大小
int map[ROW][COL];
IMAGE img[IMAGENUM];//定义图片数组,存储所有图片//初始化数据
void GameInit()
{srand((unsigned int)time(NULL));//设置随机数种子for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){map[i][k] = 0;}}//埋雷 -1:表示此处有雷 【总共10个雷】for (int i = 0; i < ROW; ) {int r = rand() % 10;int c = rand() % 10;if (map[r][c]==0){map[r][c] = -1;i++;//只有成功埋雷才算数,确保10个雷}}//把以雷为中心的九宫格的数据都加上1,除了雷之外for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){//如果当前位置是雷if (map[i][k]==-1){//九宫格for (int r = i - 1; r <= i + 1; r++){for (int c = k - 1; c <= k + 1; c++){//判断是否越界if (r >= 0 && r < ROW && c >= 0 && c < COL && map[r][c] != -1){map[r][c]++;}}}}}}//加载图片(赋值)for (int i = 0; i < IMAGENUM; i++){char file[20] = "";sprintf(file, "./image/%d.jpg", i);loadimage(&img[i], file, IMG_SIZE, IMG_SIZE);}
}//绘制界面
void GameDraw()
{BeginBatchDraw();//开始双缓冲【开始批量绘制】for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){if (map[i][k] == -1){putimage(k* IMG_SIZE, i * IMG_SIZE, &img[9]);}else {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[map[i][k]]);}}}EndBatchDraw();//结束双缓冲【结束批量绘制(一次性显示到屏幕)】
}//打印二维数组
void show()
{for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){printf("%2d ", map[i][k]);}putchar('\n');}
}int main()
{// 创建窗口:一行有十张图片每张图片40pxinitgraph(IMG_SIZE * ROW, IMG_SIZE * COL);GameInit();show();// 游戏主循环while (true) {GameDraw();}return 0;
}

在这里插入图片描述

(4)鼠标点击打开格子

  • 加密格子
//对数据进行加密
for (int i = 0; i < ROW; i++)
{for (int k = 0; k < COL; k++) {map[i][k]+= 20;}
}

在这里插入图片描述

  • 修改GameDraw
void GameDraw()
{BeginBatchDraw();//开始双缓冲【开始批量绘制】for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){if (map[i][k] == -1){putimage(k* IMG_SIZE, i * IMG_SIZE, &img[9]);}else if(map[i][k] >= 0 && map[i][k] <= 8){putimage(k * IMG_SIZE, i * IMG_SIZE, &img[map[i][k]]);}else if (map[i][k]>=19 && map[i][k]<=28) {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[10]);}else if (map[i][k] >= 39) {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[11]);}}}EndBatchDraw();//结束双缓冲【结束批量绘制(一次性显示到屏幕)】
}
  • 添加鼠标事件
void MouseEvent()
{//检测是否有鼠标消息if (MouseHit()){//获取鼠标消息,坐标,左键还是右键MOUSEMSG msg = GetMouseMsg();//把坐标转化成数组下标int openr = msg.y / IMG_SIZE;int openc = msg.x / IMG_SIZE;//判断是左键还是右键switch (msg.uMsg){case WM_LBUTTONDOWN://左键//如果格子没有打开,就打开格子,否则不做处理if (map[openr][openc] >= 19){map[openr][openc] -= 20;}break;case WM_RBUTTONDOWN://右键【标记】//如果格子没有打开,且没有标记,就标记if (map[openr][openc] >= 19 && map[openr][openc] <= 28){map[openr][openc] += 20;}else if (map[openr][openc] >= 39)//如果格子没有打开,且有标记,才可以取消标记{map[openr][openc] -= 20;}break;}}
}
  • 完整代码

#include<stdio.h>//标准输入输出库,用于printf等函数。
#include<graphics.h>//包含图形库头文件
#include<stdlib.h>//标准库,主要用于srand、rand等函数。
#include<time.h>//时间库,用于获取当前时间作为随机数种子。
#define _CRT_SECURE_NO_WARNINGS//关闭安全警告,防止sprintf等函数报错
#define ROW 10 //行
#define COL 10 //列 
#define IMAGENUM 12 //图片数量
#define IMG_SIZE 50 //图片大小
int map[ROW][COL];
IMAGE img[IMAGENUM];//定义图片数组,存储所有图片//初始化数据
void GameInit()
{srand((unsigned int)time(NULL));//设置随机数种子for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){map[i][k] = 0;}}//埋雷 -1:表示此处有雷 【总共10个雷】for (int i = 0; i < ROW; ) {int r = rand() % 10;int c = rand() % 10;if (map[r][c]==0){map[r][c] = -1;i++;//只有成功埋雷才算数,确保10个雷}}//把以雷为中心的九宫格的数据都加上1,除了雷之外for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){//如果当前位置是雷if (map[i][k]==-1){//九宫格for (int r = i - 1; r <= i + 1; r++){for (int c = k - 1; c <= k + 1; c++){//判断是否越界if (r >= 0 && r < ROW && c >= 0 && c < COL && map[r][c] != -1){map[r][c]++;}}}}}}//加载图片(赋值)for (int i = 0; i < IMAGENUM; i++){char file[20] = "";sprintf(file, "./image/%d.jpg", i);loadimage(&img[i], file, IMG_SIZE, IMG_SIZE);}//对数据进行加密for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++) {map[i][k]+= 20;}}
}//绘制界面
void GameDraw()
{BeginBatchDraw();//开始双缓冲【开始批量绘制】for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){if (map[i][k] == -1){putimage(k* IMG_SIZE, i * IMG_SIZE, &img[9]);}else if(map[i][k] >= 0 && map[i][k] <= 8){putimage(k * IMG_SIZE, i * IMG_SIZE, &img[map[i][k]]);}else if (map[i][k]>=19 && map[i][k]<=28) {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[10]);}else if (map[i][k] >= 39) {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[11]);}}}EndBatchDraw();//结束双缓冲【结束批量绘制(一次性显示到屏幕)】
}//打印二维数组
void show()
{for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){printf("%2d ", map[i][k]);}putchar('\n');}
}//鼠标事件
void MouseEvent()
{//检测是否有鼠标消息if (MouseHit()){//获取鼠标消息,坐标,左键还是右键MOUSEMSG msg = GetMouseMsg();//把坐标转化成数组下标int openr = msg.y / IMG_SIZE;int openc = msg.x / IMG_SIZE;//判断是左键还是右键switch (msg.uMsg){case WM_LBUTTONDOWN://左键//如果格子没有打开,就打开格子,否则不做处理if (map[openr][openc] >= 19){map[openr][openc] -= 20;}break;case WM_RBUTTONDOWN://右键【标记】//如果格子没有打开,且没有标记,就标记if (map[openr][openc] >= 19 && map[openr][openc] <= 28){map[openr][openc] += 20;}else if (map[openr][openc] >= 39)//如果格子没有打开,且有标记,才可以取消标记{map[openr][openc] -= 20;}break;}}
}
int main()
{// 创建窗口:一行有十张图片每张图片50pxinitgraph(IMG_SIZE * ROW, IMG_SIZE * COL);GameInit();show();// 游戏主循环while (true) {GameDraw();MouseEvent();}return 0;
}

(5)炸开连续区域

  • 添加openNull函数
//炸开连续区域
void openNull(int x,int y) {//如果当前位置为0,就把九宫格都打开 if (map[x][y] == 0){//九宫格for (int r = x - 1; r <= x + 1; r++){for (int c = y - 1; c <= y + 1; c++){if ((r >= 0 && r < ROW && c >= 0 && c < COL) && //判断是否越界(map[r][c] > 19)  &&//判断没有打开(map[r][c] != 19) //判断不是雷){map[r][c] -= 20;//打开openNull(r, c);//如果当前位置为0,就把九宫格都打开}}}}
}

在这里插入图片描述

openNull 函数是一个利用递归策略来自动展开空白区域的实用工具,在扫雷类游戏中,它有助于简化玩家的操作流程,提高游戏的流畅性和趣味性。

  • 完整代码

#include<stdio.h>//标准输入输出库,用于printf等函数。
#include<graphics.h>//包含图形库头文件
#include<stdlib.h>//标准库,主要用于srand、rand等函数。
#include<time.h>//时间库,用于获取当前时间作为随机数种子。
#define _CRT_SECURE_NO_WARNINGS//关闭安全警告,防止sprintf等函数报错
#define ROW 10 //行
#define COL 10 //列 
#define IMAGENUM 12 //图片数量
#define IMG_SIZE 50 //图片大小
int map[ROW][COL];
IMAGE img[IMAGENUM];//定义图片数组,存储所有图片//初始化数据
void GameInit()
{srand((unsigned int)time(NULL));//设置随机数种子for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){map[i][k] = 0;}}//埋雷 -1:表示此处有雷 【总共10个雷】for (int i = 0; i < ROW; ) {int r = rand() % 10;int c = rand() % 10;if (map[r][c]==0){map[r][c] = -1;i++;//只有成功埋雷才算数,确保10个雷}}//把以雷为中心的九宫格的数据都加上1,除了雷之外for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){//如果当前位置是雷if (map[i][k]==-1){//九宫格for (int r = i - 1; r <= i + 1; r++){for (int c = k - 1; c <= k + 1; c++){//判断是否越界if (r >= 0 && r < ROW && c >= 0 && c < COL && map[r][c] != -1){map[r][c]++;}}}}}}//加载图片(赋值)for (int i = 0; i < IMAGENUM; i++){char file[20] = "";sprintf(file, "./image/%d.jpg", i);loadimage(&img[i], file, IMG_SIZE, IMG_SIZE);}//对数据进行加密for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++) {map[i][k]+= 20;}}
}//绘制界面
void GameDraw()
{BeginBatchDraw();//开始双缓冲【开始批量绘制】for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){if (map[i][k] == -1){putimage(k* IMG_SIZE, i * IMG_SIZE, &img[9]);}else if(map[i][k] >= 0 && map[i][k] <= 8){putimage(k * IMG_SIZE, i * IMG_SIZE, &img[map[i][k]]);}else if (map[i][k]>=19 && map[i][k]<=28) {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[10]);}else if (map[i][k] >= 39) {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[11]);}}}EndBatchDraw();//结束双缓冲【结束批量绘制(一次性显示到屏幕)】
}//打印二维数组
void show()
{for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){printf("%2d ", map[i][k]);}putchar('\n');}
}//炸开连续区域
void openNull(int x,int y) {//如果当前位置为0,就把九宫格都打开 if (map[x][y] == 0){//九宫格for (int r = x - 1; r <= x + 1; r++){for (int c = y - 1; c <= y + 1; c++){if ((r >= 0 && r < ROW && c >= 0 && c < COL) && //判断是否越界(map[r][c] > 19)  &&//判断没有打开(map[r][c] != 19) //判断不是雷){map[r][c] -= 20;//打开openNull(r, c);//如果当前位置为0,就把九宫格都打开}}}}
}//鼠标事件
void MouseEvent()
{//检测是否有鼠标消息if (MouseHit()){//获取鼠标消息,坐标,左键还是右键MOUSEMSG msg = GetMouseMsg();//把坐标转化成数组下标int openr = msg.y / IMG_SIZE;int openc = msg.x / IMG_SIZE;//判断是左键还是右键switch (msg.uMsg){case WM_LBUTTONDOWN://左键//如果格子没有打开,就打开格子,否则不做处理if (map[openr][openc] >= 19){map[openr][openc] -= 20;openNull(openr, openc);//如果当前位置为0,就把九宫格都打开}break;case WM_RBUTTONDOWN://右键【标记】//如果格子没有打开,且没有标记,就标记if (map[openr][openc] >= 19 && map[openr][openc] <= 28){map[openr][openc] += 20;}else if (map[openr][openc] >= 39)//如果格子没有打开,且有标记,才可以取消标记{map[openr][openc] -= 20;}break;}}
}
int main()
{// 创建窗口:一行有十张图片每张图片50pxinitgraph(IMG_SIZE * ROW, IMG_SIZE * COL);GameInit();show();// 游戏主循环while (true) {GameDraw();MouseEvent();}return 0;
}

(6)游戏输赢判定

  • 添加 游戏胜利/失败的判断机制,并使用你定义的 flag 变量来控制游戏状态。
int flag = 0; // 游戏状态:0-进行中,1-胜利,-1-失败

在这里插入图片描述
1️⃣ 修改 MouseEvent:检测是否点到雷(失败)

//鼠标事件
void MouseEvent()
{if (flag != 0) return; // 游戏已结束,不再处理if (MouseHit()) //检测是否有鼠标消息{MOUSEMSG msg = GetMouseMsg();int openr = msg.y / IMG_SIZE; //把坐标转化成数组下标int openc = msg.x / IMG_SIZE;switch (msg.uMsg) //获取鼠标消息,坐标,左键还是右键{case WM_LBUTTONDOWN: // 左键点击if (map[openr][openc] >= 19) //如果格子没有打开,就打开格子,否则不做处理{// 如果是雷(加密后为19)if (map[openr][openc] == 19){map[openr][openc] = -1; // 显示雷flag = -1; // 标记失败GameOver();}else{map[openr][openc] -= 20; // 打开openNull(openr, openc);  //如果当前位置为0,就把九宫格都打开// 检查是否胜利if (CheckWin()){flag = 1;GameOver();}}}break;case WM_RBUTTONDOWN: // 右键标记if (map[openr][openc] >= 19 && map[openr][openc] <= 28){map[openr][openc] += 20; // 标记为39+}else if (map[openr][openc] >= 39) //如果格子没有打开,且有标记,才可以取消标记{map[openr][openc] -= 20; // 取消标记}break;}}
}

2️⃣ 添加 CheckWin() 函数:检查是否所有安全格子都已翻开(胜利)

// 检查是否所有非雷格子都已翻开(胜利条件)
int CheckWin()
{for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){// 如果是未打开的非雷格子(加密状态 20~28),说明还没赢if (map[i][k] >= 20 && map[i][k] <= 28){return 0; // 还没赢}}}return 1; // 所有安全格子都打开了,胜利!
}

3️⃣ 添加 GameOver() 函数:显示结果并暂停游戏

// 游戏结束:显示结果,停止交互
void GameOver()
{// === 第一步:游戏结束,无论胜利还是失败,都显示所有雷 ===for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){if (map[i][k] == 19)        // 未翻开的雷(加密状态){map[i][k] = -1;         // 显示为雷}else if (map[i][k] == 39)   // 玩家标记为旗子的雷(加密+标记){map[i][k] = -1;         // 也显示为雷(表示正确标记)}}}// === 第二步:强制刷新画面,让用户看到结果 ===EndBatchDraw();        // 结束双缓冲,强制刷新GameDraw();            // 再画一次,确保雷显示出来FlushBatchDraw();      // 确保画面立即更新到屏幕// === 第三步:弹出对话框(此时用户已看到雷) ===int isok;if (flag == 1){isok = MessageBox(GetHWnd(), _T("恭喜!你赢了!是否再来一局?"), _T("胜利"), MB_OKCANCEL | MB_ICONINFORMATION);}else // flag == -1{isok = MessageBox(GetHWnd(), _T("踩到雷了!游戏结束!是否再来一局?"), _T("失败"), MB_OKCANCEL | MB_ICONERROR);}// === 第四步:处理用户选择 ===if (isok == IDOK){flag = 0;GameInit();           // 重新初始化/*system("cls");show();*/  // 控制台打印数组,仅调试用BeginBatchDraw();     // 重新开启双缓冲}else{closegraph();// 关闭图形窗口exit(0);// 退出程序代码}
}
  • 完整代码
#include<stdio.h>//标准输入输出库,用于printf等函数。
#include<graphics.h>//包含图形库头文件
#include<stdlib.h>//标准库,主要用于srand、rand等函数。
#include<time.h>//时间库,用于获取当前时间作为随机数种子。
#define _CRT_SECURE_NO_WARNINGS//关闭安全警告,防止sprintf等函数报错
#define ROW 10 //行
#define COL 10 //列 
#define IMAGENUM 12 //图片数量
#define IMG_SIZE 50 //图片大小
int map[ROW][COL];
IMAGE img[IMAGENUM];//定义图片数组,存储所有图片
int flag = 0; // 游戏状态:0-进行中,1-胜利,-1-失败//初始化数据
void GameInit()
{srand((unsigned int)time(NULL));//设置随机数种子for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){map[i][k] = 0;}}//埋雷 -1:表示此处有雷 【总共10个雷】for (int i = 0; i < ROW; ) {int r = rand() % 10;int c = rand() % 10;if (map[r][c] == 0){map[r][c] = -1;i++;//只有成功埋雷才算数,确保10个雷}}//把以雷为中心的九宫格的数据都加上1,除了雷之外for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){//如果当前位置是雷if (map[i][k] == -1){//九宫格for (int r = i - 1; r <= i + 1; r++){for (int c = k - 1; c <= k + 1; c++){//判断是否越界if (r >= 0 && r < ROW && c >= 0 && c < COL && map[r][c] != -1){map[r][c]++;}}}}}}//加载图片(赋值)for (int i = 0; i < IMAGENUM; i++){char file[20] = "";sprintf(file, "./image/%d.jpg", i);loadimage(&img[i], file, IMG_SIZE, IMG_SIZE);}//对数据进行加密for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++) {map[i][k] += 20;}}
}//绘制界面
void GameDraw()
{BeginBatchDraw();//开始双缓冲【开始批量绘制】for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){if (map[i][k] == -1){putimage(k * IMG_SIZE, i * IMG_SIZE, &img[9]);}else if (map[i][k] >= 0 && map[i][k] <= 8) {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[map[i][k]]);}else if (map[i][k] >= 19 && map[i][k] <= 28) {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[10]);}else if (map[i][k] >= 39) {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[11]);}}}EndBatchDraw();//结束双缓冲【结束批量绘制(一次性显示到屏幕)】
}//打印二维数组
void show()
{for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){printf("%2d ", map[i][k]);}putchar('\n');}
}//炸开连续区域
void openNull(int x, int y) {//如果当前位置为0,就把九宫格都打开 if (map[x][y] == 0){//九宫格for (int r = x - 1; r <= x + 1; r++){for (int c = y - 1; c <= y + 1; c++){if ((r >= 0 && r < ROW && c >= 0 && c < COL) && //判断是否越界(map[r][c] > 19) &&//判断没有打开(map[r][c] != 19) //判断不是雷){map[r][c] -= 20;//打开openNull(r, c);//如果当前位置为0,就把九宫格都打开}}}}
}// 检查是否所有非雷格子都已翻开(胜利条件)
int CheckWin()
{for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){// 如果是未打开的非雷格子(加密状态 20~28),说明还没赢if (map[i][k] >= 20 && map[i][k] <= 28){return 0; // 还没赢}}}return 1; // 所有安全格子都打开了,胜利!
}// 游戏结束:显示结果,停止交互
void GameOver()
{// === 第一步:游戏结束,无论胜利还是失败,都显示所有雷 ===for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){if (map[i][k] == 19)        // 未翻开的雷(加密状态){map[i][k] = -1;         // 显示为雷}else if (map[i][k] == 39)   // 玩家标记为旗子的雷(加密+标记){map[i][k] = -1;         // 也显示为雷(表示正确标记)}}}// === 第二步:强制刷新画面,让用户看到结果 ===EndBatchDraw();        // 结束双缓冲,强制刷新GameDraw();            // 再画一次,确保雷显示出来FlushBatchDraw();      // 确保画面立即更新到屏幕// === 第三步:弹出对话框(此时用户已看到雷) ===int isok;if (flag == 1){isok = MessageBox(GetHWnd(), _T("恭喜!你赢了!是否再来一局?"), _T("胜利"), MB_OKCANCEL | MB_ICONINFORMATION);}else // flag == -1{isok = MessageBox(GetHWnd(), _T("踩到雷了!游戏结束!是否再来一局?"), _T("失败"), MB_OKCANCEL | MB_ICONERROR);}// === 第四步:处理用户选择 ===if (isok == IDOK){flag = 0;GameInit();           // 重新初始化/*system("cls");show();*/  // 控制台打印数组,仅调试用BeginBatchDraw();     // 重新开启双缓冲}else{closegraph();// 关闭图形窗口exit(0);// 退出程序代码}
}//鼠标事件
void MouseEvent()
{if (flag != 0) return; // 游戏已结束,不再处理if (MouseHit()) //检测是否有鼠标消息{MOUSEMSG msg = GetMouseMsg();int openr = msg.y / IMG_SIZE; //把坐标转化成数组下标int openc = msg.x / IMG_SIZE;switch (msg.uMsg) //获取鼠标消息,坐标,左键还是右键{case WM_LBUTTONDOWN: // 左键点击if (map[openr][openc] >= 19) //如果格子没有打开,就打开格子,否则不做处理{// 如果是雷(加密后为19)if (map[openr][openc] == 19){map[openr][openc] = -1; // 显示雷flag = -1; // 标记失败GameOver();}else{map[openr][openc] -= 20; // 打开openNull(openr, openc);  //如果当前位置为0,就把九宫格都打开// 检查是否胜利if (CheckWin()){flag = 1;GameOver();}}}break;case WM_RBUTTONDOWN: // 右键标记if (map[openr][openc] >= 19 && map[openr][openc] <= 28){map[openr][openc] += 20; // 标记为39+}else if (map[openr][openc] >= 39) //如果格子没有打开,且有标记,才可以取消标记{map[openr][openc] -= 20; // 取消标记}break;}}
}int main()
{// 创建窗口:一行有十张图片每张图片50pxinitgraph(IMG_SIZE * ROW, IMG_SIZE * COL);GameInit();show();// 游戏主循环while (true) {GameDraw();MouseEvent();}return 0;
}

(7)添加音效

  • 加载多媒体库,支持声音播放
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib") //加载多媒体库,支持声音播放
  • GameInit函数中添加 背景音乐
//初始化数据
void GameInit()
{mciSendString("open ./image/start.mp3 alias BGM", 0, 0, 0); //加载背景音乐mciSendString("play BGM", 0, 0, 0); //循环播放背景音乐
  • GameOver函数中关闭音乐
mciSendString("close BGM", 0, 0, 0); //关闭背景音乐
  • 添加点击鼠标左键 音效
mciSendString("close CLICK", 0, 0, 0); //停止上一次的点击音效
mciSendString("open ./image/click.wav alias CLICK", 0, 0, 0); //加载点击音效
mciSendString("play CLICK", 0, 0, 0); //播放点击音效
  • 添加点击鼠标右键 音效
mciSendString("close CLICK", 0, 0, 0); //停止上一次的点击音效
mciSendString("open ./image/rightClick.wav alias CLICK", 0, 0, 0); //加载点击音效
mciSendString("play CLICK", 0, 0, 0); //播放点击音效
  • 完整代码
#include<stdio.h>//标准输入输出库,用于printf等函数。
#include<graphics.h>//包含图形库头文件
#include<stdlib.h>//标准库,主要用于srand、rand等函数。
#include<time.h>//时间库,用于获取当前时间作为随机数种子。
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib") //加载多媒体库,支持声音播放
#define _CRT_SECURE_NO_WARNINGS//关闭安全警告,防止sprintf等函数报错
#define ROW 10 //行
#define COL 10 //列 
#define IMAGENUM 12 //图片数量
#define IMG_SIZE 50 //图片大小
int map[ROW][COL];
IMAGE img[IMAGENUM];//定义图片数组,存储所有图片
int flag = 0; // 游戏状态:0-进行中,1-胜利,-1-失败//初始化数据
void GameInit()
{mciSendString("open ./image/start.mp3 alias BGM", 0, 0, 0); //加载背景音乐mciSendString("play BGM", 0, 0, 0); //循环播放背景音乐srand((unsigned int)time(NULL));//设置随机数种子for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){map[i][k] = 0;}}//埋雷 -1:表示此处有雷 【总共10个雷】for (int i = 0; i < ROW; ) {int r = rand() % 10;int c = rand() % 10;if (map[r][c] == 0){map[r][c] = -1;i++;//只有成功埋雷才算数,确保10个雷}}//把以雷为中心的九宫格的数据都加上1,除了雷之外for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){//如果当前位置是雷if (map[i][k] == -1){//九宫格for (int r = i - 1; r <= i + 1; r++){for (int c = k - 1; c <= k + 1; c++){//判断是否越界if (r >= 0 && r < ROW && c >= 0 && c < COL && map[r][c] != -1){map[r][c]++;}}}}}}//加载图片(赋值)for (int i = 0; i < IMAGENUM; i++){char file[20] = "";sprintf(file, "./image/%d.jpg", i);loadimage(&img[i], file, IMG_SIZE, IMG_SIZE);}//对数据进行加密for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++) {map[i][k] += 20;}}
}//绘制界面
void GameDraw()
{BeginBatchDraw();//开始双缓冲【开始批量绘制】for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){if (map[i][k] == -1){putimage(k * IMG_SIZE, i * IMG_SIZE, &img[9]);}else if (map[i][k] >= 0 && map[i][k] <= 8) {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[map[i][k]]);}else if (map[i][k] >= 19 && map[i][k] <= 28) {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[10]);}else if (map[i][k] >= 39) {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[11]);}}}EndBatchDraw();//结束双缓冲【结束批量绘制(一次性显示到屏幕)】
}//打印二维数组
void show()
{for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){printf("%2d ", map[i][k]);}putchar('\n');}
}//炸开连续区域
void openNull(int x, int y) {//如果当前位置为0,就把九宫格都打开 if (map[x][y] == 0){//九宫格for (int r = x - 1; r <= x + 1; r++){for (int c = y - 1; c <= y + 1; c++){if ((r >= 0 && r < ROW && c >= 0 && c < COL) && //判断是否越界(map[r][c] > 19) &&//判断没有打开(map[r][c] != 19) //判断不是雷){map[r][c] -= 20;//打开openNull(r, c);//如果当前位置为0,就把九宫格都打开}}}}
}// 检查是否所有非雷格子都已翻开(胜利条件)
int CheckWin()
{for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){// 如果是未打开的非雷格子(加密状态 20~28),说明还没赢if (map[i][k] >= 20 && map[i][k] <= 28){return 0; // 还没赢}}}return 1; // 所有安全格子都打开了,胜利!
}// 游戏结束:显示结果,停止交互
void GameOver()
{// === 第一步:游戏结束,无论胜利还是失败,都显示所有雷 ===for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){if (map[i][k] == 19)        // 未翻开的雷(加密状态){map[i][k] = -1;         // 显示为雷}else if (map[i][k] == 39)   // 玩家标记为旗子的雷(加密+标记){map[i][k] = -1;         // 也显示为雷(表示正确标记)}}}// === 第二步:强制刷新画面,让用户看到结果 ===EndBatchDraw();        // 结束双缓冲,强制刷新GameDraw();            // 再画一次,确保雷显示出来FlushBatchDraw();      // 确保画面立即更新到屏幕// === 第三步:弹出对话框(此时用户已看到雷) ===int isok;if (flag == 1){isok = MessageBox(GetHWnd(), _T("恭喜!你赢了!是否再来一局?"), _T("胜利"), MB_OKCANCEL | MB_ICONINFORMATION);}else // flag == -1{isok = MessageBox(GetHWnd(), _T("踩到雷了!游戏结束!是否再来一局?"), _T("失败"), MB_OKCANCEL | MB_ICONERROR);}// === 第四步:处理用户选择 ===if (isok == IDOK){flag = 0;GameInit();           // 重新初始化/*system("cls");show();*/  // 控制台打印数组,仅调试用BeginBatchDraw();     // 重新开启双缓冲}else{closegraph();// 关闭图形窗口exit(0);// 退出程序代码}mciSendString("close BGM", 0, 0, 0); //关闭背景音乐
}//鼠标事件
void MouseEvent()
{if (flag != 0) return; // 游戏已结束,不再处理if (MouseHit()) //检测是否有鼠标消息{MOUSEMSG msg = GetMouseMsg();int openr = msg.y / IMG_SIZE; //把坐标转化成数组下标int openc = msg.x / IMG_SIZE;switch (msg.uMsg) //获取鼠标消息,坐标,左键还是右键{case WM_LBUTTONDOWN: // 左键点击if (map[openr][openc] >= 19) //如果格子没有打开,就打开格子,否则不做处理{mciSendString("close CLICK", 0, 0, 0); //停止上一次的点击音效mciSendString("open ./image/click.wav alias CLICK", 0, 0, 0); //加载点击音效mciSendString("play CLICK", 0, 0, 0); //播放点击音效// 如果是雷(加密后为19)if (map[openr][openc] == 19){map[openr][openc] = -1; // 显示雷flag = -1; // 标记失败GameOver();}else{map[openr][openc] -= 20; // 打开openNull(openr, openc);  //如果当前位置为0,就把九宫格都打开// 检查是否胜利if (CheckWin()){flag = 1;GameOver();}}}break;case WM_RBUTTONDOWN: // 右键标记if (map[openr][openc] >= 19 && map[openr][openc] <= 28){mciSendString("close CLICK", 0, 0, 0); //停止上一次的点击音效mciSendString("open ./image/rightClick.wav alias CLICK", 0, 0, 0); //加载点击音效mciSendString("play CLICK", 0, 0, 0); //播放点击音效map[openr][openc] += 20; // 标记为39+}else if (map[openr][openc] >= 39) //如果格子没有打开,且有标记,才可以取消标记{mciSendString("close CLICK", 0, 0, 0); //停止上一次的点击音效mciSendString("open ./image/rightClick.wav alias CLICK", 0, 0, 0); //加载点击音效mciSendString("play CLICK", 0, 0, 0); //播放点击音效map[openr][openc] -= 20; // 取消标记}break;}}
}int main()
{// 创建窗口:一行有十张图片每张图片50pxinitgraph(IMG_SIZE * ROW, IMG_SIZE * COL);GameInit();show();// 游戏主循环while (true) {GameDraw();MouseEvent();}return 0;
}

(8)添加计时功能

  1. 新增变量

gameTime: 记录游戏已进行的时间(秒)

startTime: 游戏开始的时间戳

timerRunning: 计时器运行状态

// 添加倒计时相关变量
int gameTime = 0; // 游戏已进行的时间(秒)
int startTime = 0; // 游戏开始的时间戳
int timerRunning = 0; // 计时器状态:0-停止,1-运行
  • GameInit初始化
//初始化数据
void GameInit()
{//....// 初始化计时器gameTime = 0;startTime = (int)time(NULL); // 获取当前时间戳timerRunning = 1; // 开始计时
  1. 新增函数

UpdateTimer(): 更新游戏时间

// 更新游戏时间
void UpdateTimer()
{if (timerRunning) {gameTime = (int)time(NULL) - startTime;}
}

DrawTimer(): 在屏幕上绘制时间显示

// 绘制时间显示
void DrawTimer()
{// 设置文字颜色和样式settextcolor(WHITE);settextstyle(20, 0, _T("宋体"));setbkmode(TRANSPARENT); // 透明背景// 格式化时间显示char timeStr[20];int minutes = gameTime / 60;int seconds = gameTime % 60;sprintf(timeStr, "时间: %02d:%02d", minutes, seconds);// 在窗口右上角显示时间outtextxy(COL * IMG_SIZE - 120, 10, timeStr);
}
  • 调用函数
void GameDraw()
{//....// 绘制计时器UpdateTimer();DrawTimer();
}

StopTimer(): 停止计时器

// 停止计时器
void StopTimer()
{timerRunning = 0;
}
  • 调用函数
// 游戏结束:显示结果,停止交互
void GameOver()
{// 停止计时器StopTimer();
  1. 功能特点

实时显示: 在窗口右上角显示格式化的时间(分:秒)

自动停止: 游戏结束时自动停止计时

结果显示: 在胜利/失败对话框中显示最终用时

重新开始: 重新开始游戏时会重置计时器

在这里插入图片描述

  • 完整代码
#include<stdio.h>//标准输入输出库,用于printf等函数。
#include<graphics.h>//包含图形库头文件
#include<stdlib.h>//标准库,主要用于srand、rand等函数。
#include<time.h>//时间库,用于获取当前时间作为随机数种子。
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib") //加载多媒体库,支持声音播放
#define _CRT_SECURE_NO_WARNINGS//关闭安全警告,防止sprintf等函数报错
#define ROW 10 //行
#define COL 10 //列 
#define IMAGENUM 12 //图片数量
#define IMG_SIZE 50 //图片大小
int map[ROW][COL];
IMAGE img[IMAGENUM];//定义图片数组,存储所有图片
int flag = 0; // 游戏状态:0-进行中,1-胜利,-1-失败
// 添加倒计时相关变量
int gameTime = 0; // 游戏已进行的时间(秒)
int startTime = 0; // 游戏开始的时间戳
int timerRunning = 0; // 计时器状态:0-停止,1-运行//初始化数据
void GameInit()
{mciSendString("open ./image/start.mp3 alias BGM", 0, 0, 0); //加载背景音乐mciSendString("play BGM", 0, 0, 0); //循环播放背景音乐srand((unsigned int)time(NULL));//设置随机数种子// 初始化计时器gameTime = 0;startTime = (int)time(NULL); // 获取当前时间戳timerRunning = 1; // 开始计时for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){map[i][k] = 0;}}//埋雷 -1:表示此处有雷 【总共10个雷】for (int i = 0; i < ROW; ) {int r = rand() % 10;int c = rand() % 10;if (map[r][c] == 0){map[r][c] = -1;i++;//只有成功埋雷才算数,确保10个雷}}//把以雷为中心的九宫格的数据都加上1,除了雷之外for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){//如果当前位置是雷if (map[i][k] == -1){//九宫格for (int r = i - 1; r <= i + 1; r++){for (int c = k - 1; c <= k + 1; c++){//判断是否越界if (r >= 0 && r < ROW && c >= 0 && c < COL && map[r][c] != -1){map[r][c]++;}}}}}}//加载图片(赋值)for (int i = 0; i < IMAGENUM; i++){char file[20] = "";sprintf(file, "./image/%d.jpg", i);loadimage(&img[i], file, IMG_SIZE, IMG_SIZE);}//对数据进行加密for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++) {map[i][k] += 20;}}
}// 更新游戏时间
void UpdateTimer()
{if (timerRunning) {gameTime = (int)time(NULL) - startTime;}
}// 绘制时间显示
void DrawTimer()
{// 设置文字颜色和样式settextcolor(WHITE);settextstyle(20, 0, _T("宋体"));setbkmode(TRANSPARENT); // 透明背景// 格式化时间显示char timeStr[20];int minutes = gameTime / 60;int seconds = gameTime % 60;sprintf(timeStr, "时间: %02d:%02d", minutes, seconds);// 在窗口右上角显示时间outtextxy(COL * IMG_SIZE - 120, 10, timeStr);
}//绘制界面
void GameDraw()
{BeginBatchDraw();//开始双缓冲【开始批量绘制】for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){if (map[i][k] == -1){putimage(k * IMG_SIZE, i * IMG_SIZE, &img[9]);}else if (map[i][k] >= 0 && map[i][k] <= 8) {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[map[i][k]]);}else if (map[i][k] >= 19 && map[i][k] <= 28) {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[10]);}else if (map[i][k] >= 39) {putimage(k * IMG_SIZE, i * IMG_SIZE, &img[11]);}}}// 绘制计时器UpdateTimer();DrawTimer();EndBatchDraw();//结束双缓冲【结束批量绘制(一次性显示到屏幕)】
}//打印二维数组
void show()
{for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){printf("%2d ", map[i][k]);}putchar('\n');}
}//炸开连续区域
void openNull(int x, int y) {//如果当前位置为0,就把九宫格都打开 if (map[x][y] == 0){//九宫格for (int r = x - 1; r <= x + 1; r++){for (int c = y - 1; c <= y + 1; c++){if ((r >= 0 && r < ROW && c >= 0 && c < COL) && //判断是否越界(map[r][c] > 19) &&//判断没有打开(map[r][c] != 19) //判断不是雷){map[r][c] -= 20;//打开openNull(r, c);//如果当前位置为0,就把九宫格都打开}}}}
}// 检查是否所有非雷格子都已翻开(胜利条件)
int CheckWin()
{for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){// 如果是未打开的非雷格子(加密状态 20~28),说明还没赢if (map[i][k] >= 20 && map[i][k] <= 28){return 0; // 还没赢}}}return 1; // 所有安全格子都打开了,胜利!
}// 停止计时器
void StopTimer()
{timerRunning = 0;
}// 游戏结束:显示结果,停止交互
void GameOver()
{// 停止计时器StopTimer();// === 第一步:游戏结束,无论胜利还是失败,都显示所有雷 ===for (int i = 0; i < ROW; i++){for (int k = 0; k < COL; k++){if (map[i][k] == 19)        // 未翻开的雷(加密状态){map[i][k] = -1;         // 显示为雷}else if (map[i][k] == 39)   // 玩家标记为旗子的雷(加密+标记){map[i][k] = -1;         // 也显示为雷(表示正确标记)}}}// === 第二步:强制刷新画面,让用户看到结果 ===EndBatchDraw();        // 结束双缓冲,强制刷新GameDraw();            // 再画一次,确保雷显示出来FlushBatchDraw();      // 确保画面立即更新到屏幕// === 第三步:弹出对话框(此时用户已看到雷) ===int isok;if (flag == 1){isok = MessageBox(GetHWnd(), _T("恭喜!你赢了!是否再来一局?"), _T("胜利"), MB_OKCANCEL | MB_ICONINFORMATION);}else // flag == -1{isok = MessageBox(GetHWnd(), _T("踩到雷了!游戏结束!是否再来一局?"), _T("失败"), MB_OKCANCEL | MB_ICONERROR);}// === 第四步:处理用户选择 ===if (isok == IDOK){flag = 0;GameInit();           // 重新初始化/*system("cls");show();*/  // 控制台打印数组,仅调试用BeginBatchDraw();     // 重新开启双缓冲}else{closegraph();// 关闭图形窗口exit(0);// 退出程序代码}mciSendString("close BGM", 0, 0, 0); //关闭背景音乐
}//鼠标事件
void MouseEvent()
{if (flag != 0) return; // 游戏已结束,不再处理if (MouseHit()) //检测是否有鼠标消息{MOUSEMSG msg = GetMouseMsg();int openr = msg.y / IMG_SIZE; //把坐标转化成数组下标int openc = msg.x / IMG_SIZE;switch (msg.uMsg) //获取鼠标消息,坐标,左键还是右键{case WM_LBUTTONDOWN: // 左键点击if (map[openr][openc] >= 19) //如果格子没有打开,就打开格子,否则不做处理{mciSendString("close CLICK", 0, 0, 0); //停止上一次的点击音效mciSendString("open ./image/click.wav alias CLICK", 0, 0, 0); //加载点击音效mciSendString("play CLICK", 0, 0, 0); //播放点击音效// 如果是雷(加密后为19)if (map[openr][openc] == 19){map[openr][openc] = -1; // 显示雷flag = -1; // 标记失败GameOver();}else{map[openr][openc] -= 20; // 打开openNull(openr, openc);  //如果当前位置为0,就把九宫格都打开// 检查是否胜利if (CheckWin()){flag = 1;GameOver();}}}break;case WM_RBUTTONDOWN: // 右键标记if (map[openr][openc] >= 19 && map[openr][openc] <= 28){mciSendString("close CLICK", 0, 0, 0); //停止上一次的点击音效mciSendString("open ./image/rightClick.wav alias CLICK", 0, 0, 0); //加载点击音效mciSendString("play CLICK", 0, 0, 0); //播放点击音效map[openr][openc] += 20; // 标记为39+}else if (map[openr][openc] >= 39) //如果格子没有打开,且有标记,才可以取消标记{mciSendString("close CLICK", 0, 0, 0); //停止上一次的点击音效mciSendString("open ./image/rightClick.wav alias CLICK", 0, 0, 0); //加载点击音效mciSendString("play CLICK", 0, 0, 0); //播放点击音效map[openr][openc] -= 20; // 取消标记}break;}}
}int main()
{// 创建窗口:一行有十张图片每张图片50pxinitgraph(IMG_SIZE * ROW, IMG_SIZE * COL);GameInit();show();// 游戏主循环while (true) {GameDraw();MouseEvent();}return 0;
}

(9)打包程序

打包教程

下载打包工具

(10)我的记录

在这里插入图片描述

目前个人最高记录,48秒,有没有来挑战我的?

在这里插入图片描述

http://www.dtcms.com/a/407948.html

相关文章:

  • 做网站租空间wordpress怎样发布
  • 网站建设优選宙斯站长网站自动识别手机代码
  • 永磁同步电机无速度算法--恒is的调整方法实现IF与SMO间的平滑切换
  • 网站建设评分标准网页游戏新区开服
  • 网站的版面设计邯郸网站设计制作
  • 做个网站 多少钱网站html模板下载
  • 月票车超时配置功能
  • 网站软件下载安装网站建设项目采购公告
  • jsp购物网站开发微信小程序与wordpress
  • AlmaLinux release 9.6服务器离线安装nginx-1.24.0详细步骤
  • 淘宝获取商品详情数据API接口PC端和App端的实际操作指南
  • 在哪个公司建设网站好设计网站页面要注意什么
  • 移动固态硬盘连接手机无法读取是什么原因?
  • 做阿里巴巴1688网站程序cms网站开发实验报告
  • 做美图+网站有哪些公司网站怎么做
  • Ubuntu24搭建PHP访问SQL Server环境
  • 甘州区建设局网站做logo的网站
  • 网站名 注册钓鱼网站搭建教程
  • 电子商务网站规划与建设步骤武夷山网站建设wzjseo
  • 学校网站开发免费行情软件app网站大全下载免费入口
  • 北京网站建设排行榜10条重大新闻事件
  • 阅读网站建设重庆网站关键字优化
  • C++基础(21)——内存管理
  • 企业网站建设的目的网页 网站 站点的区别
  • 图像分类项目
  • wordpress 英语太原seo优化公司
  • 专门做壁纸的网站传奇页游
  • ubuntu18.04 vsomeip的编译及使用
  • 自适应网站价格成都it公司排名
  • 长沙seo网站排名厦门同安网站建设