開發環境: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<conio.h> #include<stdio.h> #include<easyx.h> #include<time.h> #include<Windows.h> #include<mmsystem.h> //音樂 #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<conio.h> #include<stdio.h> #include<easyx.h> #include<time.h> #include<Windows.h> #include<mmsystem.h> #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); } }
總結
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注服務器之家的更多內容!
原文鏈接:https://blog.csdn.net/qq_53162179/article/details/120496585