基于MATLAB的⼩游戏(puzzle)
更新:
没有素材或者.mat⽂件看着博客也⽐较难实现,下⾯是完整的游戏⽂件
链接:
提取码:uo2x
游戏画⾯:
注:⽂章开始写的时候还没有考虑到⾼阶的扩展的问题,⾼阶扩展部分的代码更具有普遍性,可以直接跳过前⾯的代码设计看⾼阶扩展部分。
游戏介绍
游戏玩法来源
游戏的玩法规则并⾮原创,最早看到是多年前百度魔⽅吧有⼈制作了可以在⽹页上玩的版本,同时还制作了4×4版本。⽹页连接很早之前就失效,作者也不可考。感谢作者制作了这样⼀个有意思的⼩游戏。
设计参考
主要来⾃桥上风景楼上的你的博客,基于MATLAB的拼图游戏设计(图⽂详解,附完整代码)
两个游戏有很多相似之处,这篇⽂章条理很清晰,对于整个编写过程带来了很⼤帮助。
规则和功能
⼩游戏的基本规则:如图所⽰,点击某⼀个⽅块⾃⾝及相邻的⽅块数值加⼀,到达最⼤值(设定的是9)循环回最⼩值(1),最⼩值的索引不是0⽽是1对应了Matlab的索引下标是1起始。
游戏⽬标:通过点击⽅块使所有的⽅块的值相同。
当玩家完成后显⽰步数和胜利语句。
⼀些定义
游戏画⾯有长宽两个维度,同时还有数字循环的次数。
仿照魔⽅将维度定义为m×n,可以在后续看到这个游戏的长宽不⼀定需要相等。
将⼀个循环中有的数字个数称之为深度。
设计逻辑
仿照桥上风景楼上的你的⽂章也画了⼀张流程图。两个游戏的基本逻辑相似。
前期准备
⾸先是绘制这⼏张图⽚(我是⽤画图软件画的)。
然后⽤imread()读⼊Matlab,直接拼接成⼀长条。
网页游戏小游戏img=[];
for k=1:9
img=[img,imread(strcat(num2str(k),'.png'))];
end
imshow(img)%显⽰
imwrite(img,'puzzle1.png');%输出到⽂件⽬录
本来打算⽤⼩⽅块来实现,后来发现拼合成长条直接⽤也很⽅便。使⽤长条形的素材,构造⼀个GetImg函数以获取第k个数字的图⽚。
function X=GetImg(img,k)
%取出第k张图
X=img(:,100*(k-1)+1:100*k,:);
end
绘制游戏画⾯
游戏画⾯的9个数字可以⽤⼀个3×3的矩阵来标记。绘制游戏画⾯的函数drawmap就依靠得到的状态,也就是3×3的标记矩阵来显⽰,代码如下
function drawmap(A)
im=imread('puzzle1.png');
img=uint8(zeros(300,300,3));%预分配,且类型需要为unint8
%对要显⽰的图⽚进⾏赋值
for row=1:3
for col=1:3
img(1+(row-1)*100:100*row,1+(col-1)*100:100*col,:)=GetImg(im,A(row,col));%将A矩阵中的数字和图⽚对应
end
end
imshow(img)%显⽰画⾯
end
⽤以下语句测试,矩阵A和显⽰的每个数字都对应
A=[1,2,3;4,5,6;7,8,9]
drawmap(A);
打乱函数
虽然没有严格的证明,但是经验得出(没有遇到随机的打乱⽆法复原的情况)任意状态应该都是可以复原的,所以打乱就可以很简单⽤随机⽣成的9个数字来实现,并不需要模拟⼈为打乱。任意状态是否都能复原还有待证明。
function A=Disrupt()
A=unidrnd(9,3,3);随机⽣成值在1到9之间的3×3矩阵
drawmap(A);
end
主函数和规则
Matlab提供了两种获取⿏标坐标的途径,⼀个是ginput()函数,会有⼀个⼗字光标进⾏定位;另⼀个利⽤figure的WindowButtonDownFcn属性,在figure界⾯点击⿏标可以调⽤回调函数,实现⼀些功能。游戏的主函数如下
function puzzle()
%%主函数
loading()%开场动画
global Tag;%Tag是标记矩阵,定义成全局变量,⽅便传递参数
Tag=Disrupt();%将标记矩阵的排列顺序打乱Tag_A;
global count;%计算步数,也设为全局变量
count=0;
set(gcf,'windowButtonDownFcn',@ButttonDownFcn);%点击⿏标时调⽤ButttonDownFcn函数
⿏标点击时调⽤ButttonDownFcn函数,ButttonDownFcn函数中实现游戏的规则和画⾯的刷新,⽐较偷懒没有分模块来写,所有都写在⼀块了。图像的⼤⼩时300×300,所以坐标值/100向上取整(ceil函数)转化为矩阵对应的坐标。⽤四个if语句来实现了规则。最后检测是否胜利,可以⽤标记矩阵和k*ones(3,3)⽐较,也可以逐项⽐较每个元素是否相等。达成胜利条件,输出包含还原步数的消息。
function ButttonDownFcn(src,event)
pt =get(gca,'CurrentPoint');
y =uint8(ceil(pt(1,1)/100));
x =uint8(ceil(pt(1,2)/100));%获取点击的位置转化为矩阵中的坐标
global Tag
global count%声明全局变量
if x>=1&&x<=3&&y>=1&&y<=3%点击位置满⾜才执⾏
count=count+1;%计算步数
Tag(x,y)=Tag(x,y)+1;
if x<3%四个if实现规则
Tag(x+1,y)=Tag(x+1,y)+1;
end
if x>1
Tag(x-1,y)=Tag(x-1,y)+1;
end
if y<3
Tag(x,y+1)=Tag(x,y+1)+1;
end
if y>1
Tag(x,y-1)=Tag(x,y-1)+1;
end
Tag(Tag==10)=1;
end
drawmap(Tag);
%胜利条件
for k=1:9
if Tag==uint8(k*ones(3,3))
msgbox(strcat(num2str(count),' !You win!'));%提⽰完成信息
pause(5);%延迟
close all %游戏结束,关闭所有图像窗⼝
end
end
end
⾄此所有的⼯作都完成了,运⾏puzzle()函数就能可以玩了。
谜题解法
我的解法利⽤了它的对称性,优化⼀下步数⼤概在40-60之间。欢迎交流解法。
叙述可能有些繁杂,有时间再详写。
扩展
以上整个3×3的拼图就算是完成了,但是功能并不灵活。经过⼀些⼩修改可以实现⼗分丰富的玩法。
更多阶数和深度
在这个代码的基础上制作更⾼阶的版本也⾮常容易实现。在puzzle()函数中引⼊3个全局变量dim_x,dim_y和depth,编写setdim()分别来设置维数。
puzzle.m修改如下:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。