时间:2017年8月28日
呼,感觉小游戏里拼图(puzzle)游戏算是最简单的几个游戏之一了吧
代码比较简单,因为今天是七夕,所以用了单身狗为主题,学c挺好,单身到老啊!
哈哈,各位码农节日快乐
编程语言:c语言
编译环境:vs,easyx图形库
基本操作:方向键,WASD键控制方向,esc退出游戏
github:点击打开链接
1.找到一张图,用ps分成3*3的小方格,标记为1-9.jpg(方便函数调用),
这里我选取了一张273*300的图片(完整的原图),可以分成9张91*100的图片
另外加了一张91*100的白色图片
准备了一首音乐,前段时间挺火的single dog……
这样放入exe目录下的编辑好的文件夹里,素材就准备好了
2.有这样几个函数,有几个是类似于推箱子游戏的,相信做过推箱子游戏的会比较了解
这里先放一下函数声明
#include
#include
#include"graphics.h"
#include
#include
#pragma comment(lib,"winmm.lib")
void GameInit();
void draw();
void game();
int judge();
void menu();
IMAGE img[11];//封面图1张,3*3拼图的9小张,1张空白小图
int p[3][3];//拼图的数组
int gn= 0;//变为空白小图的地方
HWND hWnd;//窗口句柄
重点说一下这里的逆序数和曼哈顿距离运用,
我们用1-9数值代表拼图的图片
百度上关于逆序数的介绍如下
点击打开链接
曼哈顿距离
点击打开链接
总状态数=行数*列数-1+gn到左下角数组的曼哈顿距离(gn是当前空白图)
拼图的当前状态数=逆序数+空白图片到左下角数组(这里是[2][2])的曼哈顿距离
逆序数为0(拼好了);
状态数与总状态数奇偶性一致,才能顺利拼图(排除不能还原拼图的情况)
在3*3拼图里,
总状态数为3*3-1=8,为偶数
所以有
状态数为奇数,不可以拼图;
状态数为偶数,可以拼图,但尚未拼好;
int judge()
{
int i, j,x=0;
int s;
s= 0;
int manha=0;
int b[N*N];
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
{
if (p[i][j])
b[x++] = p[i][j];
else b[x++] = gn;
}
for (i = 0; i < (N*N-1);i++)
for (j = (N*N-1); j>i; j--)
{
if (b[i]>b[j])s++;
}
int m, n;
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
{
if (p[i][j] == 0)
{
m = i; n = j; break;
}
}
manha = N-1 - m + N-1 - n;
if (s==0)
return 2;
if ((s + manha) % 2 == (N * N - 1 + 2 - (gn - 1) / N
+ 2 - gn + ((gn - 1) / N) * N + 1) % 2)
return 0;
return 1;
}
根据这个judge函数,最终返回值可以为
0,可以拼图;
1,无法拼图;
2,拼图按拼好的顺序,1-9依次排列,游戏胜利。
GameInit函数里,初始化函数时,结合judge函数打乱了一下拼图
void GameInit()
{
int i, j, x = 1;
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
{
p[i][j] = x++;
}
srand((unsigned)time(NULL));
int temp;
while (gn== 0)gn= rand() % 10;
p[(gn- 1) / 3][2 - gn % 3] = 0;
while (judge() != 0) //取状态为偶数,而且未还原的状态
{for (int t = 0; t < 2; t++)
{
temp = p[t][t];
p[t][t] =p[t][t+1];
p[t][t + 1] = temp;
}
for (int t = 0; t < 2; t++)
{
temp = p[t][t];
p[t][t] = p[t + 1][t ];
p[t + 1][t] = temp;
}
}
}
while (judge() != 0) //取状态为偶数,而且未还原的状态
{for (int t = 0; t < 2; t++)
{
temp = p[t][t];
p[t][t] =p[t][t+1];
p[t][t + 1] = temp;
}
for (int t = 0; t < 2; t++)
{
temp = p[t][t];
p[t][t] = p[t + 1][t ];
p[t + 1][t] = temp;
}
}
}
这里int了gn(gn是全局变量),
用rand()对它进行取值,使gn的值在1-9之间
(使得9张图中一张变为空白,进行游戏)
p[(gn- 1) / 3][gn-((gn-1)/3+1)*3] = 0;
用这一段使gn数值的方块变为空白图,也就是文件夹里的0.jpg空白图
(gn- 1) / 3
为gn的行数
gn-((gn-1)/3+1)*3
为gn的列数
红色的代码部分有待争议,
因为是我自己临时编的打乱拼图顺序的代码,
有建议更改的欢迎指出
之后是和推箱子游戏等类似的draw画图函数,和利用getch()读取输入
的game()游戏函数
放一段w,和方向键向上控制的代码
void game()
{
char ch;
int m, n;
int i, j;
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
{
if (p[i][j] == 0)
{
m = i; n = j;//保留下0空白位置的数组下标
}
}
ch = getch();
switch (ch)
{
case 'w':
case 'W':
case 72:if (m != 2){
p[m][n] = p[m + 1][n];
p[m + 1][n] = 0;}
break;
其余的A,S,D的情况就有劳大家自行脑补了,哈哈
外加一个开始的menu()函数
做出这样的效果:
放置一张封面图,并给出messagebox,提示是否开始游戏
这里放一下播放音乐的代码
需要嵌入相应的头文件
mciSendString(L"open ./res/单身狗之歌.mp3 alias bgm", 0, 0, 0);
mciSendString(L"play bgm repeat", 0, 0, 0);
主函数里主要的部分为
menu();
GameInit();
while (1)
{
draw();
game();
if (judge()==2)break;
}
hWnd=GetForegroundWindow();
MessageBoxA(hWnd, "恭喜通关,节日快乐!", "恭喜通关", MB_OK);
return 0;
之后再拼好图,judge会返回2,循环也就break掉,
游戏结束,会出现messagebox的弹窗,
算是一点节日的小创意吧
以上就是所谓的“单身狗拼图游戏”了,逆序数的想法是之前看的网上的
代码上传到了github
点击打开链接
谢谢你的观看,欢迎评论互相学习,互相进步。