如何使用C++语言实现拼图游戏
发表于:2025-02-19 作者:千家信息网编辑
千家信息网最后更新 2025年02月19日,小编给大家分享一下如何使用C++语言实现拼图游戏,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!开发环境:Visual St
千家信息网最后更新 2025年02月19日如何使用C++语言实现拼图游戏
小编给大家分享一下如何使用C++语言实现拼图游戏,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
开发环境: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键返回桌面
游戏规则窗口
游戏效果
封面(音乐按钮有点拉跨~)
游戏初始图(我的心是冰冰的)
通关图
一.头文件和基本量
#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++语言实现拼图游戏"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!
图片
鼠标
空白
目标
音乐
函数
消息
关卡
按钮
绘图
地图
封面
所在
数据
位置
规则
j++
成功
图贴
游戏规则
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
超级计算机是不是和服务器差不多
网络安全文明
直接成本软件开发
软件开发职业技能等级考试
西电的服务器
我的网络安全故事
数据库表引用方法
战神引擎连接不上数据库
酒店网络技术方案
java怎么看数据库查到的数据
工信部网络安全局工业互联网
绍兴安卓软件开发
花雨庭服务器ip
网络安全讲座感悟50字
重庆移动软件开发代码
芜湖安卓应用软件开发价格
第几个网络安全日
网络安全法韩国
银行软件开发中心面经
数据库的布尔类型
闵行区推广软件开发供应商
竞选网络技术部入部
软件开发职业技能等级考试
男爵领域服务器
咸阳公安网络安全
哈尔滨奇配网络技术服务
jdbc两个数据库连接
学软件开发和学网络工程哪个好
主要目的是为了实现数据库的
数据库的三级模式