c语言拼图游戏-PicturePuzzle
vtor3478@qq.com,2023年6月22日
https://www.cnblogs.com/vtor3478/articles/17498545.html
开发环境:使用vs2019,配合easyx图形库
基本设计:
注意,需要自行(寻找并)添加图片,在例子中,使用原神角色 甘雨进行游戏。
struct Block结构体:每个方块,都有坐标,以及对应的图片, 所以起码需要col,row,imgIdx。
init函数:然后使用easyx,初始化图片对象,,加载图片等。
paint函数:使用col得到y坐标,使用row得到x坐标,使用imgIdx得到确定图片,直接进行绘制图片,在程序中,增加了线,用于区分每个block。
userInput函数:使用easyx图形库,确定点击的坐标(x,y),
左击时,,,根据y得到col,根据x得到row,判断四个方向是否有空缺(注意防止越界),如果有空缺,交换两者的imgIdx,从而完成图片交换。
当完成游戏时,右击可重新开始游戏。
checkWin函数:检查block的imgidx是否有序即可。
拓展功能:
为了保证能完成拼图,打乱时,需要保证逆序数是偶数,两个循环比较一下即可。
以下是完整代码:
1 #include <stdio.h> 2 #include <time.h> 3 #include <easyx.h> 4 5 6 #define GAME_LEVEL 3 7 8 #define WINDOW_WIDTH 800 9 #define WINDOW_HEIGHT 800 10 11 12 #define X_OFFSET 0 13 #define Y_OFFSET 0 14 #define BLOCK_SIZE (WINDOW_HEIGHT / GAME_LEVEL) 15 16 #define GetXByCol(col) (col * BLOCK_SIZE + X_OFFSET) 17 #define GetYByRow(row) (row * BLOCK_SIZE + Y_OFFSET) 18 19 #define GetColByX(x) ((x - X_OFFSET) / BLOCK_SIZE) 20 #define GetRowByY(y) ((y - Y_OFFSET) / BLOCK_SIZE) 21 22 struct Block 23 { 24 int col, row; 25 int imgIdx; 26 }; 27 28 int colNum = GAME_LEVEL; 29 int rowNum = GAME_LEVEL; 30 31 int moveFlag = 0; 32 33 34 struct Block blocks[GAME_LEVEL][GAME_LEVEL] = {0}; 35 36 const char* imgFileString = { "res//ganyu-1280.png" }; 37 //const char* imgFileString = { "res//unable.png" }; 38 IMAGE wholeImg; 39 // https://wiki.biligame.com/ys/%E7%94%98%E9%9B%A8#/media/%E6%96%87%E4%BB%B6:%E7%94%98%E9%9B%A8%E7%AB%8B%E7%BB%98.png 40 IMAGE img[GAME_LEVEL * GAME_LEVEL] = { 0 }; 41 42 43 int getReverseOrder() 44 { 45 int reverseOrderCnt = 0; 46 for (int preOrder = 0; preOrder < colNum * rowNum - 1; preOrder++) { 47 for (int nextOrder = preOrder + 1; nextOrder < colNum * rowNum; nextOrder++) { 48 if (blocks[preOrder % colNum][preOrder / colNum].imgIdx != colNum * rowNum - 1 49 && blocks[nextOrder % colNum][nextOrder / colNum].imgIdx != colNum * rowNum - 1) { 50 if (blocks[preOrder % colNum][preOrder / colNum].imgIdx 51 > blocks[nextOrder % colNum][nextOrder / colNum].imgIdx) 52 { 53 reverseOrderCnt++; 54 } 55 } 56 } 57 } 58 return reverseOrderCnt; 59 } 60 61 bool checkWin() 62 { 63 bool winFlag = true; 64 for (int imgIdx = 0; imgIdx < colNum * rowNum - 1; imgIdx++) { 65 if (blocks[imgIdx % colNum][imgIdx / colNum].imgIdx != imgIdx) { 66 winFlag = false; 67 break; 68 } 69 } 70 return winFlag; 71 } 72 73 74 void start() 75 { 76 int swapCnt = 3; 77 while (1) 78 { 79 if ((swapCnt < 0) && (getReverseOrder() % 2 == 0)) 80 { 81 break; 82 } 83 int swapIdx1 = rand() % (colNum * rowNum - 1); 84 int swapIdx2 = rand() % (colNum * rowNum - 1); 85 int tempImgIdx = blocks[swapIdx1 / colNum][swapIdx1 % colNum].imgIdx; 86 blocks[swapIdx1 / colNum][swapIdx1 % colNum].imgIdx = blocks[swapIdx2 / colNum][swapIdx2 % colNum].imgIdx; 87 blocks[swapIdx2 / colNum][swapIdx2 % colNum].imgIdx = tempImgIdx; 88 swapCnt--; 89 } 90 91 } 92 93 94 void init() 95 { 96 srand(time(NULL)); 97 initgraph(WINDOW_WIDTH, WINDOW_HEIGHT, EW_SHOWCONSOLE); 98 // 加载到画面中,为下一步做准备 99 loadimage(&wholeImg, imgFileString, WINDOW_WIDTH, WINDOW_WIDTH); 100 putimage(0, 0, &wholeImg); 101 102 103 for (int row = 0; row < rowNum; row++) { 104 for (int col = 0; col < colNum; col++) { 105 blocks[col][row].col = col; 106 blocks[col][row].row = row; 107 // 先有序,然后进行打乱 108 blocks[col][row].imgIdx = row * rowNum + col; 109 110 if (row * colNum + col < colNum * rowNum - 1) 111 { 112 getimage(&img[blocks[col][row].imgIdx], 113 GetXByCol(col), 114 GetYByRow(row), 115 BLOCK_SIZE, 116 BLOCK_SIZE); 117 } 118 } 119 } 120 // 针对最后一张图片额外处理 121 //loadimage(&img[colNum * rowNum - 1], imgFileString, BLOCK_SIZE, BLOCK_SIZE); 122 cleardevice(); 123 } 124 125 126 void userInput() 127 { 128 MOUSEMSG msg; 129 if (PeekMouseMsg(&msg)) { 130 if (WM_LBUTTONDOWN == msg.uMsg) { 131 int clickCol, clickRow; 132 clickCol = GetColByX(msg.x); 133 clickRow = GetRowByY(msg.y); 134 printf("lbutton %d %d\r\n", clickCol, clickRow); 135 for (int around = -3; around <= 3; around +=2) 136 { 137 int aroundCol = clickCol + (around % 3); 138 int aroundRow = clickRow + (around / 3); 139 140 printf("around %d %d\r\n", aroundCol, aroundRow); 141 // 需要判断有效,防止越界访问 142 if (0 <= aroundRow && aroundRow < rowNum 143 && 0 <= aroundCol && aroundCol < colNum) { 144 // 如果有一个方向是空块,那么将进行坐标置换 145 if (blocks[aroundCol][aroundRow].imgIdx == rowNum * colNum - 1) { 146 int tempImgIdx = blocks[clickCol][clickRow].imgIdx; 147 blocks[clickCol][clickRow].imgIdx = blocks[aroundCol][aroundRow].imgIdx; 148 blocks[aroundCol][aroundRow].imgIdx = tempImgIdx; 149 break; 150 } 151 } 152 } 153 } 154 else if (WM_RBUTTONDOWN == msg.uMsg) { 155 // 游戏结束,右击,重新开始 156 if (checkWin()) 157 { 158 start(); 159 } 160 for (int row = 0; row < rowNum; row++) { 161 printf(" "); 162 for (int col = 0; col < colNum; col++) { 163 164 printf("%d %d %d\t\t", 165 blocks[col][row].col, 166 blocks[col][row].row, 167 blocks[col][row].imgIdx); 168 } 169 printf("\r\n"); 170 } 171 printf("getReverseOrder = %d\r\n\r\n", getReverseOrder()); 172 } 173 174 } 175 } 176 177 void paint() 178 { 179 BeginBatchDraw(); 180 cleardevice(); 181 for (int row = 0; row < rowNum; row++) { 182 for (int col = 0; col < colNum; col++) { 183 putimage( 184 GetXByCol(blocks[col][row].col), 185 GetYByRow(blocks[col][row].row), 186 &img[blocks[col][row].imgIdx]); 187 } 188 } 189 190 setlinestyle(0, 3); 191 setlinecolor(RGB(0, 0, 255)); 192 for (int row = 1; row < rowNum; row++) { 193 line(0, row * BLOCK_SIZE, (colNum + 1) * BLOCK_SIZE, row * BLOCK_SIZE); 194 } 195 for (int col = 1; col < colNum; col++) { 196 line(col * BLOCK_SIZE, 0, col * BLOCK_SIZE, (rowNum + 1) * BLOCK_SIZE); 197 } 198 EndBatchDraw(); 199 } 200 201 202 int main(void) 203 { 204 init(); 205 start(); 206 while (1) { 207 // 当逆序为0时,说明游戏成功 208 if (checkWin()) { 209 BeginBatchDraw(); 210 putimage(0, 0, &wholeImg); 211 EndBatchDraw(); 212 } else { 213 paint(); 214 } 215 userInput(); 216 } 217 system("pause"); 218 return 0; 219 }