C++语言实现拼图游戏详解

目录

  • 开发环境:Visual Studio 2019,easyx图形库。
    • 游戏功能列表:
    • 游戏效果
    • 一.头文件和基本量
    • 二.封面
    • 三.数据初始化
    • 四.封面规则按钮
    • 五.构造拼图
    • 六.绘图函数
    • 七.背景音乐
    • 八.数据更新
    • 九.通关判断
    • 十.完整程序
  • 总结

    开发环境:Visual Studio 2019,easyx图形库。 easyx下载官网:
    EasyX Graphics Library for C++
    https://easyx.cn/
    easyx使用文档:
    EasyX 文档 - 函数说明
    https://docs.easyx.cn/zh-cn/reference

    游戏功能列表:
    其主要功能描述如下:
    1.图片尺寸自适应
    2.图片动态分割
    3.查看原图
    4.随机切换图片
    5.鼠标拖动拼图<——>交换拼图块
    6.自动判断拼图成功
    拓展功能:
    • 背景音乐(开,关)
    • 游戏中Esc键返回桌面
    • 游戏规则窗口


    游戏效果
    C++语言实现拼图游戏详解
    文章图片

    封面(音乐按钮有点拉跨~)
    C++语言实现拼图游戏详解
    文章图片

    游戏初始图(我的心是冰冰的)
    C++语言实现拼图游戏详解
    文章图片

    通关图

    一.头文件和基本量
    #include#include#include#include#include#include//音乐#pragma comment(lib,"Winmm.lib")//静态库,调用音乐using namespace std; constexpr auto N = 3; //3*3拼图IMAGE img[4], imgs[9]; //img存整张图片,imgs暂存拼图块int aim_c, aim_r; //拼图块坐标int map[3][3] = { 0 }; //存拼图块int NUM = 0; //关卡数计数


    二.封面
    //开始界面void start(){ loadimage(NULL, L"cover.jpg"); setbkmode(TRANSPARENT); settextcolor(BLACK); settextstyle(60, 0, _T("楷体"),0,0,4,false,false,false); outtextxy(180, 120, L"拼图游戏"); //游戏名称 settextstyle(30, 0, _T("微软雅黑")); setfillcolor(BROWN); setlinestyle(BS_SOLID, 5); setlinecolor(RED); fillroundrect(220, 220, 370, 270, 10, 10); settextstyle(30, 0, _T("宋体"), 0, 0, 6, false, false, false); //开始按钮 outtextxy(270, 230, L"开始"); fillroundrect(220, 300, 370, 350, 10, 10); outtextxy(240, 310, L"游戏规则"); setfillcolor(BROWN); setlinestyle(BS_SOLID, 5); setlinecolor(BLACK); fillcircle(490, 440, 30); //音乐控制按钮:开 fillcircle(560, 440, 30); //音乐控制按钮:关 outtextxy(380, 430, L"音乐:"); setfillcolor(BLACK); POINT pts[] = { {481,425},{481,455},{507,440} }; fillpolygon(pts, 3); fillrectangle(546, 425, 554, 455); fillrectangle(566, 425, 574, 455); rules(); }


    三.数据初始化
    //游戏初始化void init(){ //加载资源图片,4张图4个关卡 loadimage(&img[0], L"picture1.jpg",600, 600); loadimage(&img[1], L"picture2.jpg", 600, 600); loadimage(&img[2], L"picture3.jpg", 600, 600); loadimage(&img[3], L"picture4.jpg", 600, 600); //设置最后一张图片为空白图片,作为目标图片 loadimage(&imgs[8], L"white.jpg", 200, 200); //设置随机种子 srand((unsigned)time(NULL)); }


    四.封面规则按钮
    //封面规则函数int rules(){ExMessage Mou; //鼠标消息while (1){Mou = getmessage(EM_MOUSE); switch (Mou.message)//对鼠标信息进行匹配{case WM_LBUTTONDOWN://按下左键if (Mou.x >= 220 && Mou.x <= 370 && Mou.y >= 300 && Mou.y <= 350){HWND hwnd = GetHWnd(); MessageBox(NULL, L"1.鼠标左键点击空白图处周围图片交换位置\n2.鼠标右键任意处按下显示参照图片\n3.鼠标中键更换背景图片\n4.按Esc键返回封面", L"游戏规则", MB_OKCANCEL); break; //规则按钮}if (Mou.x >= 220 && Mou.x <= 370 && Mou.y >= 220 && Mou.y <= 270){return 0; //开始按钮}if (Mou.x >= 460 && Mou.x <= 520 && Mou.y >= 410 && Mou.y <= 470){BGM(); //音乐播放按钮break; }if (Mou.x >= 530 && Mou.x <= 590 && Mou.y >= 410 && Mou.y <= 470){mciSendString(L"close back", 0, 0, 0); //音乐关闭按钮break; }}} }


    五.构造拼图
    //拼图构造函数void GameInit(){ //把拼图贴上去 putimage(0, 0, &img[NUM]); //设置绘图目标为img对象对拼图图片进行切割 SetWorkingImage(&img[NUM]); for (int y = 0, n = 0; y < N; y++) {for (int x = 0; x < N; x++){if (n == 8) break; //获取100*100像素图片,存储在img中;getimage(&imgs[n++], x * 200, y * 200, (x + 1) * 200, (y + 1) * 200); } } //设置绘图目标为绘图窗口 SetWorkingImage(); //初始化地图0~15 for (int i = 0, k = 0; i < N; i++) {for (int j = 0; j < N; j++){map[i][j] = k++; } } //打乱地图 for (int k = 0; k <= 1000; k++) {//得到目标所在的行和列for (int i = 0; i < N; i++){for (int j = 0; j < N; j++){if (map[i][j] == 8)//空白图片作为交换目标{aim_r = i; aim_c = j; break; }}}//一千次打乱顺序之后需要将空白图片转移到右下角//可以封装成函数下面这个代码if (k == 1000){//将空白图片循环转移到右下角while (aim_r < 2){//保证空白目标在最下map[aim_r][aim_c] = map[aim_r + 1][aim_c]; map[aim_r + 1][aim_c] = 8; aim_r++; }while (aim_c < 2){//保证空白目标在最右map[aim_r][aim_c] = map[aim_r][aim_c + 1]; map[aim_r][aim_c + 1] = 8; aim_c++; }return; }int dir = rand() % 4; //随机一个方向switch (dir){case 0://向上交换if (aim_r >= 1){//空白图片和空白处上面的图片交换map[aim_r][aim_c] = map[aim_r - 1][aim_c]; map[aim_r - 1][aim_c] = 8; break; }case 1://向下交换if (aim_r < 2){//空白图片和空白处下面的图片交换map[aim_r][aim_c] = map[aim_r + 1][aim_c]; map[aim_r + 1][aim_c] = 8; break; }case 2://向左交换if (aim_c >= 1){//空白图片和空白处左边的图片交换map[aim_r][aim_c] = map[aim_r][aim_c - 1]; map[aim_r][aim_c - 1] = 8; break; }case 3://向右交换if (aim_c < 2){//空白图片和空白处右边的图片交换 map[aim_r][aim_c] = map[aim_r][aim_c + 1]; map[aim_r][aim_c + 1] = 8; break; }} }}


    六.绘图函数
    //绘图函数void DrawMap(){ FlushBatchDraw(); //开始渲染图片 for (int y = 0; y < N; y++) {for (int x = 0; x < N; x++){putimage(x * 200, y * 200, &imgs[map[y][x]]); } } EndBatchDraw(); }


    七.背景音乐
    //背景音乐函数void BGM(){ //打开音乐,播放音乐 mciSendStringW(L"open ./Thrills.mp3 alias back", NULL, 0, NULL); mciSendStringW(_T("play back repeat"), 0, 0, 0); }


    八.数据更新
    //数据更新函数void play(){ int col, row; //鼠标点击的位置 ExMessage msg; //鼠标消息 msg = getmessage(EM_MOUSE|EM_KEY); //获取鼠标消息 switch (msg.message)//对鼠标消息进行匹配 { case WM_LBUTTONDOWN://当鼠标消息是左键按下时//获取鼠标按下所在列col = msg.x / 200; if (msg.x == 600)col = 2; //获取鼠标按下所在行row = msg.y / 200; if (msg.y == 600)row = 2; //得到目标所在行和列for (int i = 0; i < N; i++){for (int j = 0; j < N; j++){if (map[i][j] == 8)//空白处为交换目标{aim_r = i; aim_c = j; }}}//判断鼠标点击位置和目标是否相邻,相邻交换数据if (row == aim_r && col == aim_c + 1 ||row == aim_r && col == aim_c - 1 ||row == aim_r + 1 && col == aim_c ||row == aim_r - 1 && col == aim_c){//鼠标点击图片和空白目标图片交换map[aim_r][aim_c] = map[row][col]; map[row][col] = 8; }DrawMap(); break; case WM_RBUTTONDOWN: //当鼠标消息是右键按下时putimage(0, 0, &img[NUM]); //将关卡图片贴到窗口上break; case WM_RBUTTONUP://当鼠标消息是右键抬起时DrawMap(); break; case WM_MBUTTONDOWN:NUM++; if (NUM == 4)NUM = 0; //返回第一张图//重新开始游戏GameInit(); //游戏初始化DrawMap(); //渲染地图break; case WM_KEYDOWN:if (msg.vkcode == VK_ESCAPE)//按Esc键返回封面{start(); break; } } }


    九.通关判断
    //通关判断函数void Judge(){ //判断当前每张图片是否在对应位置 if (map[0][0] == 0 && map[0][1] == 1 && map[0][2] == 2 &&map[1][0] == 3 && map[1][1] == 4 && map[1][2] == 5 &&map[2][0] == 6 && map[2][1] ==7 && map[2][2] == 8 ) {//挑战成功之后将全图贴上putimage(0, 0, &img[NUM++]); //四个关卡都胜利之后退出程序if (NUM == 4){MessageBox(GetHWnd(), L"挑战成功", L"Vectory", MB_OK); exit(0); return; }//每过一个关卡判断是否进入下一个关卡if (MessageBox(GetHWnd(), L"是否进入下一关", L"Vectory", MB_YESNO) == IDYES){//重新开始游戏GameInit(); //游戏初始化DrawMap(); //渲染地图}//退出游戏else exit(0); }}


    十.完整程序
    #include#include#include#include#include#include#pragma comment(lib,"Winmm.lib") using namespace std; constexpr auto N = 3; IMAGE img[4], imgs[9]; int aim_c, aim_r; int map[3][3] = { 0 }; int NUM = 0; //游戏规则,开始界面设计void start(); //封面按钮int rules(); //加载资源void init(); //游戏数据初始化void GameInit(); //游戏渲染void DrawMap(); //播放音乐void BGM(); //玩家操作void play(); //判断输赢void Judge(); int main(){ //设置窗口大小 initgraph(6 * 100, 6 * 100); //设置图片 start(); init(); GameInit(); DrawMap(); while (1) {play(); Judge(); } system("pause"); //等待用户按键 closegraph(); return 0; }//开始界面void start(){ loadimage(NULL, L"cover.jpg"); setbkmode(TRANSPARENT); settextcolor(BLACK); settextstyle(60, 0, _T("楷体"),0,0,4,false,false,false); outtextxy(180, 120, L"拼图游戏"); //游戏名称 settextstyle(30, 0, _T("微软雅黑")); setfillcolor(BROWN); setlinestyle(BS_SOLID, 5); setlinecolor(RED); fillroundrect(220, 220, 370, 270, 10, 10); settextstyle(30, 0, _T("宋体"), 0, 0, 6, false, false, false); //开始按钮 outtextxy(270, 230, L"开始"); fillroundrect(220, 300, 370, 350, 10, 10); outtextxy(240, 310, L"游戏规则"); setfillcolor(BROWN); setlinestyle(BS_SOLID, 5); setlinecolor(BLACK); fillcircle(490, 440, 30); //音乐控制按钮:开 fillcircle(560, 440, 30); //音乐控制按钮:关 outtextxy(380, 430, L"音乐:"); setfillcolor(BLACK); POINT pts[] = { {481,425},{481,455},{507,440} }; fillpolygon(pts, 3); fillrectangle(546, 425, 554, 455); fillrectangle(566, 425, 574, 455); rules(); }//游戏初始化void init(){ //加载资源图片,4张图4个关卡 loadimage(&img[0], L"picture1.jpg",600, 600); loadimage(&img[1], L"picture2.jpg", 600, 600); loadimage(&img[2], L"picture3.jpg", 600, 600); loadimage(&img[3], L"picture4.jpg", 600, 600); //设置最后一张图片为空白图片,作为目标图片 loadimage(&imgs[8], L"white.jpg", 200, 200); //设置随机种子 srand((unsigned)time(NULL)); }//封面选项函数int rules(){ExMessage Mou; //鼠标消息while (1){Mou = getmessage(EM_MOUSE); switch (Mou.message)//对鼠标信息进行匹配{case WM_LBUTTONDOWN://按下左键if (Mou.x >= 220 && Mou.x <= 370 && Mou.y >= 300 && Mou.y <= 350){HWND hwnd = GetHWnd(); MessageBox(NULL, L"1.鼠标左键点击空白图处周围图片交换位置\n2.鼠标右键任意处按下显示参照图片\n3.鼠标中键更换背景图片\n4.按Esc键返回封面", L"游戏规则", MB_OKCANCEL); break; //规则按钮}if (Mou.x >= 220 && Mou.x <= 370 && Mou.y >= 220 && Mou.y <= 270){return 0; //开始按钮}if (Mou.x >= 460 && Mou.x <= 520 && Mou.y >= 410 && Mou.y <= 470){BGM(); //音乐播放按钮break; }if (Mou.x >= 530 && Mou.x <= 590 && Mou.y >= 410 && Mou.y <= 470){mciSendString(L"close back", 0, 0, 0); //音乐关闭按钮break; }}} }//拼图构造函数void GameInit(){ //把拼图贴上去 putimage(0, 0, &img[NUM]); //设置绘图目标为img对象对拼图图片进行切割 SetWorkingImage(&img[NUM]); for (int y = 0, n = 0; y < N; y++) {for (int x = 0; x < N; x++){if (n == 8) break; //获取100*100像素图片,存储在img中;getimage(&imgs[n++], x * 200, y * 200, (x + 1) * 200, (y + 1) * 200); } } //设置绘图目标为绘图窗口 SetWorkingImage(); //初始化地图0~15 for (int i = 0, k = 0; i < N; i++) {for (int j = 0; j < N; j++){map[i][j] = k++; } } //打乱地图 for (int k = 0; k <= 1000; k++) {//得到目标所在的行和列for (int i = 0; i < N; i++){for (int j = 0; j < N; j++){if (map[i][j] == 8)//空白图片作为交换目标{aim_r = i; aim_c = j; break; }}}//一千次打乱顺序之后需要将空白图片转移到右下角//可以封装成函数下面这个代码if (k == 1000){//将空白图片循环转移到右下角while (aim_r < 2){//保证空白目标在最下map[aim_r][aim_c] = map[aim_r + 1][aim_c]; map[aim_r + 1][aim_c] = 8; aim_r++; }while (aim_c < 2){//保证空白目标在最右map[aim_r][aim_c] = map[aim_r][aim_c + 1]; map[aim_r][aim_c + 1] = 8; aim_c++; }return; }int dir = rand() % 4; //随机一个方向switch (dir){case 0://向上交换if (aim_r >= 1){//空白图片和空白处上面的图片交换map[aim_r][aim_c] = map[aim_r - 1][aim_c]; map[aim_r - 1][aim_c] = 8; break; }case 1://向下交换if (aim_r < 2){//空白图片和空白处下面的图片交换map[aim_r][aim_c] = map[aim_r + 1][aim_c]; map[aim_r + 1][aim_c] = 8; break; }case 2://向左交换if (aim_c >= 1){//空白图片和空白处左边的图片交换map[aim_r][aim_c] = map[aim_r][aim_c - 1]; map[aim_r][aim_c - 1] = 8; break; }case 3://向右交换if (aim_c < 2){//空白图片和空白处右边的图片交换 map[aim_r][aim_c] = map[aim_r][aim_c + 1]; map[aim_r][aim_c + 1] = 8; break; }} }}//绘图函数void DrawMap(){ FlushBatchDraw(); //开始渲染图片 for (int y = 0; y < N; y++) {for (int x = 0; x < N; x++){putimage(x * 200, y * 200, &imgs[map[y][x]]); } } EndBatchDraw(); }//背景音乐函数void BGM(){ //打开音乐,播放音乐 mciSendStringW(L"open ./Thrills.mp3 alias back", NULL, 0, NULL); mciSendStringW(_T("play back repeat"), 0, 0, 0); }//数据更新函数void play(){ int col, row; //鼠标点击的位置 ExMessage msg; //鼠标消息 msg = getmessage(EM_MOUSE|EM_KEY); //获取鼠标消息 switch (msg.message)//对鼠标消息进行匹配 { case WM_LBUTTONDOWN://当鼠标消息是左键按下时//获取鼠标按下所在列col = msg.x / 200; if (msg.x == 600)col = 2; //获取鼠标按下所在行row = msg.y / 200; if (msg.y == 600)row = 2; //得到目标所在行和列for (int i = 0; i < N; i++){for (int j = 0; j < N; j++){if (map[i][j] == 8)//空白处为交换目标{aim_r = i; aim_c = j; }}}//判断鼠标点击位置和目标是否相邻,相邻交换数据if (row == aim_r && col == aim_c + 1 ||row == aim_r && col == aim_c - 1 ||row == aim_r + 1 && col == aim_c ||row == aim_r - 1 && col == aim_c){//鼠标点击图片和空白目标图片交换map[aim_r][aim_c] = map[row][col]; map[row][col] = 8; }DrawMap(); break; case WM_RBUTTONDOWN: //当鼠标消息是右键按下时putimage(0, 0, &img[NUM]); //将关卡图片贴到窗口上break; case WM_RBUTTONUP://当鼠标消息是右键抬起时DrawMap(); break; case WM_MBUTTONDOWN:NUM++; if (NUM == 4)NUM = 0; //返回第一张图//重新开始游戏GameInit(); //游戏初始化DrawMap(); //渲染地图break; case WM_KEYDOWN:if (msg.vkcode == VK_ESCAPE)//按Esc键返回封面{start(); break; } } }//通关判断函数void Judge(){ //判断当前每张图片是否在对应位置 if (map[0][0] == 0 && map[0][1] == 1 && map[0][2] == 2 &&map[1][0] == 3 && map[1][1] == 4 && map[1][2] == 5 &&map[2][0] == 6 && map[2][1] ==7 && map[2][2] == 8 ) {//挑战成功之后将全图贴上putimage(0, 0, &img[NUM++]); //四个关卡都胜利之后退出程序if (NUM == 4){MessageBox(GetHWnd(), L"挑战成功", L"Vectory", MB_OK); exit(0); return; }//每过一个关卡判断是否进入下一个关卡if (MessageBox(GetHWnd(), L"是否进入下一关", L"Vectory", MB_YESNO) == IDYES){//重新开始游戏GameInit(); //游戏初始化DrawMap(); //渲染地图}//退出游戏else exit(0); }}


    总结 【C++语言实现拼图游戏详解】本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

      推荐阅读