摘要:这篇博文在早前本人写的介绍拼图游戏的基础上推出带有GUI用户界面的增强版,这里将通过上、中、下三篇博文详细介绍利用MATLAB GUI设计的拼图游戏完整实现过程,每篇都会附上相应代码及解释。中篇主要讲解拼图游戏中游戏难度选择(拼图阶数设置)与拼图块数字提示功能的详细实现过程。中篇的要点如下:
点击跳转至拼图游戏全部文件下载页
从网络上可以看到用Java, C++等语言编写的拼图小游戏多不胜数,MATLAB作为高校几乎必设的一名基础编程语言或工具,大多都是用在数据计算、科学研究及实验仿真上,而网上流传的其编写小游戏的代码都是那几个老旧版本。这篇博文紧接着上篇继续介绍MATLAB GUI拼图游戏的详细过程,相比于早前的基本版本增加了图片选择、难度设置、数字提示的功能,使其在功能上更像一个游戏的样子。因为GUI界面版内容较多,这里限于篇幅分成了上、中、下连续三篇依次讲解。希望本文能给对MATLAB GUI界面设计或小游戏感兴趣的朋友有所启发。
简单来说,我们这一节实现的功能是:刚运行程序后,在两个用于显示原始图片和拼图图片的坐标轴上显示一张预先设置的初始图片(否则该区域空白,有失美观),在下方任务栏和界面左上角显示自行设置的图标。其效果如下:
要实现以上功能,需要在GUI界面中各控件创建时,添加相应代码使在界面初始化时显示我们设置的图片。每个控件都有一个回调函数CreateFcn,该函数只有在创建该控件的时候才会被调用。和上篇的方法一样,我们打开之前设计好的包含GUI界面的fig文件,分别选中用于显示初始图片和拼图图片的两个坐标轴,右击选择“查看回调”,点击“CreateFcn”即可跳转至该函数的定义编辑文件中,如下图所示:
axes_jigsaw_CreateFcn是这里创建显示拼图的坐标轴(axes_jigsaw)时调用的函数,在该函数中添加下面的代码:
% --- Executes during object creation, after setting all properties.
function axes_jigsaw_CreateFcn(hObject, eventdata, handles)
% 创建图形时执行,设置拼图区坐标显示拼图原始图片
image(imread('jigsawImage.jpeg'));
set(hObject,'Visible','off','Tag','axes_jigsaw')% 关闭坐标轴显示
代码第4行表示先读入事先准备好的放在同一目录下的名为‘jigsawImage.jpeg’的图片并在该坐标轴显示,第5行设置该坐标轴状态为隐藏(不影响该坐标上图片的显示)。同理在显示初始图片的坐标轴(axes_original)的CreateFcn函数下添加以下代码:
% --- Executes during object creation, after setting all properties.
function axes_original_CreateFcn(hObject, eventdata, handles)
% 创建图形时执行,设置原始图片显示
image(imread('jigsawImage.jpeg'));
set(hObject,'Visible','off','Tag','axes_original');
以上代码添加后再次运行程序则会在开始时显示图片,那么如何设置图标呢?在MATLAB 2016的窗口属性中可直接设置图标,而在之前的版本中则需要调用javax设置。采用上述相同的方式,在窗口(figure1)中右击选择“查看回调”选择“CreateFcn”,并跳转至该回调函数中,添加如下代码:
% --- Executes during object creation, after setting all properties.
function figure1_CreateFcn(hObject, eventdata, handles)
javaFrame=get(hObject,'javaFrame'); % 获取图形句柄
% 为窗口设置图标
set(javaFrame,'FigureIcon',javax.swing.ImageIcon('Puzzle_icon.png')) % Puzzle_icon.png为指定的图标
warning off all; % 忽略警告
以上代码中,第4行为获取坐标轴中javaFrame对象的句柄,第6行设置窗口图标为文件名为“Puzzle_icon.png”的图片(文件需与m文件在同一文件夹下),第7行忽略警告。至此本节初始图片和图标功能完成,需要注意的是在“CreateFcn”中的代码只在创建时执行一次,因此若需修改效果需按上面的方法再次修改代码并生效。
为了能够调整拼图难度,这里选择一个弹出式菜单控件供用户选择拼图阶数,其效果简单演示如下:
在上篇中就以及在设计GUI时,为这个弹出式菜单控件(popupmenu_rank)添加了供选择的菜单项。这里只需为其添加回调函数,对此这里再次通过上面的方法跳转至该控件的“Callback”函数中,或者在fig对应的m文件中直接找到这个函数,在其中添加如下代码:
% --- 下拉选择框popupmenu_rank被点击时执行.
function popupmenu_rank_Callback(hObject, eventdata, handles)
global flag; % 是否可点击拼图块标识
flag=false; % 下拉框改变,点击开始前不能点击
file_name=get(handles.edit_path,'String');% 文件名
% 读取图片
if exist(file_name,'file')==0
pic_data=imread('jigsawImage.jpeg');
else
pic_data=imread(file_name);
end
% 获取并计算拼图阶数
n=get(handles.popupmenu_rank,'value');
rank_Tag=n+2;
% 计算拼图块长宽
len=min([size(pic_data,1),size(pic_data,2)]);
len_col=round(len/rank_Tag);
len_row=round(len/rank_Tag);
% 统一拼图尺寸
pic_data=imresize(pic_data,[rank_Tag*len_col rank_Tag*len_row]);
% 数字标识
Tag=[1:1:rank_Tag^2-1,0];
Tag=reshape(Tag,rank_Tag,rank_Tag);
Tag=Tag';
% 显示拼图
axes(handles.axes_jigsaw)
image(pic_data);
axis off;
% 根据选择情况决定是否显示数字标识
ismask=get(handles.checkbox_num,'Value');
axes(handles.axes_jigsaw);
for i=1:size(Tag,1)
for j=1:size(Tag,2)
text(len_col/2*(2*j-1)-10,len_row/2*(2*i-1),num2str(Tag(i,j)),'FontSize',55-rank_Tag*5,'Color','c')
end
end
if ~ismask
h=findall(gca,'type','text');
delete(h);
end
在以上代码中,第4-5行使用了一个全局变量flag这个变量与上篇中提到的是相同的变量,MATLAB中全局变量是可以在不同函数、文件中使用的,只要有所声明。这里flag的作用在作为一个标志决定是否能够点击拼图区的拼图使其移动,需要遵循的一条是即便上次游戏还在运行只要点击了难度选择菜单,立即将标志置为false表示重新设置重新开始游戏了,在开始游戏前点击无效了(涉及点击事件响应,下篇介绍)。
这部分思路是首先读取用于显示文件路径的标签上的显示的路径,并读取该路径下上的图片并显示,然后读取当前菜单栏选中项并据此计算出拼图阶数,根据阶数将拼图分成对应的拼图块并调整图片尺寸。由于需要考虑到点击菜单栏选择难度时可能已勾选“显示提示数字”的勾选框,因此需添加一段代码判断勾选状态并根据勾选状态决定是否显示数字。代码中许多代码与上篇中实现图片选择功能部分的代码一致,其中的代码注释也比较完善这里就不多介绍了。
这节要实现的功能是:游戏开始前或进行中,可以对对应的拼图块标识相应的数字作为提示信息,提示的数字应能够适应相应的拼图阶数。效果如下:
其实这部分实现在上篇也有所提及,采用上面的方法跳转至数字提示勾选框的回调函数“Callback”的代码编辑中,在该函数中添加如下代码:
% --- checkbox_num按钮被点击时执行.
function checkbox_num_Callback(hObject, eventdata, handles)
global Tag;% 拼图块的数字标识
% 读取图片文件
file_name=get(handles.edit_path,'String');
if exist(file_name,'file')==0
pic_data=imread('jigsawImage.jpeg');
else
pic_data=imread(file_name);
end
% 获取并计算拼图阶数
n=get(handles.popupmenu_rank,'value');
rank_Tag=n+2;
% 如果拼图块标识Tag与当前的拼图阶数不符,根据当前阶数重置
if size(Tag,1)~=rank_Tag||size(Tag,2)~=rank_Tag
Tag=[1:1:rank_Tag^2-1,0];
Tag=reshape(Tag,rank_Tag,rank_Tag);
Tag=Tag';
end
% 计算每个拼图块的长宽
len=min([size(pic_data,1),size(pic_data,2)]);
len_col=round(len/rank_Tag);
len_row=round(len/rank_Tag);
% 根据选择情况决定是否显示数字标识
ismask=get(handles.checkbox_num,'Value');
axes(handles.axes_jigsaw);
for i=1:size(Tag,1)
for j=1:size(Tag,2)
% 在每块拼图的中心位置添加对应数字显示
text(len_col/2*(2*j-1)-10,len_row/2*(2*i-1),num2str(Tag(i,j)),'FontSize',55-rank_Tag*5,'Color','c')
end
end
if ~ismask % 选择不显示,则删除所有text图形
h=findall(gca,'type','text');
delete(h);
end
【代码解释】
代码第3行首先申明了一个全局变量Tag,它保存有当前拼图块的标号矩阵,通过对Tag的操作将图片与其对应起来,因为其他函数中也需要用到这里干脆设置为全局变量。代码第28-40行,理由text函数在坐标轴中显示文本,而显示的文本内容是每块拼图块对应的数字,通过遍历Tag能够得到,而要显示的位置可通过每块拼图的长宽计算得到,长宽除以2即要显示数字的中心位置。如第34行所示,利用text函数显示文本,第37-40行,根据获取的勾选的结果决定是否显示text文本,第39行表示删除所有text对象。
【下载链接】
若您想提前获得博文中涉及的实现完整拼图功能的全部程序文件(包括图片、fig, m文件等),这里已打包上传至博主的CSDN下载资源中,下载后运行jigsawGUI.m文件即可运行(实现完整功能)。同时已将文件打包编程成exe的可执行文件,可在我的百度网盘中下载后直接运行。文件下载链接如下:
下载链接1:博文中涉及的完整程序文件
下载链接2:拼图游戏打包的可执行EXE文件(已装MATLAB的用户下载)
链接:https://pan.baidu.com/s/1m0qLu3Un4jDT-NyQwFZs1g
提取码:j906
下载链接3:拼图游戏打包的可执行EXE文件(未装MATLAB的用户下载)
链接:https://pan.baidu.com/s/1uCMJI5O0FsnJKyoK4Lcvmw
提取码:a1kb
【公众号获取】
本人微信公众号已创建,扫描以下二维码并关注公众号“AI技术研究与分享”,后台回复“JG20190508”即可获取全部资源文件。
中篇的讲述就是这么多了,拼图的更多功能的实现会在后面的博文中讲述,大家也可以参考博主前面的一篇博文:基于MATLAB的拼图游戏设计。由于博主能力有限,博文中提及的方法与代码即使经过测试,也难免会有疏漏之处。希望您能热心指出其中的错误,以便下次修改时能以一个更完美更严谨的样子,呈现在大家面前。同时如果有更好的实现方法也请您不吝赐教。
大家的点赞和关注是博主最大的动力,如果您想要获取博文中的完整代码文件,可通过C币或积分下载,没有C币或积分的朋友可在关注、点赞博文后在评论区留下邮箱,我会在第一时间发送给您。