本帖最后由 vtor 于 2023-6-22 23:45 编辑
c语言拼图游戏-PicturePuzzle2023年6月22日 ​
开发环境:使用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是否有序即可。
拓展功能:
为了保证能完成拼图,打乱时,需要保证逆序数是偶数,两个循环比较一下即可。
以下是完整代码:
[C++] 纯文本查看 复制代码 #include <stdio.h>
#include <time.h>
#include <easyx.h>
#define GAME_LEVEL 3
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 800
#define X_OFFSET 0
#define Y_OFFSET 0
#define BLOCK_SIZE (WINDOW_HEIGHT / GAME_LEVEL)
#define GetXByCol(col) (col * BLOCK_SIZE + X_OFFSET)
#define GetYByRow(row) (row * BLOCK_SIZE + Y_OFFSET)
#define GetColByX(x) ((x - X_OFFSET) / BLOCK_SIZE)
#define GetRowByY(y) ((y - Y_OFFSET) / BLOCK_SIZE)
struct Block
{
int col, row;
int imgIdx;
};
int colNum = GAME_LEVEL;
int rowNum = GAME_LEVEL;
int moveFlag = 0;
struct Block blocks[GAME_LEVEL][GAME_LEVEL] = {0};
const char* imgFileString = { "res//ganyu-1280.png" };
//const char* imgFileString = { "res//unable.png" };
IMAGE wholeImg;
// 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
IMAGE img[GAME_LEVEL * GAME_LEVEL] = { 0 };
int getReverseOrder()
{
int reverseOrderCnt = 0;
for (int preOrder = 0; preOrder < colNum * rowNum - 1; preOrder++) {
for (int nextOrder = preOrder + 1; nextOrder < colNum * rowNum; nextOrder++) {
if (blocks[preOrder % colNum][preOrder / colNum].imgIdx != colNum * rowNum - 1
&& blocks[nextOrder % colNum][nextOrder / colNum].imgIdx != colNum * rowNum - 1) {
if (blocks[preOrder % colNum][preOrder / colNum].imgIdx
> blocks[nextOrder % colNum][nextOrder / colNum].imgIdx)
{
reverseOrderCnt++;
}
}
}
}
return reverseOrderCnt;
}
bool checkWin()
{
bool winFlag = true;
for (int imgIdx = 0; imgIdx < colNum * rowNum - 1; imgIdx++) {
if (blocks[imgIdx % colNum][imgIdx / colNum].imgIdx != imgIdx) {
winFlag = false;
break;
}
}
return winFlag;
}
void start()
{
int swapCnt = 3;
while (1)
{
if ((swapCnt < 0) && (getReverseOrder() % 2 == 0))
{
break;
}
int swapIdx1 = rand() % (colNum * rowNum - 1);
int swapIdx2 = rand() % (colNum * rowNum - 1);
int tempImgIdx = blocks[swapIdx1 / colNum][swapIdx1 % colNum].imgIdx;
blocks[swapIdx1 / colNum][swapIdx1 % colNum].imgIdx = blocks[swapIdx2 / colNum][swapIdx2 % colNum].imgIdx;
blocks[swapIdx2 / colNum][swapIdx2 % colNum].imgIdx = tempImgIdx;
swapCnt--;
}
}
void init()
{
srand(time(NULL));
initgraph(WINDOW_WIDTH, WINDOW_HEIGHT, EW_SHOWCONSOLE);
// 加载到画面中,为下一步做准备
loadimage(&wholeImg, imgFileString, WINDOW_WIDTH, WINDOW_WIDTH);
putimage(0, 0, &wholeImg);
for (int row = 0; row < rowNum; row++) {
for (int col = 0; col < colNum; col++) {
blocks[col][row].col = col;
blocks[col][row].row = row;
// 先有序,然后进行打乱
blocks[col][row].imgIdx = row * rowNum + col;
if (row * colNum + col < colNum * rowNum - 1)
{
getimage(&img[blocks[col][row].imgIdx],
GetXByCol(col),
GetYByRow(row),
BLOCK_SIZE,
BLOCK_SIZE);
}
}
}
// 针对最后一张图片额外处理
//loadimage(&img[colNum * rowNum - 1], imgFileString, BLOCK_SIZE, BLOCK_SIZE);
cleardevice();
}
void userInput()
{
MOUSEMSG msg;
if (PeekMouseMsg(&msg)) {
if (WM_LBUTTONDOWN == msg.uMsg) {
int clickCol, clickRow;
clickCol = GetColByX(msg.x);
clickRow = GetRowByY(msg.y);
printf("lbutton %d %d\r\n", clickCol, clickRow);
for (int around = -3; around <= 3; around +=2)
{
int aroundCol = clickCol + (around % 3);
int aroundRow = clickRow + (around / 3);
printf("around %d %d\r\n", aroundCol, aroundRow);
// 需要判断有效,防止越界访问
if (0 <= aroundRow && aroundRow < rowNum
&& 0 <= aroundCol && aroundCol < colNum) {
// 如果有一个方向是空块,那么将进行坐标置换
if (blocks[aroundCol][aroundRow].imgIdx == rowNum * colNum - 1) {
int tempImgIdx = blocks[clickCol][clickRow].imgIdx;
blocks[clickCol][clickRow].imgIdx = blocks[aroundCol][aroundRow].imgIdx;
blocks[aroundCol][aroundRow].imgIdx = tempImgIdx;
break;
}
}
}
}
else if (WM_RBUTTONDOWN == msg.uMsg) {
// 游戏结束,右击,重新开始
if (checkWin())
{
start();
}
for (int row = 0; row < rowNum; row++) {
printf(" ");
for (int col = 0; col < colNum; col++) {
printf("%d %d %d\t\t",
blocks[col][row].col,
blocks[col][row].row,
blocks[col][row].imgIdx);
}
printf("\r\n");
}
printf("getReverseOrder = %d\r\n\r\n", getReverseOrder());
}
}
}
void paint()
{
BeginBatchDraw();
cleardevice();
for (int row = 0; row < rowNum; row++) {
for (int col = 0; col < colNum; col++) {
putimage(
GetXByCol(blocks[col][row].col),
GetYByRow(blocks[col][row].row),
&img[blocks[col][row].imgIdx]);
}
}
setlinestyle(0, 3);
setlinecolor(RGB(0, 0, 255));
for (int row = 1; row < rowNum; row++) {
line(0, row * BLOCK_SIZE, (colNum + 1) * BLOCK_SIZE, row * BLOCK_SIZE);
}
for (int col = 1; col < colNum; col++) {
line(col * BLOCK_SIZE, 0, col * BLOCK_SIZE, (rowNum + 1) * BLOCK_SIZE);
}
EndBatchDraw();
}
int main(void)
{
init();
start();
while (1) {
// 当逆序为0时,说明游戏成功
if (checkWin()) {
BeginBatchDraw();
putimage(0, 0, &wholeImg);
EndBatchDraw();
} else {
paint();
}
userInput();
}
system("pause");
return 0;
} |